Skip to content

Commit 63ebf3a

Browse files
authored
Add s3 Range compatibility tests (floci-io#13)
1 parent 68a099f commit 63ebf3a

2 files changed

Lines changed: 107 additions & 0 deletions

File tree

sdk-test-java/src/main/java/com/floci/test/FlociTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
* <li>{@code secretsmanager}
5555
* <li>{@code sfn-jsonata}
5656
* <li>{@code s3-large-object}
57+
* <li>{@code s3-range}
5758
* <li>{@code s3-virtual-host}
5859
* <li>{@code ses}
5960
* </ul>
@@ -72,6 +73,7 @@ public static void main(String[] args) {
7273
new S3ObjectLockTests(),
7374
new S3AdvancedTests(),
7475
new S3LargeObjectTests(),
76+
new S3RangeTests(),
7577
new S3VirtualHostTests(),
7678
new DynamoDbTests(),
7779
new DynamoDbAdvancedTests(),
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
package com.floci.test.tests;
2+
3+
import com.floci.test.TestContext;
4+
import com.floci.test.TestGroup;
5+
import software.amazon.awssdk.core.ResponseBytes;
6+
import software.amazon.awssdk.core.sync.RequestBody;
7+
import software.amazon.awssdk.services.s3.S3Client;
8+
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
9+
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
10+
import software.amazon.awssdk.services.s3.model.HeadObjectResponse;
11+
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
12+
import software.amazon.awssdk.services.s3.model.S3Exception;
13+
14+
public class S3RangeTests implements TestGroup {
15+
16+
@Override
17+
public String name() { return "s3-range"; }
18+
19+
@Override
20+
public void run(TestContext ctx) {
21+
System.out.println("--- S3 Range Tests ---");
22+
23+
try (S3Client s3 = S3Client.builder()
24+
.endpointOverride(ctx.endpoint)
25+
.region(ctx.region)
26+
.credentialsProvider(ctx.credentials)
27+
.forcePathStyle(true)
28+
.build()) {
29+
30+
String bucket = "sdk-range-test-bucket-" + System.currentTimeMillis();
31+
String key = "range-test.txt";
32+
// "Hello, Range World!!" = 20 bytes (indices 0-19)
33+
String content = "Hello, Range World!!";
34+
35+
s3.createBucket(b -> b.bucket(bucket));
36+
s3.putObject(PutObjectRequest.builder()
37+
.bucket(bucket).key(key).contentType("text/plain").build(),
38+
RequestBody.fromString(content));
39+
40+
// 1. Accept-Ranges header on normal GetObject
41+
try {
42+
ResponseBytes<GetObjectResponse> resp = s3.getObjectAsBytes(
43+
GetObjectRequest.builder().bucket(bucket).key(key).build());
44+
ctx.check("S3 GetObject Accept-Ranges header",
45+
"bytes".equals(resp.response().acceptRanges()));
46+
} catch (Exception e) { ctx.check("S3 GetObject Accept-Ranges header", false, e); }
47+
48+
// 2. Accept-Ranges header on HeadObject
49+
try {
50+
HeadObjectResponse resp = s3.headObject(b -> b.bucket(bucket).key(key));
51+
ctx.check("S3 HeadObject Accept-Ranges header",
52+
"bytes".equals(resp.acceptRanges()));
53+
} catch (Exception e) { ctx.check("S3 HeadObject Accept-Ranges header", false, e); }
54+
55+
// 3. Full range bytes=0-4 → "Hello" (5 bytes)
56+
try {
57+
ResponseBytes<GetObjectResponse> resp = s3.getObjectAsBytes(
58+
GetObjectRequest.builder().bucket(bucket).key(key).range("bytes=0-4").build());
59+
ctx.check("S3 GetObject Range bytes=0-4",
60+
"Hello".equals(resp.asUtf8String())
61+
&& "bytes 0-4/20".equals(resp.response().contentRange()));
62+
} catch (Exception e) { ctx.check("S3 GetObject Range bytes=0-4", false, e); }
63+
64+
// 4. Open-ended range bytes=15- → "rld!!" (bytes 15-19)
65+
try {
66+
ResponseBytes<GetObjectResponse> resp = s3.getObjectAsBytes(
67+
GetObjectRequest.builder().bucket(bucket).key(key).range("bytes=15-").build());
68+
ctx.check("S3 GetObject Range bytes=15-",
69+
"rld!!".equals(resp.asUtf8String())
70+
&& "bytes 15-19/20".equals(resp.response().contentRange()));
71+
} catch (Exception e) { ctx.check("S3 GetObject Range bytes=15-", false, e); }
72+
73+
// 5. Suffix range bytes=-5 → last 5 bytes "rld!!" (bytes 15-19)
74+
try {
75+
ResponseBytes<GetObjectResponse> resp = s3.getObjectAsBytes(
76+
GetObjectRequest.builder().bucket(bucket).key(key).range("bytes=-5").build());
77+
ctx.check("S3 GetObject Range bytes=-5",
78+
"rld!!".equals(resp.asUtf8String())
79+
&& "bytes 15-19/20".equals(resp.response().contentRange()));
80+
} catch (Exception e) { ctx.check("S3 GetObject Range bytes=-5", false, e); }
81+
82+
// 6. Single-byte range at end bytes=19-19 → "!"
83+
try {
84+
ResponseBytes<GetObjectResponse> resp = s3.getObjectAsBytes(
85+
GetObjectRequest.builder().bucket(bucket).key(key).range("bytes=19-19").build());
86+
ctx.check("S3 GetObject Range bytes=19-19 (last byte)",
87+
"!".equals(resp.asUtf8String())
88+
&& "bytes 19-19/20".equals(resp.response().contentRange()));
89+
} catch (Exception e) { ctx.check("S3 GetObject Range bytes=19-19 (last byte)", false, e); }
90+
91+
// 7. Out-of-bounds range bytes=50-100 → 416 InvalidRange
92+
try {
93+
s3.getObjectAsBytes(GetObjectRequest.builder().bucket(bucket).key(key).range("bytes=50-100").build());
94+
ctx.check("S3 GetObject Range out-of-bounds returns 416", false);
95+
} catch (S3Exception e) {
96+
ctx.check("S3 GetObject Range out-of-bounds returns 416",
97+
e.statusCode() == 416 && "InvalidRange".equals(e.awsErrorDetails().errorCode()));
98+
} catch (Exception e) { ctx.check("S3 GetObject Range out-of-bounds returns 416", false, e); }
99+
100+
// Cleanup
101+
s3.deleteObject(b -> b.bucket(bucket).key(key));
102+
s3.deleteBucket(b -> b.bucket(bucket));
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)