Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize Object Key when Getting Resources #19

Merged
merged 18 commits into from
Sep 25, 2017

Conversation

michaelahlers
Copy link

@michaelahlers michaelahlers commented Sep 22, 2017

Possible solution for ohnosequences/sbt-s3-resolver#52.

@laughedelic laughedelic self-requested a review September 22, 2017 19:48
Copy link
Contributor

@laughedelic laughedelic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @michaelahlers! Even though this is not where the problem comes from (see ohnosequences/sbt-s3-resolver#52 (comment)), I still think this is a valuable improvement here. Let's apply it to all relevant methods in S3Repository:

  • get (source arg)
  • list (parent arg)
  • put (destination arg)

P.S. Also if you don't have time for it, tell me. No problem, I'll do it myself.

@@ -117,6 +117,8 @@ public void get(String source, File destination) {
}

public Resource getResource(String source) {
/* For ohnosequences/sbt-s3-resolver#52, has the effect of cleaning up redundant path delimiters (thereby fixing invalid S3 object keys). */
source = java.net.URI.create(source).normalize().toString();
Copy link
Contributor

@laughedelic laughedelic Sep 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take a look at the S3Utils.getUri method:

https://github.com/michaelahlers/ivy-s3-resolver/blob/df2ffd3dc5010139b9ac0276646dc301dd1a7bd5/src/main/java/ohnosequences/ivy/S3Utils.java#L50-L56

You can add there .normalize() and then this change will propagate to the getBucket, getKey methods used in S3Repository.put.

And then here in getResource you can also use it as S3Utils.getUri(source).toString().

@michaelahlers
Copy link
Author

@laughedelic, found a little time today, so I'll try wrapping this up!

@michaelahlers
Copy link
Author

@laughedelic, any objection to adding a (Scala-fluent) unit test framework to this project?

@laughedelic
Copy link
Contributor

@michaelahlers of course, you are more than welcome to add tests here!

This library was maintained by my colleague before, and since it was handed to me, I was keeping the changes to minimum. I was actually thinking recently to drop this dependency in sbt-s3-resolver and just write an analogous resolver in Scala. But I don't know yet when I will have time for doing it...

val scenarios =
("s3://bucket/p0/p1", ("bucket", "p0/p1")) ::
("s3://bucket/p0//p1", ("bucket", "p0/p1")) ::
Nil
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For now, only includes basic and ohnosequences/sbt-s3-resolver#52 cases.

"com.github.pathikrit" %% "better-files" % "2.17.1" % Test,
"org.scalamock" %% "scalamock-scalatest-support" % "3.6.0" % Test,
"org.scalatest" %% "scalatest" % "3.0.1" % Test
)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add test libraries with helpful support, and make Wartremover less strict from "ohnosequences" % "nice-sbt-settings" % "0.8.0" settings.

boolean serverSideEncryption,
StorageClass storageClass
) {
this.s3Client = s3Client;
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An unfortunate conceit. This is unrelated to the fix, but it makes life significantly easier to support injection of (mocked) AmazonS3 instances when S3Repository is under test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could be actually useful. It allows you to make whatever special S3 client directly with the Java SDK (being able to tune things besides credentials and region) and use resolver with it.
I don't know if it makes sense to make this constructor public right now if there's no explicit need, but it could be done in some future release.

@@ -49,7 +49,8 @@ public static String getKey(String uri) {

private static URI getUri(String uri) {
try {
return new URI(uri);
/* For ohnosequences/sbt-s3-resolver#52, has the effect of cleaning up redundant path delimiters (thereby fixing invalid S3 object keys). */
return new URI(uri).normalize();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crux of the fix. Everything ultimately comes through here.

acl,
serverSideEncryption,
storageClass
)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Help make tests more concise where all they care about is the client.

}
}

}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test cases for each API mentioned in the review.


}

}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is used as a delegate by S3Repository.get, so ensure it's behavior is correct.


}

}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant, yes, but it'd take significant refactoring to remove various assumptions about URI parsing.

("s3://bucket//path0//path1", ("bucket", "path0/path1")) ::
Nil

}
Copy link
Author

@michaelahlers michaelahlers Sep 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard-coding these isn't my favorite thing, but it's a simple way to get scenarios we want to address with this pull-request.

@michaelahlers
Copy link
Author

michaelahlers commented Sep 24, 2017

@laughedelic, ready for another review. There's a lot added to src/test/scala here, but I figured aggressively adding test coverage to essential functionality couldn't hurt while covering the specific bug. A lot of this test code could be removed with the introduction of a type representing normalized and validated S3 object identifiers, but that may be done in another PR (or not at all depending on whether or not this library's scrapped). Codacy isn't happy with a few ScalaMock conventions, so I'll try cleaning those up in a bit.

summary
}
}
(listing.getNextMarker _).expects().once().returns(null)
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codacy rejects on this, but returning null is a necessary behavior of the com.amazonaws.services.s3.model.ObjectListing#getNextMarker API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem with it. I told it to ignore this particular place.

@laughedelic
Copy link
Contributor

@michaelahlers wow! 💯 I didn't expect that you will write tests for other parts besides getKey/getBucket. This is such a great contribution! I'm going to review the code tomorrow as soon as a have time.

Copy link
Contributor

@laughedelic laughedelic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Thanks a lot @michaelahlers! 👏

I'm going to merge it and cut a new release quickly to bring the fix to the sbt plugin.

boolean serverSideEncryption,
StorageClass storageClass
) {
this.s3Client = s3Client;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it could be actually useful. It allows you to make whatever special S3 client directly with the Java SDK (being able to tune things besides credentials and region) and use resolver with it.
I don't know if it makes sense to make this constructor public right now if there's no explicit need, but it could be done in some future release.

@laughedelic
Copy link
Contributor

Released in v0.12.0 :shipit:

I also added you to the collaborators. In case you'll want to hack around here some more, you're welcome to submit PRs directly 😉

@michaelahlers
Copy link
Author

@laughedelic, what can I say? I love writing test code. 😉 You're welcome, I'm glad to help, and thanks for the invitation. (Accepted!) Your S3 resolver plugin has been extremely useful to me on a number of projects both professional and personal. Pretty thrilled to contribute back any way I can!

@michaelahlers michaelahlers deleted the normalize-object-keys branch September 25, 2017 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants