Skip to content

Commit c3cb14f

Browse files
authored
HDDS-12914. Bump awssdk to 2.31.40, test ResumableFileDownload (#8455)
1 parent c6b47e9 commit c3cb14f

File tree

4 files changed

+79
-6
lines changed

4 files changed

+79
-6
lines changed

hadoop-ozone/integration-test-s3/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@
112112
<artifactId>s3</artifactId>
113113
<scope>test</scope>
114114
</dependency>
115+
<dependency>
116+
<groupId>software.amazon.awssdk</groupId>
117+
<artifactId>s3-transfer-manager</artifactId>
118+
<scope>test</scope>
119+
</dependency>
115120
<dependency>
116121
<groupId>software.amazon.awssdk</groupId>
117122
<artifactId>sdk-core</artifactId>

hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/S3ClientFactory.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,11 @@
3939
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
4040
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
4141
import software.amazon.awssdk.regions.Region;
42+
import software.amazon.awssdk.services.s3.S3AsyncClient;
43+
import software.amazon.awssdk.services.s3.S3AsyncClientBuilder;
44+
import software.amazon.awssdk.services.s3.S3BaseClientBuilder;
4245
import software.amazon.awssdk.services.s3.S3Client;
46+
import software.amazon.awssdk.services.s3.S3ClientBuilder;
4347

4448
/**
4549
* Factory class for creating S3 clients.
@@ -127,6 +131,23 @@ public S3Client createS3ClientV2() throws Exception {
127131
* @throws Exception if there is an error creating the client
128132
*/
129133
public S3Client createS3ClientV2(boolean enablePathStyle) throws Exception {
134+
S3ClientBuilder builder = S3Client.builder();
135+
configureCommon(builder, enablePathStyle);
136+
return builder.build();
137+
}
138+
139+
public S3AsyncClient createS3AsyncClientV2() throws Exception {
140+
return createS3AsyncClientV2(true);
141+
}
142+
143+
public S3AsyncClient createS3AsyncClientV2(boolean enablePathStyle) throws Exception {
144+
S3AsyncClientBuilder builder = S3AsyncClient.builder();
145+
configureCommon(builder, enablePathStyle);
146+
return builder.build();
147+
}
148+
149+
private <T extends S3BaseClientBuilder<T, ?>> void configureCommon(T builder, boolean enablePathStyle)
150+
throws Exception {
130151
final String accessKey = "user";
131152
final String secretKey = "password";
132153
final Region region = Region.US_EAST_1;
@@ -151,11 +172,9 @@ public S3Client createS3ClientV2(boolean enablePathStyle) throws Exception {
151172

152173
AwsBasicCredentials credentials = AwsBasicCredentials.create(accessKey, secretKey);
153174

154-
return S3Client.builder()
155-
.region(region)
175+
builder.region(region)
156176
.endpointOverride(new URI(endpoint))
157177
.credentialsProvider(StaticCredentialsProvider.create(credentials))
158-
.forcePathStyle(enablePathStyle)
159-
.build();
178+
.forcePathStyle(enablePathStyle);
160179
}
161180
}

hadoop-ozone/integration-test-s3/src/test/java/org/apache/hadoop/ozone/s3/awssdk/v2/AbstractS3SDKV2Tests.java

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
import org.junit.jupiter.api.io.TempDir;
6464
import software.amazon.awssdk.core.ResponseBytes;
6565
import software.amazon.awssdk.core.sync.RequestBody;
66+
import software.amazon.awssdk.services.s3.S3AsyncClient;
6667
import software.amazon.awssdk.services.s3.S3Client;
6768
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
6869
import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload;
@@ -83,6 +84,10 @@
8384
import software.amazon.awssdk.services.s3.model.Tagging;
8485
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
8586
import software.amazon.awssdk.services.s3.model.UploadPartResponse;
87+
import software.amazon.awssdk.transfer.s3.S3TransferManager;
88+
import software.amazon.awssdk.transfer.s3.model.DownloadFileRequest;
89+
import software.amazon.awssdk.transfer.s3.model.FileDownload;
90+
import software.amazon.awssdk.transfer.s3.model.ResumableFileDownload;
8691

8792
/**
8893
* This is an abstract class to test the AWS Java S3 SDK operations.
@@ -103,6 +108,7 @@ public abstract class AbstractS3SDKV2Tests extends OzoneTestBase {
103108

104109
private static MiniOzoneCluster cluster = null;
105110
private static S3Client s3Client = null;
111+
private static S3AsyncClient s3AsyncClient = null;
106112

107113
/**
108114
* Create a MiniOzoneCluster with S3G enabled for testing.
@@ -116,7 +122,10 @@ static void startCluster(OzoneConfiguration conf) throws Exception {
116122
.setNumDatanodes(5)
117123
.build();
118124
cluster.waitForClusterToBeReady();
119-
s3Client = new S3ClientFactory(s3g.getConf()).createS3ClientV2();
125+
126+
S3ClientFactory s3Factory = new S3ClientFactory(s3g.getConf());
127+
s3Client = s3Factory.createS3ClientV2();
128+
s3AsyncClient = s3Factory.createS3AsyncClientV2();
120129
}
121130

122131
/**
@@ -340,6 +349,46 @@ public void testLowLevelMultipartUpload(@TempDir Path tempDir) throws Exception
340349
assertEquals(userMetadata, headObjectResponse.metadata());
341350
}
342351

352+
@Test
353+
public void testResumableDownloadWithEtagMismatch() throws Exception {
354+
// Arrange
355+
final String bucketName = getBucketName("resumable");
356+
final String keyName = getKeyName("resumable");
357+
final String fileContent = "This is a test file for resumable download.";
358+
s3Client.createBucket(b -> b.bucket(bucketName));
359+
s3Client.putObject(b -> b.bucket(bucketName).key(keyName), RequestBody.fromString(fileContent));
360+
361+
// Prepare a temp file for download
362+
Path downloadPath = Files.createTempFile("downloaded", ".txt");
363+
364+
// Set up S3TransferManager
365+
try (S3TransferManager transferManager =
366+
S3TransferManager.builder().s3Client(s3AsyncClient).build()) {
367+
368+
// First download
369+
DownloadFileRequest downloadRequest = DownloadFileRequest.builder()
370+
.getObjectRequest(b -> b.bucket(bucketName).key(keyName))
371+
.destination(downloadPath)
372+
.build();
373+
FileDownload download = transferManager.downloadFile(downloadRequest);
374+
ResumableFileDownload resumableFileDownload = download.pause();
375+
376+
// Simulate etag mismatch by modifying the file in S3
377+
final String newContent = "This is new content to cause etag mismatch.";
378+
s3Client.putObject(b -> b.bucket(bucketName).key(keyName), RequestBody.fromString(newContent));
379+
380+
// Resume download
381+
FileDownload resumedDownload = transferManager.resumeDownloadFile(resumableFileDownload);
382+
resumedDownload.completionFuture().get();
383+
384+
String downloadedContent = new String(Files.readAllBytes(downloadPath), StandardCharsets.UTF_8);
385+
assertEquals(newContent, downloadedContent);
386+
387+
File downloadFile = downloadPath.toFile();
388+
assertTrue(downloadFile.delete());
389+
}
390+
}
391+
343392
private String getBucketName() {
344393
return getBucketName("");
345394
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<aspectj.version>1.9.7</aspectj.version>
3737
<assertj.version>3.27.3</assertj.version>
3838
<aws-java-sdk.version>1.12.661</aws-java-sdk.version>
39-
<aws-java-sdk2.version>2.31.25</aws-java-sdk2.version>
39+
<aws-java-sdk2.version>2.31.40</aws-java-sdk2.version>
4040
<bonecp.version>0.8.0.RELEASE</bonecp.version>
4141
<bouncycastle.version>1.80</bouncycastle.version>
4242
<build-helper-maven-plugin.version>3.6.0</build-helper-maven-plugin.version>

0 commit comments

Comments
 (0)