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

Fix Len = 0 and Insufficient Buffer behaviours for positioned reads #203

Merged
merged 2 commits into from
Jan 7, 2025

Conversation

fuatbasik
Copy link
Contributor

@fuatbasik fuatbasik commented Jan 3, 2025

Description of change

According to InputStream documentation Len = 0 should return 0

If len is zero, then no bytes are read and 0 is returned;

Following the InputStream implementation, this commit is adding argument checks to Positioned Reads. This validation is implemented in the SeekableInputStream to ensure all subclasses behave the same way in the unhappy path.

Checks are done in the same order with InputStream implementation.

Relevant issues

#201

Does this contribution introduce any breaking changes to the existing APIs or behaviors?

Yes. For a 0-length read to a 0-sized object read will now return 0 instead of -1.
Insufficient Buffer Capacity will now throw IndexOutOfBoundsException instead of IllegalArgumentException.

Does this contribution introduce any new public APIs or behaviors?

No, it changes existing public API behaviour.

How was the contribution tested?

Added new unit tests.

Does this contribution need a changelog entry?

  • [N/A] I have updated the CHANGELOG or README if appropriate

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license and I agree to the terms of the Developer Certificate of Origin (DCO).

According to InputStream documentation Len = 0 should return 0

`If len is zero, then no bytes are read and 0 is returned;`
Following the InputStream implementation, this commit is adding argument checks to
Positioned Reads. This validation is implemented in the SeekableInputStream to ensure
all subclasses behave the same way in the unhappy path.
@fuatbasik fuatbasik changed the title Test Len = 0 and Insufficient Buffer behaviours for positioned reads Fix Len = 0 and Insufficient Buffer behaviours for positioned reads Jan 3, 2025
if (this.position >= getContentLength()) {
if (length == 0) {
return 0;
} else if (this.position >= getContentLength()) {
Copy link

Choose a reason for hiding this comment

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

shall we move this validation as well to the method where we did the previous validations, so that all the validations are in same place?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a good recommendation. I did not move this validation because full content length might not be available to other streams those will implement this class. In S3 case we know the size thanks to object metadata. Let me know what you think.

Preconditions.checkArgument(position >= 0, "Position is negative");

if (buffer == null) {
throw new NullPointerException("Null destination buffer");
Copy link

Choose a reason for hiding this comment

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

why not just have both of these in precondition checks?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That makes perfect sense. Doing it now.

* @throws NullPointerException if the buffer is null
* @throws IndexOutOfBoundsException if the offset or length are invalid for the given buffer
*/
protected void validatePositionedReadArgs(long position, byte[] buffer, int offset, int length) {
Copy link

Choose a reason for hiding this comment

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

maybe add a unit test for this method? should be quick

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well i didn't because it is a protected method and not sure if we want to expose it. Instead i added tests to S3SeekableInputStream class which is publicly exposed. Let me know if you think this is a good approach.

Copy link

Choose a reason for hiding this comment

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

Happy with this approach!
Just fyi I think there is a visibleForTesting Annotation that helps with this

@fuatbasik fuatbasik requested review from rajdchak and stubz151 January 6, 2025 10:53
@CsengerG
Copy link
Contributor

CsengerG commented Jan 6, 2025

Didn't look very deep but saw threads discussing stream spec/testing this. Where is the right place to test behaviour like this, unit tests or some higher level? Also, when we change higher level behaviour, do we need to update our reference model (this is an open question, but it feels like if we don't maintain the reference model then it will stop being useful over time)? Does anyone have a mental model yet? :)

@fuatbasik fuatbasik merged commit 32946d0 into awslabs:main Jan 7, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants