From 05e95eed3abde5492d62b97aa17849d6b1cccebc Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Thu, 23 Jul 2026 08:00:56 -0700 Subject: [PATCH 1/7] Remove resolveClientEndpointProvider from AwsDefaultClientBuilder This fallback method was triggering GeneratedServiceMetadataProvider initialization (~350ms) during every client creation because AttributeMap.build() eagerly resolves all lazy values including lazyOptionIfAbsent fallbacks. All generated clients have set CLIENT_ENDPOINT_PROVIDER themselves since SDK 2.27.16. Added null validation with clear error message for custom clients that don't set it --- .../builder/AwsDefaultClientBuilder.java | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index cf74d712bc26..9641c8aff2b0 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -34,7 +34,6 @@ import software.amazon.awssdk.awscore.client.config.AwsAdvancedClientOption; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.defaultsmode.DefaultsMode; -import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.awscore.endpoint.DualstackEnabledProvider; import software.amazon.awssdk.awscore.endpoint.FipsEnabledProvider; import software.amazon.awssdk.awscore.eventstream.EventStreamInitialRequestInterceptor; @@ -75,6 +74,7 @@ import software.amazon.awssdk.utils.Logger; import software.amazon.awssdk.utils.Pair; import software.amazon.awssdk.utils.StringUtils; +import software.amazon.awssdk.utils.Validate; /** * An SDK-internal implementation of the methods in {@link AwsClientBuilder}, {@link AwsAsyncClientBuilder} and @@ -97,7 +97,6 @@ public abstract class AwsDefaultClientBuilder implements AwsClientBuilder { private static final Logger log = Logger.loggerFor(AwsClientBuilder.class); - private static final String DEFAULT_ENDPOINT_PROTOCOL = "https"; private static final String[] FIPS_SEARCH = {"fips-", "-fips"}; private static final String[] FIPS_REPLACE = {"", ""}; @@ -188,7 +187,6 @@ private SdkClientConfiguration finalizeAwsConfiguration(SdkClientConfiguration c this::resolveCredentialsIdentityProvider) // Set CREDENTIALS_PROVIDER, because older clients may be relying on it .lazyOptionIfAbsent(AwsClientOption.CREDENTIALS_PROVIDER, this::resolveCredentialsProvider) - .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, this::resolveClientEndpointProvider) // Set ENDPOINT and ENDPOINT_OVERRIDDEN, because older clients may be relying on it .lazyOptionIfAbsent(SdkClientOption.ENDPOINT, this::resolveEndpoint) .lazyOptionIfAbsent(SdkClientOption.ENDPOINT_OVERRIDDEN, this::resolveEndpointOverridden) @@ -320,33 +318,16 @@ private Region resolveSigningRegion(LazyValueSource config) { .signingRegion(config.get(AwsClientOption.AWS_REGION)); } - /** - * Specify the client endpoint provider to use for the client, if the client didn't specify one itself. - *

- * This is only used for older client versions. Newer clients specify this value themselves. - */ - private ClientEndpointProvider resolveClientEndpointProvider(LazyValueSource config) { - ServiceMetadataAdvancedOption useGlobalS3EndpointProperty = - ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT; - return AwsClientEndpointProvider.builder() - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol(DEFAULT_ENDPOINT_PROTOCOL) - .region(config.get(AwsClientOption.AWS_REGION)) - .profileFile(config.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) - .profileName(config.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(useGlobalS3EndpointProperty, - config.get(useGlobalS3EndpointProperty)) - .dualstackEnabled(config.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(config.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)) - .build(); - } - /** * Resolve the client endpoint. This code is only needed by old SDK client versions. Newer SDK client versions resolve this * information from the client endpoint provider. */ private URI resolveEndpoint(LazyValueSource config) { - return config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).clientEndpoint(); + ClientEndpointProvider clientEndpointProvider = config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + Validate.notNull(clientEndpointProvider, + "No CLIENT_ENDPOINT_PROVIDER was configured. Client builders must set " + + "SdkClientOption.CLIENT_ENDPOINT_PROVIDER in finalizeServiceConfiguration()."); + return clientEndpointProvider.clientEndpoint(); } /** @@ -354,7 +335,11 @@ private URI resolveEndpoint(LazyValueSource config) { * client versions resolve this information from the client endpoint provider. */ private boolean resolveEndpointOverridden(LazyValueSource config) { - return config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER).isEndpointOverridden(); + ClientEndpointProvider clientEndpointProvider = config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); + Validate.notNull(clientEndpointProvider, + "No CLIENT_ENDPOINT_PROVIDER was configured. Client builders must set " + + "SdkClientOption.CLIENT_ENDPOINT_PROVIDER in finalizeServiceConfiguration()."); + return clientEndpointProvider.isEndpointOverridden(); } /** From f756d41fadb975a011a091362c1572ab4cd422fa Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Thu, 23 Jul 2026 16:06:21 -0700 Subject: [PATCH 2/7] fix tests --- .../endpoint/AwsClientEndpointProvider.java | 5 ++++ .../builder/DefaultAwsClientBuilderTest.java | 23 ++++++++++++++++ .../client/builder/DefaultsModeTest.java | 26 +++++++++++++++++++ .../client/builder/FipsPseudoRegionTest.java | 14 ++++++++++ .../client/builder/InternalDefaultsTest.java | 14 ++++++++++ 5 files changed, 82 insertions(+) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 2e660f06ea08..480e7cea2d3c 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -480,6 +480,11 @@ public Builder putAdvancedOption(ServiceMetadataAdvancedOption option, T return this; } + /** + * @deprecated Use {@link #resolveFromOverrides()} instead, combined with the service's EndpointProvider + * for default resolution. This method triggers expensive ServiceMetadata initialization. + */ + @Deprecated public AwsClientEndpointProvider build() { return new AwsClientEndpointProvider(this); } diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java index 74d263c68f43..bbd0852bf4e1 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultAwsClientBuilderTest.java @@ -52,6 +52,7 @@ import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.internal.retry.SdkDefaultRetryStrategy; import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.http.SdkHttpClient; @@ -403,6 +404,17 @@ protected TestClient buildClient() { return new TestClient(super.syncClientConfiguration()); } + @Override + protected SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + return config.toBuilder() + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { + URI endpoint = URI.create("https://" + serviceEndpointPrefix() + "." + + c.get(AwsClientOption.AWS_REGION) + ".amazonaws.com"); + return ClientEndpointProvider.create(endpoint, false); + }) + .build(); + } + @Override protected String serviceEndpointPrefix() { return ENDPOINT_PREFIX; @@ -444,6 +456,17 @@ protected TestAsyncClient buildClient() { return new TestAsyncClient(super.asyncClientConfiguration()); } + @Override + protected SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + return config.toBuilder() + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { + URI endpoint = URI.create("https://" + serviceEndpointPrefix() + "." + + c.get(AwsClientOption.AWS_REGION) + ".amazonaws.com"); + return ClientEndpointProvider.create(endpoint, false); + }) + .build(); + } + @Override protected String serviceEndpointPrefix() { return ENDPOINT_PREFIX; diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultsModeTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultsModeTest.java index 2b9ea42a5d73..37bfd4dcf901 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultsModeTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/DefaultsModeTest.java @@ -37,6 +37,10 @@ import software.amazon.awssdk.awscore.internal.defaultsmode.DefaultsModeConfiguration; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; +import software.amazon.awssdk.core.ClientEndpointProvider; +import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import java.net.URI; import software.amazon.awssdk.core.internal.retry.SdkDefaultRetryStrategy; import software.amazon.awssdk.core.retry.RetryMode; import software.amazon.awssdk.http.SdkHttpClient; @@ -187,6 +191,17 @@ protected TestClient buildClient() { return new TestClient(super.syncClientConfiguration()); } + @Override + protected SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + return config.toBuilder() + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { + URI endpoint = URI.create("https://" + serviceEndpointPrefix() + "." + + c.get(AwsClientOption.AWS_REGION) + ".amazonaws.com"); + return ClientEndpointProvider.create(endpoint, false); + }) + .build(); + } + @Override protected String serviceEndpointPrefix() { return ENDPOINT_PREFIX; @@ -220,6 +235,17 @@ protected TestAsyncClient buildClient() { return new TestAsyncClient(super.asyncClientConfiguration()); } + @Override + protected SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + return config.toBuilder() + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { + URI endpoint = URI.create("https://" + serviceEndpointPrefix() + "." + + c.get(AwsClientOption.AWS_REGION) + ".amazonaws.com"); + return ClientEndpointProvider.create(endpoint, false); + }) + .build(); + } + @Override protected String serviceEndpointPrefix() { return ENDPOINT_PREFIX; diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/FipsPseudoRegionTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/FipsPseudoRegionTest.java index c20f3d924157..5cf5c5d859e7 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/FipsPseudoRegionTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/FipsPseudoRegionTest.java @@ -22,6 +22,7 @@ import static software.amazon.awssdk.awscore.client.config.AwsAdvancedClientOption.ENABLE_DEFAULT_REGION_DETECTION; import static software.amazon.awssdk.core.client.config.SdkAdvancedClientOption.SIGNER; +import java.net.URI; import java.time.Duration; import java.util.ArrayList; import java.util.List; @@ -30,8 +31,10 @@ import org.junit.jupiter.params.provider.MethodSource; import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; +import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.core.signer.Signer; import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpConfigurationOption; @@ -122,6 +125,17 @@ protected TestClient buildClient() { return new TestClient(super.syncClientConfiguration()); } + @Override + protected SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + return config.toBuilder() + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { + URI endpoint = URI.create("https://" + serviceEndpointPrefix() + "." + + c.get(AwsClientOption.AWS_REGION) + ".amazonaws.com"); + return ClientEndpointProvider.create(endpoint, false); + }) + .build(); + } + @Override protected String serviceEndpointPrefix() { return ENDPOINT_PREFIX; diff --git a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/InternalDefaultsTest.java b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/InternalDefaultsTest.java index 5c411276e923..6de908763b03 100644 --- a/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/InternalDefaultsTest.java +++ b/core/aws-core/src/test/java/software/amazon/awssdk/awscore/client/builder/InternalDefaultsTest.java @@ -28,6 +28,9 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import software.amazon.awssdk.core.SdkSystemSetting; +import java.net.URI; +import software.amazon.awssdk.awscore.client.config.AwsClientOption; +import software.amazon.awssdk.core.ClientEndpointProvider; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; import software.amazon.awssdk.http.SdkHttpClient; @@ -159,5 +162,16 @@ protected TestClient buildClient() { return new TestClient(config); } + + @Override + protected SdkClientConfiguration finalizeServiceConfiguration(SdkClientConfiguration config) { + return config.toBuilder() + .lazyOptionIfAbsent(SdkClientOption.CLIENT_ENDPOINT_PROVIDER, c -> { + URI endpoint = URI.create("https://" + serviceEndpointPrefix() + "." + + c.get(AwsClientOption.AWS_REGION) + ".amazonaws.com"); + return ClientEndpointProvider.create(endpoint, false); + }) + .build(); + } } } From 493fab4282001b9c941b227e2460d088f57a472b Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Fri, 24 Jul 2026 10:55:09 -0700 Subject: [PATCH 3/7] update s3 depedency version in the old version compatibilty tests --- test/old-client-version-compatibility-test/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/old-client-version-compatibility-test/pom.xml b/test/old-client-version-compatibility-test/pom.xml index cbbb76f723c8..be3f73ee59f6 100644 --- a/test/old-client-version-compatibility-test/pom.xml +++ b/test/old-client-version-compatibility-test/pom.xml @@ -103,7 +103,7 @@ software.amazon.awssdk s3 - 2.20.136 + 2.28.1 From 6fc8f739623560301a4153253eea6cc2a93b8e91 Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Fri, 24 Jul 2026 15:21:26 -0700 Subject: [PATCH 4/7] Update javadoc --- .../client/builder/AwsDefaultClientBuilder.java | 17 +++++++++-------- .../endpoint/AwsClientEndpointProvider.java | 6 ++++-- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index 9641c8aff2b0..9f6f7548cfd7 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -323,11 +323,7 @@ private Region resolveSigningRegion(LazyValueSource config) { * information from the client endpoint provider. */ private URI resolveEndpoint(LazyValueSource config) { - ClientEndpointProvider clientEndpointProvider = config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); - Validate.notNull(clientEndpointProvider, - "No CLIENT_ENDPOINT_PROVIDER was configured. Client builders must set " - + "SdkClientOption.CLIENT_ENDPOINT_PROVIDER in finalizeServiceConfiguration()."); - return clientEndpointProvider.clientEndpoint(); + return requireClientEndpointProvider(config).clientEndpoint(); } /** @@ -335,11 +331,16 @@ private URI resolveEndpoint(LazyValueSource config) { * client versions resolve this information from the client endpoint provider. */ private boolean resolveEndpointOverridden(LazyValueSource config) { + return requireClientEndpointProvider(config).isEndpointOverridden(); + } + + private ClientEndpointProvider requireClientEndpointProvider(LazyValueSource config) { ClientEndpointProvider clientEndpointProvider = config.get(SdkClientOption.CLIENT_ENDPOINT_PROVIDER); Validate.notNull(clientEndpointProvider, - "No CLIENT_ENDPOINT_PROVIDER was configured. Client builders must set " - + "SdkClientOption.CLIENT_ENDPOINT_PROVIDER in finalizeServiceConfiguration()."); - return clientEndpointProvider.isEndpointOverridden(); + "No CLIENT_ENDPOINT_PROVIDER was configured. This is typically caused by using " + + "an older service client version with a newer sdk-core. " + + "Please align all SDK dependency versions."); + return clientEndpointProvider; } /** diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 480e7cea2d3c..7251ce6cbe1f 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -481,8 +481,10 @@ public Builder putAdvancedOption(ServiceMetadataAdvancedOption option, T } /** - * @deprecated Use {@link #resolveFromOverrides()} instead, combined with the service's EndpointProvider - * for default resolution. This method triggers expensive ServiceMetadata initialization. + * @deprecated Since 2.x.x. Use {@link #resolveFromOverrides()} instead, combined with the service's + * EndpointProvider for default endpoint resolution. This method triggers expensive + * {@code ServiceMetadata} initialization which is unnecessary when the service + * EndpointProvider can resolve the default endpoint directly. */ @Deprecated public AwsClientEndpointProvider build() { From b89eaa1ec34f60aefeeaa92513bdc44e535224e6 Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Sun, 26 Jul 2026 18:14:49 -0700 Subject: [PATCH 5/7] update javadoc --- .../awssdk/awscore/endpoint/AwsClientEndpointProvider.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 7251ce6cbe1f..6697bbb94448 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -481,10 +481,9 @@ public Builder putAdvancedOption(ServiceMetadataAdvancedOption option, T } /** - * @deprecated Since 2.x.x. Use {@link #resolveFromOverrides()} instead, combined with the service's - * EndpointProvider for default endpoint resolution. This method triggers expensive - * {@code ServiceMetadata} initialization which is unnecessary when the service - * EndpointProvider can resolve the default endpoint directly. + * @deprecated This method triggers expensive ServiceMetadata + * initialization and is no longer used by the SDK. Service endpoint resolution is handled + * by Endpoints 2.0 at request time. */ @Deprecated public AwsClientEndpointProvider build() { From 775f9186062d2bb2ddd560436f281f9fc8393ca9 Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Wed, 29 Jul 2026 13:20:05 -0700 Subject: [PATCH 6/7] Adress PR feedback --- pom.xml | 2 +- .../oldclient/S3PutGetIntegrationTest.java | 181 ---------------- .../awssdk/services/oldclient/TestUtils.java | 86 -------- .../src/it/resources/log4j2.properties | 38 ---- .../pom.xml | 52 ++--- .../InterceptorSignerAttributeTest.java | 67 +++--- .../backwardcompat}/S3AnonymousTest.java | 2 + .../backwardcompat/S3OperationsTest.java | 194 ++++++++++++++++++ 8 files changed, 234 insertions(+), 388 deletions(-) delete mode 100644 test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/S3PutGetIntegrationTest.java delete mode 100644 test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/TestUtils.java delete mode 100644 test/old-client-version-compatibility-test/src/it/resources/log4j2.properties rename test/{old-client-version-compatibility-test => service-client-backward-compat-test}/pom.xml (79%) rename test/{old-client-version-compatibility-test/src/test/java => service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat}/InterceptorSignerAttributeTest.java (76%) rename test/{old-client-version-compatibility-test/src/test/java => service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat}/S3AnonymousTest.java (98%) create mode 100644 test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3OperationsTest.java diff --git a/pom.xml b/pom.xml index 1e56b13fb819..61f089786022 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ test/auth-tests test/region-testing test/ruleset-testing-core - test/old-client-version-compatibility-test + test/service-client-backward-compat-test test/bundle-logging-bridge-binding-test test/v2-migration-tests test/bundle-shading-tests diff --git a/test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/S3PutGetIntegrationTest.java b/test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/S3PutGetIntegrationTest.java deleted file mode 100644 index 30f742d7a54d..000000000000 --- a/test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/S3PutGetIntegrationTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.awssdk.services.oldclient; - -import static org.assertj.core.api.AssertionsForClassTypes.assertThat; - -import java.util.UUID; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; -import software.amazon.awssdk.auth.signer.AwsS3V4Signer; -import software.amazon.awssdk.core.ResponseBytes; -import software.amazon.awssdk.core.async.AsyncRequestBody; -import software.amazon.awssdk.core.async.AsyncResponseTransformer; -import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption; -import software.amazon.awssdk.core.sync.RequestBody; -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.S3Client; -import software.amazon.awssdk.services.s3.S3ClientBuilder; -import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm; -import software.amazon.awssdk.services.s3.model.ChecksumMode; -import software.amazon.awssdk.services.s3.model.GetObjectResponse; -import software.amazon.awssdk.testutils.service.AwsTestBase; - -public class S3PutGetIntegrationTest extends AwsTestBase { - private static final S3Client S3 = - s3ClientBuilder().build(); - private static final S3Client S3_CUSTOM_SIGNER = - s3ClientBuilder().overrideConfiguration(c -> c.putAdvancedOption(SdkAdvancedClientOption.SIGNER, - AwsS3V4Signer.create())) - .build(); - private static final S3Client S3_NO_CREDS = - s3ClientBuilder().credentialsProvider(AnonymousCredentialsProvider.create()) - .build(); - - private static final S3AsyncClient S3_ASYNC = - getS3AsyncClientBuilder().build(); - private static final S3AsyncClient S3_ASYNC_CUSTOM_SIGNER = - getS3AsyncClientBuilder().overrideConfiguration(c -> c.putAdvancedOption(SdkAdvancedClientOption.SIGNER, - AwsS3V4Signer.create())) - .build(); - private static final S3AsyncClient S3_ASYNC_NO_CREDS = - getS3AsyncClientBuilder().credentialsProvider(AnonymousCredentialsProvider.create()) - .build(); - - private static final String BUCKET = "sra-get-put-integ-" + System.currentTimeMillis(); - private static final String BODY = "foo"; - private static final String BODY_CRC32 = "jHNlIQ=="; - - private String key; - - @BeforeAll - public static void setup() { - S3.createBucket(r -> r.bucket(BUCKET)); - } - - @BeforeEach - public void setupTest() { - key = UUID.randomUUID().toString(); - } - - @AfterAll - public static void teardown() { - TestUtils.deleteBucketAndAllContents(S3, BUCKET); - } - - @Test - public void putGet() { - S3.putObject(r -> r.bucket(BUCKET).key(key), RequestBody.fromString(BODY)); - assertThat(S3.getObjectAsBytes(r -> r.bucket(BUCKET).key(key)).asUtf8String()).isEqualTo(BODY); - } - - @Test - public void putGet_async() { - S3_ASYNC.putObject(r -> r.bucket(BUCKET).key(key), AsyncRequestBody.fromString(BODY)).join(); - assertThat(S3_ASYNC.getObject(r -> r.bucket(BUCKET).key(key), - AsyncResponseTransformer.toBytes()) - .join() - .asUtf8String()).isEqualTo(BODY); - } - - @Test - public void putGet_requestLevelCreds() { - S3_NO_CREDS.putObject(r -> r.bucket(BUCKET) - .key(key) - .overrideConfiguration(c -> c.credentialsProvider(CREDENTIALS_PROVIDER_CHAIN)), - RequestBody.fromString(BODY)); - assertThat(S3_NO_CREDS.getObjectAsBytes(r -> r.bucket(BUCKET) - .key(key) - .overrideConfiguration(c -> c.credentialsProvider(CREDENTIALS_PROVIDER_CHAIN))) - .asUtf8String()).isEqualTo(BODY); - } - - @Test - public void putGet_async_requestLevelCreds() { - S3_ASYNC_NO_CREDS.putObject(r -> r.bucket(BUCKET) - .key(key) - .overrideConfiguration(c -> c.credentialsProvider(CREDENTIALS_PROVIDER_CHAIN)), - AsyncRequestBody.fromString(BODY)) - .join(); - assertThat(S3_ASYNC_NO_CREDS.getObject(r -> r.bucket(BUCKET) - .key(key) - .overrideConfiguration(c -> c.credentialsProvider(CREDENTIALS_PROVIDER_CHAIN)), - AsyncResponseTransformer.toBytes()) - .join() - .asUtf8String()).isEqualTo(BODY); - } - - @Test - public void putGet_flexibleChecksums() { - S3.putObject(r -> r.bucket(BUCKET).key(key).checksumAlgorithm(ChecksumAlgorithm.CRC32), - RequestBody.fromString(BODY)); - ResponseBytes response = - S3.getObjectAsBytes(r -> r.bucket(BUCKET).key(key).checksumMode(ChecksumMode.ENABLED)); - assertThat(response.asUtf8String()).isEqualTo(BODY); - assertThat(response.response().checksumCRC32()).isEqualTo(BODY_CRC32); - } - - @Test - public void putGet_async_flexibleChecksums() { - S3_ASYNC.putObject(r -> r.bucket(BUCKET).key(key).checksumAlgorithm(ChecksumAlgorithm.CRC32), - AsyncRequestBody.fromString(BODY)).join(); - ResponseBytes response = S3_ASYNC.getObject(r -> r.bucket(BUCKET).key(key).checksumMode(ChecksumMode.ENABLED), - AsyncResponseTransformer.toBytes()) - .join(); - assertThat(response.asUtf8String()).isEqualTo(BODY); - assertThat(response.response().checksumCRC32()).isEqualTo(BODY_CRC32); - } - - @Test - public void putGet_customSigner_flexibleChecksums() { - S3_CUSTOM_SIGNER.putObject(r -> r.bucket(BUCKET).key(key).checksumAlgorithm(ChecksumAlgorithm.CRC32), - RequestBody.fromString(BODY)); - ResponseBytes response = - S3_CUSTOM_SIGNER.getObjectAsBytes(r -> r.bucket(BUCKET).key(key).checksumMode(ChecksumMode.ENABLED)); - assertThat(response.asUtf8String()).isEqualTo(BODY); - assertThat(response.response().checksumCRC32()).isEqualTo(BODY_CRC32); - } - - @Test - public void putGet_async_customSigner_flexibleChecksums() { - S3_ASYNC_CUSTOM_SIGNER.putObject(r -> r.bucket(BUCKET).key(key).checksumAlgorithm(ChecksumAlgorithm.CRC32), - AsyncRequestBody.fromString(BODY)) - .join(); - ResponseBytes response = - S3_ASYNC_CUSTOM_SIGNER.getObject(r -> r.bucket(BUCKET).key(key).checksumMode(ChecksumMode.ENABLED), - AsyncResponseTransformer.toBytes()) - .join(); - assertThat(response.asUtf8String()).isEqualTo(BODY); - assertThat(response.response().checksumCRC32()).isEqualTo(BODY_CRC32); - } - - private static S3ClientBuilder s3ClientBuilder() { - return S3Client.builder() - .region(Region.US_WEST_2) - .credentialsProvider(CREDENTIALS_PROVIDER_CHAIN); - } - - private static S3AsyncClientBuilder getS3AsyncClientBuilder() { - return S3AsyncClient.builder() - .region(Region.US_WEST_2) - .credentialsProvider(CREDENTIALS_PROVIDER_CHAIN); - } -} diff --git a/test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/TestUtils.java b/test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/TestUtils.java deleted file mode 100644 index 6a1bb1e4cec7..000000000000 --- a/test/old-client-version-compatibility-test/src/it/java/software/amazon/awssdk/services/oldclient/TestUtils.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://aws.amazon.com/apache2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package software.amazon.awssdk.services.oldclient; - -import java.util.Iterator; -import java.util.List; -import software.amazon.awssdk.services.s3.S3Client; -import software.amazon.awssdk.services.s3.model.DeleteBucketRequest; -import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; -import software.amazon.awssdk.services.s3.model.ListObjectVersionsRequest; -import software.amazon.awssdk.services.s3.model.ListObjectVersionsResponse; -import software.amazon.awssdk.services.s3.model.ListObjectsRequest; -import software.amazon.awssdk.services.s3.model.ListObjectsResponse; -import software.amazon.awssdk.services.s3.model.NoSuchBucketException; -import software.amazon.awssdk.services.s3.model.S3Object; -import software.amazon.awssdk.testutils.Waiter; - -public class TestUtils { - - public static void deleteBucketAndAllContents(S3Client s3, String bucketName) { - try { - System.out.println("Deleting S3 bucket: " + bucketName); - ListObjectsResponse response = Waiter.run(() -> s3.listObjects(r -> r.bucket(bucketName))) - .ignoringException(NoSuchBucketException.class) - .orFail(); - List objectListing = response.contents(); - - if (objectListing != null) { - while (true) { - for (Iterator iterator = objectListing.iterator(); iterator.hasNext(); ) { - S3Object objectSummary = (S3Object) iterator.next(); - s3.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(objectSummary.key()).build()); - } - - if (response.isTruncated()) { - objectListing = s3.listObjects(ListObjectsRequest.builder() - .bucket(bucketName) - .marker(response.marker()) - .build()) - .contents(); - } else { - break; - } - } - } - - - ListObjectVersionsResponse versions = s3 - .listObjectVersions(ListObjectVersionsRequest.builder().bucket(bucketName).build()); - - if (versions.deleteMarkers() != null) { - versions.deleteMarkers().forEach(v -> s3.deleteObject(DeleteObjectRequest.builder() - .versionId(v.versionId()) - .bucket(bucketName) - .key(v.key()) - .build())); - } - - if (versions.versions() != null) { - versions.versions().forEach(v -> s3.deleteObject(DeleteObjectRequest.builder() - .versionId(v.versionId()) - .bucket(bucketName) - .key(v.key()) - .build())); - } - - s3.deleteBucket(DeleteBucketRequest.builder().bucket(bucketName).build()); - } catch (Exception e) { - System.err.println("Failed to delete bucket: " + bucketName); - e.printStackTrace(); - } - } -} diff --git a/test/old-client-version-compatibility-test/src/it/resources/log4j2.properties b/test/old-client-version-compatibility-test/src/it/resources/log4j2.properties deleted file mode 100644 index e5e68dd2faa4..000000000000 --- a/test/old-client-version-compatibility-test/src/it/resources/log4j2.properties +++ /dev/null @@ -1,38 +0,0 @@ -# -# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"). -# You may not use this file except in compliance with the License. -# A copy of the License is located at -# -# http://aws.amazon.com/apache2.0 -# -# or in the "license" file accompanying this file. This file is distributed -# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either -# express or implied. See the License for the specific language governing -# permissions and limitations under the License. -# - -status = warn - -appender.console.type = Console -appender.console.name = ConsoleAppender -appender.console.layout.type = PatternLayout -appender.console.layout.pattern = %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n%throwable - -rootLogger.level = info -rootLogger.appenderRef.stdout.ref = ConsoleAppender - -# Uncomment below to enable more specific logging -# -#logger.sdk.name = software.amazon.awssdk -#logger.sdk.level = debug -# -#logger.request.name = software.amazon.awssdk.request -#logger.request.level = debug -# -#logger.apache.name = org.apache.http.wire -#logger.apache.level = debug -# -#logger.netty.name = io.netty.handler.logging -#logger.netty.level = debug diff --git a/test/old-client-version-compatibility-test/pom.xml b/test/service-client-backward-compat-test/pom.xml similarity index 79% rename from test/old-client-version-compatibility-test/pom.xml rename to test/service-client-backward-compat-test/pom.xml index be3f73ee59f6..f0998dd2cf3d 100644 --- a/test/old-client-version-compatibility-test/pom.xml +++ b/test/service-client-backward-compat-test/pom.xml @@ -25,10 +25,11 @@ ../../pom.xml - old-client-version-compatibility-test - AWS Java SDK :: Test :: Old Client Version Compatibility Test + service-client-backward-compat-test + AWS Java SDK :: Test :: Service Client Backward Compatibility Test - Tests for old client versions with the latest "core" package versions. + Tests that verify older service client versions (>= 2.28.1) work correctly with the latest core modules. + This ensures backward compatibility for the new core + old service client version skew scenario. https://aws.amazon.com/sdkforjava @@ -79,7 +80,7 @@ ${awsjavasdk.version} - + software.amazon.awssdk aws-xml-protocol @@ -99,7 +100,7 @@ runtime - + software.amazon.awssdk s3 @@ -109,44 +110,19 @@ software.amazon.awssdk - service-test-utils - ${project.version} - - - org.junit.jupiter - junit-jupiter - test - - - com.github.tomakehurst - wiremock-jre8-standalone - test - - - org.apache.logging.log4j - log4j-api - test - - - org.apache.logging.log4j - log4j-core - test - - - org.apache.logging.log4j - log4j-slf4j-impl + test-utils test - org.mockito - mockito-core + software.amazon.awssdk + service-test-utils + ${project.version} test - org.slf4j - jcl-over-slf4j + org.junit.jupiter + junit-jupiter test - ${slf4j.version} org.assertj @@ -154,8 +130,8 @@ test - software.amazon.awssdk - test-utils + org.mockito + mockito-core test diff --git a/test/old-client-version-compatibility-test/src/test/java/InterceptorSignerAttributeTest.java b/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/InterceptorSignerAttributeTest.java similarity index 76% rename from test/old-client-version-compatibility-test/src/test/java/InterceptorSignerAttributeTest.java rename to test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/InterceptorSignerAttributeTest.java index 58b525e89528..d014700c9a0b 100644 --- a/test/old-client-version-compatibility-test/src/test/java/InterceptorSignerAttributeTest.java +++ b/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/InterceptorSignerAttributeTest.java @@ -13,12 +13,13 @@ * permissions and limitations under the License. */ +package software.amazon.awssdk.services.backwardcompat; + import static org.assertj.core.api.Assertions.assertThat; import java.util.Arrays; import java.util.HashSet; import java.util.Set; -import java.util.concurrent.CompletableFuture; import java.util.function.Consumer; import java.util.function.Function; import org.junit.jupiter.api.Test; @@ -40,18 +41,6 @@ import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpRequest; import software.amazon.awssdk.http.SdkHttpResponse; -import software.amazon.awssdk.http.auth.aws.scheme.AwsV4AuthScheme; -import software.amazon.awssdk.http.auth.aws.signer.AwsV4FamilyHttpSigner; -import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner; -import software.amazon.awssdk.http.auth.spi.scheme.AuthScheme; -import software.amazon.awssdk.http.auth.spi.signer.AsyncSignRequest; -import software.amazon.awssdk.http.auth.spi.signer.AsyncSignedRequest; -import software.amazon.awssdk.http.auth.spi.signer.HttpSigner; -import software.amazon.awssdk.http.auth.spi.signer.SignRequest; -import software.amazon.awssdk.http.auth.spi.signer.SignedRequest; -import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; -import software.amazon.awssdk.identity.spi.IdentityProvider; -import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.S3AsyncClientBuilder; @@ -76,10 +65,10 @@ public void beforeExecution(Context.BeforeExecution context, ExecutionAttributes attributeModifications.accept(executionAttributes); } }, - AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME, // Endpoint rules override signing name - AwsSignerExecutionAttribute.SIGNING_REGION, // Endpoint rules override signing region - AwsSignerExecutionAttribute.AWS_CREDENTIALS, // Legacy auth strategy overrides credentials - AwsSignerExecutionAttribute.SIGNER_DOUBLE_URL_ENCODE); // Endpoint rules override double-url-encode + AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME, + AwsSignerExecutionAttribute.SIGNING_REGION, + AwsSignerExecutionAttribute.AWS_CREDENTIALS, + AwsSignerExecutionAttribute.SIGNER_DOUBLE_URL_ENCODE); } @Test @@ -91,7 +80,7 @@ public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttribut return context.request(); } }, - AwsSignerExecutionAttribute.AWS_CREDENTIALS); // Legacy auth strategy overrides credentials + AwsSignerExecutionAttribute.AWS_CREDENTIALS); } @Test @@ -145,24 +134,19 @@ private void test(Function, ExecutionInterceptor> MockAsyncHttpClient asyncHttpClient = new MockAsyncHttpClient()) { stub200Responses(httpClient, asyncHttpClient); - S3ClientBuilder s3Builder = createS3Builder(configBuilder, httpClient); - S3AsyncClientBuilder s3AsyncBuilder = createS3AsyncBuilder(configBuilder, asyncHttpClient); - CapturingSigner signer1 = new CapturingSigner(); - try (S3Client s3 = s3Builder.overrideConfiguration(configBuilder.putAdvancedOption(SdkAdvancedClientOption.SIGNER, - signer1) - .build()) - .build()) { + try (S3Client s3 = createS3Builder(configBuilder, httpClient) + .overrideConfiguration(configBuilder.putAdvancedOption(SdkAdvancedClientOption.SIGNER, signer1).build()) + .build()) { callS3(s3); validateLegacySignRequest(attributesToExclude, signer1); } CapturingSigner signer2 = new CapturingSigner(); - try (S3AsyncClient s3 = - s3AsyncBuilder.overrideConfiguration(configBuilder.putAdvancedOption(SdkAdvancedClientOption.SIGNER, signer2) - .build()) - .build()) { - callS3(s3); + try (S3AsyncClient s3 = createS3AsyncBuilder(configBuilder, asyncHttpClient) + .overrideConfiguration(configBuilder.putAdvancedOption(SdkAdvancedClientOption.SIGNER, signer2).build()) + .build()) { + callS3Async(s3); validateLegacySignRequest(attributesToExclude, signer2); } } @@ -171,15 +155,14 @@ private void test(Function, ExecutionInterceptor> private static void stub200Responses(MockSyncHttpClient httpClient, MockAsyncHttpClient asyncHttpClient) { HttpExecuteResponse response = HttpExecuteResponse.builder() - .response(SdkHttpResponse.builder() - .statusCode(200) - .build()) + .response(SdkHttpResponse.builder().statusCode(200).build()) .build(); httpClient.stubResponses(response); asyncHttpClient.stubResponses(response); } - private static S3ClientBuilder createS3Builder(ClientOverrideConfiguration.Builder configBuilder, MockSyncHttpClient httpClient) { + private static S3ClientBuilder createS3Builder(ClientOverrideConfiguration.Builder configBuilder, + MockSyncHttpClient httpClient) { return S3Client.builder() .region(Region.US_WEST_2) .credentialsProvider(AnonymousCredentialsProvider.create()) @@ -187,7 +170,8 @@ private static S3ClientBuilder createS3Builder(ClientOverrideConfiguration.Build .overrideConfiguration(configBuilder.build()); } - private static S3AsyncClientBuilder createS3AsyncBuilder(ClientOverrideConfiguration.Builder configBuilder, MockAsyncHttpClient asyncHttpClient) { + private static S3AsyncClientBuilder createS3AsyncBuilder(ClientOverrideConfiguration.Builder configBuilder, + MockAsyncHttpClient asyncHttpClient) { return S3AsyncClient.builder() .region(Region.US_WEST_2) .credentialsProvider(AnonymousCredentialsProvider.create()) @@ -196,18 +180,13 @@ private static S3AsyncClientBuilder createS3AsyncBuilder(ClientOverrideConfigura } private static void callS3(S3Client s3) { - s3.putObject(r -> r.bucket("foo") - .key("bar") - .checksumAlgorithm(ChecksumAlgorithm.CRC32), + s3.putObject(r -> r.bucket("foo").key("bar").checksumAlgorithm(ChecksumAlgorithm.CRC32), RequestBody.fromString("text")); } - private void callS3(S3AsyncClient s3) { - s3.putObject(r -> r.bucket("foo") - .key("bar") - .checksumAlgorithm(ChecksumAlgorithm.CRC32), - AsyncRequestBody.fromString("text")) - .join(); + private void callS3Async(S3AsyncClient s3) { + s3.putObject(r -> r.bucket("foo").key("bar").checksumAlgorithm(ChecksumAlgorithm.CRC32), + AsyncRequestBody.fromString("text")).join(); } private void validateLegacySignRequest(Set> attributesToExclude, CapturingSigner signer) { diff --git a/test/old-client-version-compatibility-test/src/test/java/S3AnonymousTest.java b/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3AnonymousTest.java similarity index 98% rename from test/old-client-version-compatibility-test/src/test/java/S3AnonymousTest.java rename to test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3AnonymousTest.java index 72e6baba808a..bab85cf6f89f 100644 --- a/test/old-client-version-compatibility-test/src/test/java/S3AnonymousTest.java +++ b/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3AnonymousTest.java @@ -13,6 +13,8 @@ * permissions and limitations under the License. */ +package software.amazon.awssdk.services.backwardcompat; + import static org.assertj.core.api.Assertions.assertThat; import org.junit.jupiter.api.AfterEach; diff --git a/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3OperationsTest.java b/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3OperationsTest.java new file mode 100644 index 000000000000..9b7ba2031197 --- /dev/null +++ b/test/service-client-backward-compat-test/src/test/java/software/amazon/awssdk/services/backwardcompat/S3OperationsTest.java @@ -0,0 +1,194 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package software.amazon.awssdk.services.backwardcompat; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import software.amazon.awssdk.auth.credentials.AnonymousCredentialsProvider; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.core.async.AsyncRequestBody; +import software.amazon.awssdk.core.async.AsyncResponseTransformer; +import software.amazon.awssdk.core.sync.RequestBody; +import software.amazon.awssdk.core.sync.ResponseTransformer; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.s3.S3AsyncClient; +import software.amazon.awssdk.services.s3.S3Client; +import software.amazon.awssdk.services.s3.model.ChecksumAlgorithm; +import software.amazon.awssdk.services.s3.model.ChecksumMode; +import software.amazon.awssdk.testutils.service.http.MockAsyncHttpClient; +import software.amazon.awssdk.testutils.service.http.MockSyncHttpClient; + +/** + * Ensure that S3 put/get operations, flexible checksums, and request-level credential overrides work correctly. + */ +public class S3OperationsTest { + private static final StaticCredentialsProvider REQUEST_CREDENTIALS = + StaticCredentialsProvider.create(AwsBasicCredentials.create("request-akid", "request-skid")); + + private MockSyncHttpClient httpClient; + private MockAsyncHttpClient asyncHttpClient; + private S3Client s3; + private S3AsyncClient s3Async; + + @BeforeEach + public void setup() { + this.httpClient = new MockSyncHttpClient(); + this.httpClient.stubNextResponse200(); + + this.asyncHttpClient = new MockAsyncHttpClient(); + this.asyncHttpClient.stubNextResponse200(); + + this.s3 = S3Client.builder() + .region(Region.US_WEST_2) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .httpClient(httpClient) + .build(); + + this.s3Async = S3AsyncClient.builder() + .region(Region.US_WEST_2) + .credentialsProvider(AnonymousCredentialsProvider.create()) + .httpClient(asyncHttpClient) + .build(); + } + + @AfterEach + public void teardown() { + httpClient.close(); + asyncHttpClient.close(); + s3.close(); + s3Async.close(); + } + + // Put/Get operations + + @Test + public void putObject_sync_completesSuccessfully() { + s3.putObject(r -> r.bucket("bucket").key("key"), RequestBody.fromString("foo")); + assertThat(httpClient.getLastRequest()).isNotNull(); + assertThat(httpClient.getLastRequest().method().name()).isEqualTo("PUT"); + } + + @Test + public void putObject_async_completesSuccessfully() { + s3Async.putObject(r -> r.bucket("bucket").key("key"), AsyncRequestBody.fromString("foo")).join(); + assertThat(asyncHttpClient.getLastRequest()).isNotNull(); + assertThat(asyncHttpClient.getLastRequest().method().name()).isEqualTo("PUT"); + } + + @Test + public void getObject_sync_completesSuccessfully() { + s3.getObject(r -> r.bucket("bucket").key("key"), ResponseTransformer.toBytes()); + assertThat(httpClient.getLastRequest()).isNotNull(); + assertThat(httpClient.getLastRequest().method().name()).isEqualTo("GET"); + } + + @Test + public void getObject_async_completesSuccessfully() { + s3Async.getObject(r -> r.bucket("bucket").key("key"), AsyncResponseTransformer.toBytes()).join(); + assertThat(asyncHttpClient.getLastRequest()).isNotNull(); + assertThat(asyncHttpClient.getLastRequest().method().name()).isEqualTo("GET"); + } + + // Flexible checksums + + @Test + public void putObject_withChecksumAlgorithm_sync_sendsChecksumHeader() { + s3.putObject(r -> r.bucket("bucket").key("key").checksumAlgorithm(ChecksumAlgorithm.CRC32), + RequestBody.fromString("foo")); + assertThat(httpClient.getLastRequest()).isNotNull(); + // Checksum algorithm is sent as x-amz-sdk-checksum-algorithm, actual value as trailing header + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-sdk-checksum-algorithm")) + .isPresent() + .hasValue("CRC32"); + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-trailer")) + .isPresent() + .hasValue("x-amz-checksum-crc32"); + } + + @Test + public void putObject_withChecksumAlgorithm_async_sendsChecksumHeader() { + s3Async.putObject(r -> r.bucket("bucket").key("key").checksumAlgorithm(ChecksumAlgorithm.CRC32), + AsyncRequestBody.fromString("foo")).join(); + assertThat(asyncHttpClient.getLastRequest()).isNotNull(); + assertThat(asyncHttpClient.getLastRequest().firstMatchingHeader("x-amz-sdk-checksum-algorithm")) + .isPresent() + .hasValue("CRC32"); + assertThat(asyncHttpClient.getLastRequest().firstMatchingHeader("x-amz-trailer")) + .isPresent() + .hasValue("x-amz-checksum-crc32"); + } + + @Test + public void getObject_withChecksumMode_sync_sendsChecksumHeader() { + s3.getObject(r -> r.bucket("bucket").key("key").checksumMode(ChecksumMode.ENABLED), + ResponseTransformer.toBytes()); + assertThat(httpClient.getLastRequest()).isNotNull(); + assertThat(httpClient.getLastRequest().firstMatchingHeader("x-amz-checksum-mode")) + .isPresent() + .hasValue("ENABLED"); + } + + @Test + public void getObject_withChecksumMode_async_sendsChecksumHeader() { + s3Async.getObject(r -> r.bucket("bucket").key("key").checksumMode(ChecksumMode.ENABLED), + AsyncResponseTransformer.toBytes()).join(); + assertThat(asyncHttpClient.getLastRequest()).isNotNull(); + assertThat(asyncHttpClient.getLastRequest().firstMatchingHeader("x-amz-checksum-mode")) + .isPresent() + .hasValue("ENABLED"); + } + + // Request-level credential overrides + + @Test + public void requestLevelCredentials_overrideClientCredentials_sync() { + s3.putObject(r -> r.bucket("bucket") + .key("key") + .overrideConfiguration(c -> c.credentialsProvider(REQUEST_CREDENTIALS)), + RequestBody.fromString("foo")); + // Request should have Authorization header since we overrode anonymous with real credentials + assertThat(httpClient.getLastRequest().firstMatchingHeader("Authorization")).isPresent(); + } + + @Test + public void requestLevelCredentials_overrideClientCredentials_async() { + s3Async.putObject(r -> r.bucket("bucket") + .key("key") + .overrideConfiguration(c -> c.credentialsProvider(REQUEST_CREDENTIALS)), + AsyncRequestBody.fromString("foo")) + .join(); + // Request should have Authorization header since we overrode anonymous with real credentials + assertThat(asyncHttpClient.getLastRequest().firstMatchingHeader("Authorization")).isPresent(); + } + + @Test + public void withoutRequestLevelCredentials_usesClientAnonymous_sync() { + s3.putObject(r -> r.bucket("bucket").key("key"), RequestBody.fromString("foo")); + // No override — should be anonymous (no Authorization header) + assertThat(httpClient.getLastRequest().firstMatchingHeader("Authorization")).isEmpty(); + } + + @Test + public void withoutRequestLevelCredentials_usesClientAnonymous_async() { + s3Async.putObject(r -> r.bucket("bucket").key("key"), AsyncRequestBody.fromString("foo")).join(); + // No override — should be anonymous (no Authorization header) + assertThat(asyncHttpClient.getLastRequest().firstMatchingHeader("Authorization")).isEmpty(); + } +} From 429c9046c24e22138f98468b5937a2fea4aa4025 Mon Sep 17 00:00:00 2001 From: Saranya Somepalli Date: Wed, 29 Jul 2026 14:33:17 -0700 Subject: [PATCH 7/7] Fix tests --- test/tests-coverage-reporting/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests-coverage-reporting/pom.xml b/test/tests-coverage-reporting/pom.xml index 3af81c8076e5..0353870e9fc8 100644 --- a/test/tests-coverage-reporting/pom.xml +++ b/test/tests-coverage-reporting/pom.xml @@ -218,7 +218,7 @@ ${awsjavasdk.version} - old-client-version-compatibility-test + service-client-backward-compat-test software.amazon.awssdk ${awsjavasdk.version}