Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions hadoop-ozone/integration-test-s3/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,11 @@
<artifactId>s3</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sdk-core</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.S3AsyncClientBuilder;
import software.amazon.awssdk.services.s3.S3BaseClientBuilder;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3ClientBuilder;

/**
* Factory class for creating S3 clients.
Expand Down Expand Up @@ -127,6 +131,23 @@ public S3Client createS3ClientV2() throws Exception {
* @throws Exception if there is an error creating the client
*/
public S3Client createS3ClientV2(boolean enablePathStyle) throws Exception {
S3ClientBuilder builder = S3Client.builder();
configureCommon(builder, enablePathStyle);
return builder.build();
}

public S3AsyncClient createS3AsyncClientV2() throws Exception {
return createS3AsyncClientV2(true);
}

public S3AsyncClient createS3AsyncClientV2(boolean enablePathStyle) throws Exception {
S3AsyncClientBuilder builder = S3AsyncClient.builder();
configureCommon(builder, enablePathStyle);
return builder.build();
}

private <T extends S3BaseClientBuilder<T, ?>> void configureCommon(T builder, boolean enablePathStyle)
throws Exception {
final String accessKey = "user";
final String secretKey = "password";
final Region region = Region.US_EAST_1;
Expand All @@ -151,11 +172,9 @@ public S3Client createS3ClientV2(boolean enablePathStyle) throws Exception {

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

return S3Client.builder()
.region(region)
builder.region(region)
.endpointOverride(new URI(endpoint))
.credentialsProvider(StaticCredentialsProvider.create(credentials))
.forcePathStyle(enablePathStyle)
.build();
.forcePathStyle(enablePathStyle);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import org.junit.jupiter.api.io.TempDir;
import software.amazon.awssdk.core.ResponseBytes;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse;
import software.amazon.awssdk.services.s3.model.CompletedMultipartUpload;
Expand All @@ -83,6 +84,10 @@
import software.amazon.awssdk.services.s3.model.Tagging;
import software.amazon.awssdk.services.s3.model.UploadPartRequest;
import software.amazon.awssdk.services.s3.model.UploadPartResponse;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.DownloadFileRequest;
import software.amazon.awssdk.transfer.s3.model.FileDownload;
import software.amazon.awssdk.transfer.s3.model.ResumableFileDownload;

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

private static MiniOzoneCluster cluster = null;
private static S3Client s3Client = null;
private static S3AsyncClient s3AsyncClient = null;

/**
* Create a MiniOzoneCluster with S3G enabled for testing.
Expand All @@ -117,6 +123,7 @@ static void startCluster(OzoneConfiguration conf) throws Exception {
.build();
cluster.waitForClusterToBeReady();
s3Client = new S3ClientFactory(s3g.getConf()).createS3ClientV2();
s3AsyncClient = new S3ClientFactory(s3g.getConf()).createS3AsyncClientV2();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

S3ClientFactory s3Factory = new S3ClientFactory(s3g.getConf());
s3Client = s3Factory.createS3ClientV2();
s3AsyncClient = s3Factory.createS3AsyncClientV2();

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review @peterxcli , update the PR.

}

/**
Expand Down Expand Up @@ -340,6 +347,45 @@ public void testLowLevelMultipartUpload(@TempDir Path tempDir) throws Exception
assertEquals(userMetadata, headObjectResponse.metadata());
}

@Test
public void testResumableDownloadWithEtagMismatch() throws Exception {
// Arrange
final String bucketName = getBucketName("resumable");
final String keyName = getKeyName("resumable");
final String fileContent = "This is a test file for resumable download.";
s3Client.createBucket(b -> b.bucket(bucketName));
s3Client.putObject(b -> b.bucket(bucketName).key(keyName), RequestBody.fromString(fileContent));

// Prepare a temp file for download
Path tempDownloadPath = Files.createTempFile("downloaded", ".txt");
File downloadFile = tempDownloadPath.toFile();

// Set up S3TransferManager
try (S3TransferManager transferManager =
S3TransferManager.builder().s3Client(s3AsyncClient).build()) {

// First download
DownloadFileRequest downloadRequest = DownloadFileRequest.builder()
.getObjectRequest(b -> b.bucket(bucketName).key(keyName))
.destination(downloadFile.toPath())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: can use tempDownloadPath instead of downloadFile.toPath(), since:

Also, please rename tempDownloadPath to downloadPath.

.build();
FileDownload download = transferManager.downloadFile(downloadRequest);
ResumableFileDownload resumableFileDownload = download.pause();

// Simulate etag mismatch by modifying the file in S3
final String newContent = "This is new content to cause etag mismatch.";
s3Client.putObject(b -> b.bucket(bucketName).key(keyName), RequestBody.fromString(newContent));

// Resume download
FileDownload resumedDownload = transferManager.resumeDownloadFile(resumableFileDownload);
resumedDownload.completionFuture().get();

String downloadedContent = new String(Files.readAllBytes(downloadFile.toPath()), StandardCharsets.UTF_8);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: also use tempDownloadPath (renamed to downloadPath) here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the review @adoroszlai , update for both.

assertEquals(newContent, downloadedContent);
assertTrue(downloadFile.delete());
}
}

private String getBucketName() {
return getBucketName("");
}
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<aspectj.version>1.9.7</aspectj.version>
<assertj.version>3.27.3</assertj.version>
<aws-java-sdk.version>1.12.661</aws-java-sdk.version>
<aws-java-sdk2.version>2.31.25</aws-java-sdk2.version>
<aws-java-sdk2.version>2.31.40</aws-java-sdk2.version>
<bonecp.version>0.8.0.RELEASE</bonecp.version>
<bouncycastle.version>1.80</bouncycastle.version>
<build-helper-maven-plugin.version>3.6.0</build-helper-maven-plugin.version>
Expand Down