From f71257ba6c453db7d60ffaa91af85393c59f70a0 Mon Sep 17 00:00:00 2001 From: Alex Woods Date: Tue, 14 Oct 2025 12:12:18 -0700 Subject: [PATCH] Set the RESOLVED_ACCOUNT_ID (T) user-agent metric only when accountID is actually resolved from credentials --- .../bugfix-AWSSDKforJavav2-fa66812.json | 6 +++ .../rules/EndpointParamsKnowledgeIndex.java | 7 +++- .../endpoint-resolve-interceptor-preSra.java | 6 ++- ...e-interceptor-with-endpointsbasedauth.java | 6 ++- .../rules/endpoint-resolve-interceptor.java | 6 ++- .../BusinessMetricsUserAgentTest.java | 37 +++++++++++++++++-- 6 files changed, 56 insertions(+), 12 deletions(-) create mode 100644 .changes/next-release/bugfix-AWSSDKforJavav2-fa66812.json diff --git a/.changes/next-release/bugfix-AWSSDKforJavav2-fa66812.json b/.changes/next-release/bugfix-AWSSDKforJavav2-fa66812.json new file mode 100644 index 000000000000..2a16438c3fbe --- /dev/null +++ b/.changes/next-release/bugfix-AWSSDKforJavav2-fa66812.json @@ -0,0 +1,6 @@ +{ + "type": "bugfix", + "category": "AWS SDK for Java v2", + "contributor": "", + "description": "Set the RESOLVED_ACCOUNT_ID (T) user-agent metric only when accountID is actually resolved from credentials." +} diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/EndpointParamsKnowledgeIndex.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/EndpointParamsKnowledgeIndex.java index 4cb808ef8334..7d200aeae0b5 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/EndpointParamsKnowledgeIndex.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/rules/EndpointParamsKnowledgeIndex.java @@ -204,8 +204,11 @@ public MethodSpec resolveAndRecordAccountIdFromIdentityMethod() { builder.addStatement("$T accountId = accountIdFromIdentity(executionAttributes.getAttribute($T.SELECTED_AUTH_SCHEME))", String.class, SdkInternalExecutionAttribute.class); - builder.addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS).addMetric($T.RESOLVED_ACCOUNT_ID.value())", - SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class); + builder + .beginControlFlow("if (accountId != null)") + .addStatement("executionAttributes.getAttribute($T.BUSINESS_METRICS).addMetric($T.RESOLVED_ACCOUNT_ID.value())", + SdkInternalExecutionAttribute.class, BusinessMetricFeatureId.class) + .endControlFlow(); builder.addStatement("return accountId"); diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-preSra.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-preSra.java index 7f71d8ec6856..cf27b03ed0c3 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-preSra.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-preSra.java @@ -266,8 +266,10 @@ private Supplier signerProvider(EndpointAuthScheme authScheme) { private static String resolveAndRecordAccountIdFromIdentity(ExecutionAttributes executionAttributes) { String accountId = accountIdFromIdentity(executionAttributes .getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME)); - executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( - BusinessMetricFeatureId.RESOLVED_ACCOUNT_ID.value()); + if (accountId != null) { + executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( + BusinessMetricFeatureId.RESOLVED_ACCOUNT_ID.value()); + } return accountId; } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-with-endpointsbasedauth.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-with-endpointsbasedauth.java index 80bc25041da3..6d6aa1dc2138 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-with-endpointsbasedauth.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor-with-endpointsbasedauth.java @@ -242,8 +242,10 @@ private static Optional hostPrefix(String operationName, SdkRequest requ private static String resolveAndRecordAccountIdFromIdentity(ExecutionAttributes executionAttributes) { String accountId = accountIdFromIdentity(executionAttributes .getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME)); - executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( - BusinessMetricFeatureId.RESOLVED_ACCOUNT_ID.value()); + if (accountId != null) { + executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( + BusinessMetricFeatureId.RESOLVED_ACCOUNT_ID.value()); + } return accountId; } diff --git a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor.java b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor.java index 2b194a0d3548..abdfedab0455 100644 --- a/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor.java +++ b/codegen/src/test/resources/software/amazon/awssdk/codegen/poet/rules/endpoint-resolve-interceptor.java @@ -240,8 +240,10 @@ private static Optional hostPrefix(String operationName, SdkRequest requ private static String resolveAndRecordAccountIdFromIdentity(ExecutionAttributes executionAttributes) { String accountId = accountIdFromIdentity(executionAttributes .getAttribute(SdkInternalExecutionAttribute.SELECTED_AUTH_SCHEME)); - executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( - BusinessMetricFeatureId.RESOLVED_ACCOUNT_ID.value()); + if (accountId != null) { + executionAttributes.getAttribute(SdkInternalExecutionAttribute.BUSINESS_METRICS).addMetric( + BusinessMetricFeatureId.RESOLVED_ACCOUNT_ID.value()); + } return accountId; } diff --git a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/BusinessMetricsUserAgentTest.java b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/BusinessMetricsUserAgentTest.java index 9bbb0f2eb602..204c0e389ed0 100644 --- a/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/BusinessMetricsUserAgentTest.java +++ b/test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/BusinessMetricsUserAgentTest.java @@ -21,6 +21,7 @@ import java.net.URI; import java.util.Arrays; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -63,6 +64,12 @@ class BusinessMetricsUserAgentTest { private static final String USER_AGENT_HEADER_NAME = "User-Agent"; private static final StaticCredentialsProvider CREDENTIALS_PROVIDER = StaticCredentialsProvider.create(AwsBasicCredentials.create("akid", "skid")); + private static final StaticCredentialsProvider CREDENTIALS_PROVIDER_WITH_ACCOUNTID = + StaticCredentialsProvider.create( + AwsBasicCredentials.builder() + .accessKeyId("akid").secretAccessKey("skid") + .accountId("012345678901") + .build()); @BeforeEach public void setup() { @@ -76,10 +83,10 @@ public void cleanup() { private static Stream inputValues() { return Stream.of( - Arguments.of("Default values", null, Arrays.asList("D", "N", "P", "T")), - Arguments.of("Account ID preferred mode ", AccountIdEndpointMode.PREFERRED, Arrays.asList("P", "T")), - Arguments.of("Account ID disabled mode ", AccountIdEndpointMode.DISABLED, Arrays.asList("Q", "T")), - Arguments.of("Account ID required mode ", AccountIdEndpointMode.REQUIRED, Arrays.asList("R", "T")) + Arguments.of("Default values", null, Arrays.asList("D", "N", "P")), + Arguments.of("Account ID preferred mode ", AccountIdEndpointMode.PREFERRED, Collections.singletonList("P")), + Arguments.of("Account ID disabled mode ", AccountIdEndpointMode.DISABLED, Collections.singletonList("Q")), + Arguments.of("Account ID required mode ", AccountIdEndpointMode.REQUIRED, Collections.singletonList("R")) ); } @@ -101,6 +108,28 @@ void validate_metricsString_forDifferentConfigValues(String description, expectedMetrics.forEach(expectedMetric -> assertThat(userAgent).matches(METRIC_SEARCH_PATTERN.apply(expectedMetric))); } + @Test + void when_accountIdNotResolved_noMetricIsAdded() { + RestJsonEndpointProvidersAsyncClientBuilder clientBuilder = asyncClientBuilderForEndpointProvider(); + clientBuilder.credentialsProvider(CREDENTIALS_PROVIDER); + + assertThatThrownBy(() -> clientBuilder.build().operationWithNoInputOrOutput(r -> {}).join()).hasMessageContaining("stop"); + + String userAgent = assertAndGetUserAgentString(); + assertThat(userAgent).doesNotMatch(METRIC_SEARCH_PATTERN.apply("T")); + } + + @Test + void when_accountIdResolved_correctMetricIsAdded() { + RestJsonEndpointProvidersAsyncClientBuilder clientBuilder = asyncClientBuilderForEndpointProvider(); + clientBuilder.credentialsProvider(CREDENTIALS_PROVIDER_WITH_ACCOUNTID); + + assertThatThrownBy(() -> clientBuilder.build().operationWithNoInputOrOutput(r -> {}).join()).hasMessageContaining("stop"); + + String userAgent = assertAndGetUserAgentString(); + assertThat(userAgent).matches(METRIC_SEARCH_PATTERN.apply("T")); + } + @Test void when_waiterIsUsed_correctMetricIsAdded() throws ExecutionException, InterruptedException { RestJsonWithWaitersAsyncClient asyncClient =