diff --git a/src/main/java/software/amazon/encryption/s3/internal/ConvertSDKRequests.java b/src/main/java/software/amazon/encryption/s3/internal/ConvertSDKRequests.java new file mode 100644 index 000000000..fbffadc58 --- /dev/null +++ b/src/main/java/software/amazon/encryption/s3/internal/ConvertSDKRequests.java @@ -0,0 +1,144 @@ +package software.amazon.encryption.s3.internal; + +import software.amazon.awssdk.services.s3.model.ChecksumType; +import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest; +import software.amazon.awssdk.services.s3.model.PutObjectRequest; +import java.time.Instant; +import java.util.Map; + +public class ConvertSDKRequests { + + public static CreateMultipartUploadRequest convert(PutObjectRequest request) { + + final CreateMultipartUploadRequest.Builder output = CreateMultipartUploadRequest.builder(); + request + .toBuilder() + .sdkFields() + .forEach(f -> { + final Object value = f.getValueOrDefault(request); + if (value != null) { + switch (f.memberName()) { + case "ACL": + output.acl((String) value); + break; + case "Bucket": + output.bucket((String) value); + break; + case "BucketKeyEnabled": + output.bucketKeyEnabled((Boolean) value); + break; + case "CacheControl": + output.cacheControl((String) value); + break; + case "ChecksumAlgorithm": + output.checksumAlgorithm((String) value); + break; + case "ChecksumType": + output.checksumType((ChecksumType) value); + case "ContentDisposition": + assert value instanceof String; + output.contentDisposition((String) value); + break; + case "ContentEncoding": + output.contentEncoding((String) value); + break; + case "ContentLanguage": + output.contentLanguage((String) value); + break; + case "ContentType": + output.contentType((String) value); + break; + case "ExpectedBucketOwner": + output.expectedBucketOwner((String) value); + break; + case "Expires": + output.expires((Instant) value); + break; + case "GrantFullControl": + output.grantFullControl((String) value); + break; + case "GrantRead": + output.grantRead((String) value); + break; + case "GrantReadACP": + output.grantReadACP((String) value); + break; + case "GrantWriteACP": + output.grantWriteACP((String) value); + break; + case "Key": + output.key((String) value); + break; + case "Metadata": + // The PutObjectRequest.builder().metadata(value) + // only takes Map therefore it should not be possible + // to get here with anything other than a Map + // This may be overkill, but this map should be small + // so the performance hit to verify this is worth the correctness. + if (!isStringStringMap(value)) { + throw new IllegalArgumentException("Metadata must be a Map"); + } + @SuppressWarnings("unchecked") + Map metadata = (Map) value; + output.metadata(metadata); + break; + case "ObjectLockLegalHoldStatus": + output.objectLockLegalHoldStatus((String) value); + break; + case "ObjectLockMode": + output.objectLockMode((String) value); + break; + case "ObjectLockRetainUntilDate": + output.objectLockRetainUntilDate((Instant) value); + break; + case "RequestPayer": + output.requestPayer((String) value); + break; + case "ServerSideEncryption": + output.serverSideEncryption((String) value); + break; + case "SSECustomerAlgorithm": + output.sseCustomerAlgorithm((String) value); + break; + case "SSECustomerKey": + output.sseCustomerKey((String) value); + break; + case "SSEKMSEncryptionContext": + output.ssekmsEncryptionContext((String) value); + break; + case "SSEKMSKeyId": + output.ssekmsKeyId((String) value); + break; + case "StorageClass": + output.storageClass((String) value); + break; + case "Tagging": + output.tagging((String) value); + break; + case "WebsiteRedirectLocation": + output.websiteRedirectLocation((String) value); + break; + default: + // Rather than silently dropping the value, + // we loudly signal that we don't know how to handle this field. + throw new IllegalArgumentException("Unknown PutObjectRequest field " + f.locationName() + "."); + } + } + }); + return output + // OverrideConfiguration is not as SDKField but still needs to be supported + .overrideConfiguration(request.overrideConfiguration().orElse(null)) + .build(); + } + + private static boolean isStringStringMap(Object value) { + if (!(value instanceof Map)) { + return false; + } + Map map = (Map) value; + return map.entrySet().stream() + .allMatch(entry -> entry != null + && ((Map.Entry) entry).getKey() instanceof String + && ((Map.Entry) entry).getValue() instanceof String); + } +} diff --git a/src/main/java/software/amazon/encryption/s3/internal/UploadObjectObserver.java b/src/main/java/software/amazon/encryption/s3/internal/UploadObjectObserver.java index 15e9e94b2..bf648e60f 100644 --- a/src/main/java/software/amazon/encryption/s3/internal/UploadObjectObserver.java +++ b/src/main/java/software/amazon/encryption/s3/internal/UploadObjectObserver.java @@ -7,7 +7,6 @@ import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.CompleteMultipartUploadResponse; import software.amazon.awssdk.services.s3.model.CompletedPart; -import software.amazon.awssdk.services.s3.model.CreateMultipartUploadRequest; import software.amazon.awssdk.services.s3.model.CreateMultipartUploadResponse; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.model.SdkPartType; @@ -42,20 +41,10 @@ public UploadObjectObserver init(PutObjectRequest req, this.es = es; return this; } - - protected CreateMultipartUploadRequest newCreateMultipartUploadRequest( - PutObjectRequest request) { - return CreateMultipartUploadRequest.builder() - .bucket(request.bucket()) - .key(request.key()) - .metadata(request.metadata()) - .overrideConfiguration(request.overrideConfiguration().orElse(null)) - .build(); - } - + public String onUploadCreation(PutObjectRequest req) { CreateMultipartUploadResponse res = - s3EncryptionClient.createMultipartUpload(newCreateMultipartUploadRequest(req)); + s3EncryptionClient.createMultipartUpload(ConvertSDKRequests.convert(req)); return this.uploadId = res.uploadId(); } diff --git a/src/test/java/software/amazon/encryption/s3/S3EncryptionClientMultipartUploadTest.java b/src/test/java/software/amazon/encryption/s3/S3EncryptionClientMultipartUploadTest.java index d42eb9201..aa0cf3cf2 100644 --- a/src/test/java/software/amazon/encryption/s3/S3EncryptionClientMultipartUploadTest.java +++ b/src/test/java/software/amazon/encryption/s3/S3EncryptionClientMultipartUploadTest.java @@ -20,6 +20,7 @@ import software.amazon.awssdk.services.s3.model.SdkPartType; import software.amazon.awssdk.services.s3.model.UploadPartRequest; import software.amazon.awssdk.services.s3.model.UploadPartResponse; +import software.amazon.awssdk.services.s3.model.StorageClass; import software.amazon.awssdk.utils.IoUtils; import software.amazon.encryption.s3.utils.BoundedInputStream; @@ -522,4 +523,43 @@ public void multipartUploadV3OutputStreamPartSizeMismatch() throws IOException { v3Client.close(); } + @Test + public void multipartPutObjectWithOptions() throws IOException { + final String objectKey = appendTestSuffix("multipart-put-object-with-options"); + + final long fileSizeLimit = 1024 * 1024 * 10; + final InputStream inputStream = new BoundedInputStream(fileSizeLimit); + final InputStream objectStreamForResult = new BoundedInputStream(fileSizeLimit); + + final S3Client v3Client = S3EncryptionClient.builder() + .kmsKeyId(KMS_KEY_ID) + .enableMultipartPutObject(true) + .enableDelayedAuthenticationMode(true) + .cryptoProvider(PROVIDER) + .build(); + + final Map encryptionContext = new HashMap<>(); + encryptionContext.put("user-metadata-key", "user-metadata-value-v3-to-v3"); + + final StorageClass storageClass = StorageClass.INTELLIGENT_TIERING; + + v3Client.putObject(builder -> builder + .bucket(BUCKET) + .overrideConfiguration(withAdditionalConfiguration(encryptionContext)) + .storageClass(storageClass) + .key(objectKey), RequestBody.fromInputStream(inputStream, fileSizeLimit)); + + // Asserts + final ResponseInputStream output = v3Client.getObject(builder -> builder + .bucket(BUCKET) + .overrideConfiguration(S3EncryptionClient.withAdditionalConfiguration(encryptionContext)) + .key(objectKey)); + + assertTrue(IOUtils.contentEquals(objectStreamForResult, output)); + assertEquals(storageClass, output.response().storageClass()); + + v3Client.deleteObject(builder -> builder.bucket(BUCKET).key(objectKey)); + v3Client.close(); + } + } diff --git a/src/test/java/software/amazon/encryption/s3/internal/ConvertSDKRequestsTest.java b/src/test/java/software/amazon/encryption/s3/internal/ConvertSDKRequestsTest.java new file mode 100644 index 000000000..d45bba280 --- /dev/null +++ b/src/test/java/software/amazon/encryption/s3/internal/ConvertSDKRequestsTest.java @@ -0,0 +1,425 @@ +package software.amazon.encryption.s3.internal; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; +import software.amazon.awssdk.services.s3.model.*; + +import java.time.Duration; +import java.time.Instant; +import java.util.HashMap; +import java.util.Map; +import static org.junit.jupiter.api.Assertions.*; + +class ConvertSDKRequestsTest { + + @Test + void testConvertPutObjectRequest_Bucket() { + final String value = "test-bucket"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .bucket(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.bucket()); + } + + @Test + void testConvertPutObjectRequest_ACL() { + final ObjectCannedACL value = ObjectCannedACL.PRIVATE; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .acl(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.acl()); + } + + @Test + void testConvertPutObjectRequest_ACL2() { + final String value = ObjectCannedACL.PRIVATE.toString(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .acl(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.acl().toString()); + } + + @Test + void testConvertPutObjectRequest_BucketKeyEnabled() { + final Boolean value = true; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .bucketKeyEnabled(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.bucketKeyEnabled()); + } + + @Test + void testConvertPutObjectRequest_CacheControl() { + final String value = "max-age=3600"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .cacheControl(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.cacheControl()); + } + + @Test + void testConvertPutObjectRequest_ChecksumAlgorithm() { + final ChecksumAlgorithm value = ChecksumAlgorithm.SHA256; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .checksumAlgorithm(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.checksumAlgorithm()); + } + + @Test + void testConvertPutObjectRequest_ChecksumAlgorithm2() { + final String value = ChecksumAlgorithm.SHA256.toString(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .checksumAlgorithm(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.checksumAlgorithm().toString()); + } + + @Test + void testConvertPutObjectRequest_ContentDisposition() { + final String value = "attachment; filename=\"filename.jpg\""; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .contentDisposition(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.contentDisposition()); + } + + @Test + void testConvertPutObjectRequest_ContentEncoding() { + final String value = "gzip"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .contentEncoding(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.contentEncoding()); + } + + @Test + void testConvertPutObjectRequest_ContentLanguage() { + final String value = "en-US"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .contentLanguage(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.contentLanguage()); + } + + @Test + void testConvertPutObjectRequest_ContentType() { + final String value = "text/plain"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .contentType(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.contentType()); + } + + @Test + void testConvertPutObjectRequest_ExpectedBucketOwner() { + final String value = "owner123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .expectedBucketOwner(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.expectedBucketOwner()); + } + + @Test + void testConvertPutObjectRequest_Expires() { + final Instant value = Instant.now(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .expires(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.expires()); + } + + @Test + void testConvertPutObjectRequest_GrantFullControl() { + final String value = "id=123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .grantFullControl(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.grantFullControl()); + } + + @Test + void testConvertPutObjectRequest_GrantRead() { + final String value = "id=123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .grantRead(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.grantRead()); + } + + @Test + void testConvertPutObjectRequest_GrantReadACP() { + final String value = "id=123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .grantReadACP(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.grantReadACP()); + } + + @Test + void testConvertPutObjectRequest_GrantWriteACP() { + final String value = "id=123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .grantWriteACP(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.grantWriteACP()); + } + + @Test + void testConvertPutObjectRequest_Key() { + final String value = "test-key"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .key(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.key()); + } + + @Test + void testConvertPutObjectRequest_Metadata() { + final Map value = new HashMap<>(); + value.put("key1", "value1"); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .metadata(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.metadata()); + } + + @Test + void testConvertPutObjectRequest_ObjectLockLegalHoldStatus() { + final ObjectLockLegalHoldStatus value = ObjectLockLegalHoldStatus.ON; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .objectLockLegalHoldStatus(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.objectLockLegalHoldStatus()); + } + + @Test + void testConvertPutObjectRequest_ObjectLockLegalHoldStatus2() { + final String value = ObjectLockLegalHoldStatus.ON.toString(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .objectLockLegalHoldStatus(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.objectLockLegalHoldStatus().toString()); + } + + @Test + void testConvertPutObjectRequest_ObjectLockMode() { + final ObjectLockMode value = ObjectLockMode.GOVERNANCE; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .objectLockMode(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.objectLockMode()); + } + + @Test + void testConvertPutObjectRequest_ObjectLockMode2() { + final String value = "GOVERNANCE"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .objectLockMode(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.objectLockMode().toString()); + } + + @Test + void testConvertPutObjectRequest_ObjectLockRetainUntilDate() { + final Instant value = Instant.now(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .objectLockRetainUntilDate(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.objectLockRetainUntilDate()); + } + + @Test + void testConvertPutObjectRequest_RequestPayer() { + final RequestPayer value = RequestPayer.REQUESTER; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .requestPayer(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.requestPayer()); + } + + @Test + void testConvertPutObjectRequest_RequestPayer2() { + final String value = RequestPayer.REQUESTER.toString(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .requestPayer(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.requestPayer().toString()); + } + + @Test + void testConvertPutObjectRequest_ServerSideEncryption() { + final ServerSideEncryption value = ServerSideEncryption.AES256; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .serverSideEncryption(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.serverSideEncryption()); + } + + @Test + void testConvertPutObjectRequest_ServerSideEncryption2() { + final String value = ServerSideEncryption.AES256.toString(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .serverSideEncryption(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.serverSideEncryption().toString()); + } + + @Test + void testConvertPutObjectRequest_SSECustomerAlgorithm() { + final String value = "AES256"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .sseCustomerAlgorithm(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.sseCustomerAlgorithm()); + } + + @Test + void testConvertPutObjectRequest_SSECustomerKey() { + final String value = "key123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .sseCustomerKey(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.sseCustomerKey()); + } + + @Test + void testConvertPutObjectRequest_SSEKMSKeyId() { + final String value = "arn:aws:kms:region:123456789012:key/key-id"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .ssekmsKeyId(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.ssekmsKeyId()); + } + + @Test + void testConvertPutObjectRequest_SSEKMSEncryptionContext() { + final String value = "context123"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .ssekmsEncryptionContext(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.ssekmsEncryptionContext()); + } + + @Test + void testConvertPutObjectRequest_StorageClass() { + final StorageClass value = StorageClass.STANDARD; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .storageClass(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.storageClass()); + } + + @Test + void testConvertPutObjectRequest_StorageClass2() { + final String value = StorageClass.STANDARD.toString(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .storageClass(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.storageClass().toString()); + } + + @Test + void testConvertPutObjectRequest_Tagging() { + final String value = "key1=value1&key2=value2"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .tagging(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.tagging()); + } + + @Test + void testConvertPutObjectRequest_WebsiteRedirectLocation() { + final String value = "/redirected"; + PutObjectRequest originalRequest = PutObjectRequest.builder() + .websiteRedirectLocation(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertEquals(value, convertedRequest.websiteRedirectLocation()); + } + + @Test + void testConvertPutObjectRequest_OverrideConfiguration() { + final AwsRequestOverrideConfiguration value = AwsRequestOverrideConfiguration + .builder() + .apiCallAttemptTimeout(Duration.ofMillis(100)) + .build(); + PutObjectRequest originalRequest = PutObjectRequest.builder() + .overrideConfiguration(value) + .build(); + final CreateMultipartUploadRequest convertedRequest = ConvertSDKRequests.convert(originalRequest); + assertNotNull(convertedRequest); + assertTrue(convertedRequest.overrideConfiguration().isPresent()); + assertEquals(value, convertedRequest.overrideConfiguration().get()); + } +}