From 3952ee665d97471535280e413e7219535365ee4a Mon Sep 17 00:00:00 2001 From: kai lin Date: Fri, 20 Feb 2026 14:21:45 -0500 Subject: [PATCH 1/3] added UA to paginator codegen --- .../include/aws/s3/S3PaginationBase.h | 5 + .../include/aws/core/client/UserAgent.h | 3 +- .../source/client/UserAgent.cpp | 3 +- .../aws-cpp-sdk-s3-unit-tests/CMakeLists.txt | 4 +- .../S3PaginatorUserAgentTest.cpp | 95 +++++++++++++++++++ .../pagination/PaginationBaseGenerator.java | 4 +- 6 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp diff --git a/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3PaginationBase.h b/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3PaginationBase.h index 217b69def306..893bc1436a37 100644 --- a/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3PaginationBase.h +++ b/generated/src/aws-cpp-sdk-s3/include/aws/s3/S3PaginationBase.h @@ -5,6 +5,7 @@ #pragma once +#include #include #include #include @@ -26,6 +27,7 @@ class S3PaginationBase { */ Aws::Utils::Pagination::Paginator> ListBucketsPaginator(const Model::ListBucketsRequest& request) { + request.AddUserAgentFeature(Aws::Client::UserAgentFeature::PAGINATOR); return Aws::Utils::Pagination::Paginator>{static_cast(this), request}; @@ -37,6 +39,7 @@ class S3PaginationBase { Aws::Utils::Pagination::Paginator> ListDirectoryBucketsPaginator(const Model::ListDirectoryBucketsRequest& request) { + request.AddUserAgentFeature(Aws::Client::UserAgentFeature::PAGINATOR); return Aws::Utils::Pagination::Paginator>{ static_cast(this), request}; @@ -47,6 +50,7 @@ class S3PaginationBase { */ Aws::Utils::Pagination::Paginator> ListObjectsV2Paginator(const Model::ListObjectsV2Request& request) { + request.AddUserAgentFeature(Aws::Client::UserAgentFeature::PAGINATOR); return Aws::Utils::Pagination::Paginator>{static_cast(this), request}; @@ -57,6 +61,7 @@ class S3PaginationBase { */ Aws::Utils::Pagination::Paginator> ListPartsPaginator(const Model::ListPartsRequest& request) { + request.AddUserAgentFeature(Aws::Client::UserAgentFeature::PAGINATOR); return Aws::Utils::Pagination::Paginator>{ static_cast(this), request}; } diff --git a/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h b/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h index 63227053c69f..fa0e50ce0650 100644 --- a/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h +++ b/src/aws-cpp-sdk-core/include/aws/core/client/UserAgent.h @@ -48,7 +48,8 @@ enum class UserAgentFeature { FLEXIBLE_CHECKSUMS_REQ_SHA512, FLEXIBLE_CHECKSUMS_REQ_XXHASH64, FLEXIBLE_CHECKSUMS_REQ_XXHASH3, - FLEXIBLE_CHECKSUMS_REQ_XXHASH128 + FLEXIBLE_CHECKSUMS_REQ_XXHASH128, + PAGINATOR }; class AWS_CORE_API UserAgent { diff --git a/src/aws-cpp-sdk-core/source/client/UserAgent.cpp b/src/aws-cpp-sdk-core/source/client/UserAgent.cpp index b764223d960e..f0fb66789513 100644 --- a/src/aws-cpp-sdk-core/source/client/UserAgent.cpp +++ b/src/aws-cpp-sdk-core/source/client/UserAgent.cpp @@ -58,7 +58,8 @@ const std::pair BUSINESS_METRIC_MAPPING[] = { {UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_SHA512, "AE"}, {UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_XXHASH64, "AG"}, {UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_XXHASH3, "AF"}, - {UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_XXHASH128, "AH"} + {UserAgentFeature::FLEXIBLE_CHECKSUMS_REQ_XXHASH128, "AH"}, + {UserAgentFeature::PAGINATOR, "C"}, }; const std::pair RETRY_FEATURE_MAPPING[] = { diff --git a/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt b/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt index aeda486596ca..0a7750ea378f 100644 --- a/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt +++ b/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt @@ -14,9 +14,9 @@ endif() enable_testing() if(PLATFORM_ANDROID AND BUILD_SHARED_LIBS) - add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp) + add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/S3PaginatorUserAgentTest.cpp) else() - add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp) + add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/S3PaginatorUserAgentTest.cpp) endif() set_compiler_flags(${PROJECT_NAME}) diff --git a/tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp b/tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp new file mode 100644 index 000000000000..787ecc444eb0 --- /dev/null +++ b/tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp @@ -0,0 +1,95 @@ +/** + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Aws; +using namespace Aws::Http; +using namespace Aws::S3; + +static const char* TAG = "S3PaginatorUserAgentTest"; + +class S3PaginatorUserAgentTest : public Aws::Testing::AwsCppSdkGTestSuite { +protected: + std::shared_ptr mockHttpClient; + std::shared_ptr mockHttpClientFactory; + std::shared_ptr s3Client; + + void SetUp() override { + mockHttpClient = Aws::MakeShared(TAG); + mockHttpClientFactory = Aws::MakeShared(TAG); + mockHttpClientFactory->SetClient(mockHttpClient); + SetHttpClientFactory(mockHttpClientFactory); + + Aws::Client::ClientConfiguration config; + config.region = Aws::Region::US_EAST_1; + s3Client = Aws::MakeShared(TAG, + Aws::Auth::AWSCredentials("test-key", "test-secret"), + nullptr, config); + } + + void TearDown() override { + s3Client = nullptr; + mockHttpClient->Reset(); + mockHttpClient = nullptr; + mockHttpClientFactory = nullptr; + Aws::Http::CleanupHttp(); + Aws::Http::InitHttp(); + } + + void AddMockListObjectsV2Response() { + auto requestTmp = CreateHttpRequest(URI("dummy"), HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + auto response = Aws::MakeShared(TAG, requestTmp); + response->SetResponseCode(HttpResponseCode::OK); + response->GetResponseBody() << + "" + "" + "test-bucket0" + "1000false" + ""; + mockHttpClient->AddResponseToReturn(response); + } +}; + +TEST_F(S3PaginatorUserAgentTest, TestPaginatorAddsUserAgentFeature) { + AddMockListObjectsV2Response(); + + Model::ListObjectsV2Request request; + request.SetBucket("test-bucket"); + + auto paginator = s3Client->ListObjectsV2Paginator(request); + for (const auto& outcome : paginator) { + AWS_ASSERT_SUCCESS(outcome); + } + + auto lastRequest = mockHttpClient->GetMostRecentHttpRequest(); + EXPECT_TRUE(lastRequest.HasHeader(Aws::Http::USER_AGENT_HEADER)); + const auto& userAgent = lastRequest.GetHeaderValue(Aws::Http::USER_AGENT_HEADER); + EXPECT_FALSE(userAgent.empty()); + + const auto userAgentParsed = Aws::Utils::StringUtils::Split(userAgent, ' '); + + // Verify there's only one m/ section (no duplicate m/ sections) + int mSectionCount = 0; + for (const auto& part : userAgentParsed) { + if (part.find("m/") != Aws::String::npos) { + mSectionCount++; + } + } + EXPECT_EQ(1, mSectionCount); + + auto businessMetrics = std::find_if(userAgentParsed.begin(), userAgentParsed.end(), + [](const Aws::String& value) { return value.find("m/") != Aws::String::npos && value.find("C") != Aws::String::npos; }); + EXPECT_TRUE(businessMetrics != userAgentParsed.end()); +} diff --git a/tools/code-generation/smithy/cpp-codegen/smithy-cpp-codegen/src/main/java/com/amazonaws/util/awsclientsmithygenerator/generators/pagination/PaginationBaseGenerator.java b/tools/code-generation/smithy/cpp-codegen/smithy-cpp-codegen/src/main/java/com/amazonaws/util/awsclientsmithygenerator/generators/pagination/PaginationBaseGenerator.java index 2837e368b3e3..dd78fce61041 100644 --- a/tools/code-generation/smithy/cpp-codegen/smithy-cpp-codegen/src/main/java/com/amazonaws/util/awsclientsmithygenerator/generators/pagination/PaginationBaseGenerator.java +++ b/tools/code-generation/smithy/cpp-codegen/smithy-cpp-codegen/src/main/java/com/amazonaws/util/awsclientsmithygenerator/generators/pagination/PaginationBaseGenerator.java @@ -24,6 +24,7 @@ public PaginationBaseGenerator(ServiceShape service, List data : operations) { @@ -65,7 +66,8 @@ protected void writeSpecificContent(CppWriter writer, String serviceName) { .write(opName + "Paginator(const Model::" + methodName + "Request& request)"); writer.openBlock("{", "}", () -> { - writer.write("return Aws::Utils::Pagination::Paginator>{") + writer.write("request.AddUserAgentFeature(Aws::Client::UserAgentFeature::PAGINATOR);") + .write("return Aws::Utils::Pagination::Paginator>{") .write(" static_cast(this), request};"); }); } From 812ea024f5fc266d79d668d8a5eaaad843872951 Mon Sep 17 00:00:00 2001 From: kai lin Date: Fri, 20 Feb 2026 17:08:49 -0500 Subject: [PATCH 2/3] update unit test to track C metric --- .../aws-cpp-sdk-s3-unit-tests/CMakeLists.txt | 4 +- .../S3PaginatorUserAgentTest.cpp | 95 ------------------- .../aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp | 36 ++++++- 3 files changed, 37 insertions(+), 98 deletions(-) delete mode 100644 tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp diff --git a/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt b/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt index 0a7750ea378f..aeda486596ca 100644 --- a/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt +++ b/tests/aws-cpp-sdk-s3-unit-tests/CMakeLists.txt @@ -14,9 +14,9 @@ endif() enable_testing() if(PLATFORM_ANDROID AND BUILD_SHARED_LIBS) - add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/S3PaginatorUserAgentTest.cpp) + add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp) else() - add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp ${CMAKE_CURRENT_SOURCE_DIR}/S3PaginatorUserAgentTest.cpp) + add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/S3UnitTests.cpp) endif() set_compiler_flags(${PROJECT_NAME}) diff --git a/tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp b/tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp deleted file mode 100644 index 787ecc444eb0..000000000000 --- a/tests/aws-cpp-sdk-s3-unit-tests/S3PaginatorUserAgentTest.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace Aws; -using namespace Aws::Http; -using namespace Aws::S3; - -static const char* TAG = "S3PaginatorUserAgentTest"; - -class S3PaginatorUserAgentTest : public Aws::Testing::AwsCppSdkGTestSuite { -protected: - std::shared_ptr mockHttpClient; - std::shared_ptr mockHttpClientFactory; - std::shared_ptr s3Client; - - void SetUp() override { - mockHttpClient = Aws::MakeShared(TAG); - mockHttpClientFactory = Aws::MakeShared(TAG); - mockHttpClientFactory->SetClient(mockHttpClient); - SetHttpClientFactory(mockHttpClientFactory); - - Aws::Client::ClientConfiguration config; - config.region = Aws::Region::US_EAST_1; - s3Client = Aws::MakeShared(TAG, - Aws::Auth::AWSCredentials("test-key", "test-secret"), - nullptr, config); - } - - void TearDown() override { - s3Client = nullptr; - mockHttpClient->Reset(); - mockHttpClient = nullptr; - mockHttpClientFactory = nullptr; - Aws::Http::CleanupHttp(); - Aws::Http::InitHttp(); - } - - void AddMockListObjectsV2Response() { - auto requestTmp = CreateHttpRequest(URI("dummy"), HttpMethod::HTTP_GET, - Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); - auto response = Aws::MakeShared(TAG, requestTmp); - response->SetResponseCode(HttpResponseCode::OK); - response->GetResponseBody() << - "" - "" - "test-bucket0" - "1000false" - ""; - mockHttpClient->AddResponseToReturn(response); - } -}; - -TEST_F(S3PaginatorUserAgentTest, TestPaginatorAddsUserAgentFeature) { - AddMockListObjectsV2Response(); - - Model::ListObjectsV2Request request; - request.SetBucket("test-bucket"); - - auto paginator = s3Client->ListObjectsV2Paginator(request); - for (const auto& outcome : paginator) { - AWS_ASSERT_SUCCESS(outcome); - } - - auto lastRequest = mockHttpClient->GetMostRecentHttpRequest(); - EXPECT_TRUE(lastRequest.HasHeader(Aws::Http::USER_AGENT_HEADER)); - const auto& userAgent = lastRequest.GetHeaderValue(Aws::Http::USER_AGENT_HEADER); - EXPECT_FALSE(userAgent.empty()); - - const auto userAgentParsed = Aws::Utils::StringUtils::Split(userAgent, ' '); - - // Verify there's only one m/ section (no duplicate m/ sections) - int mSectionCount = 0; - for (const auto& part : userAgentParsed) { - if (part.find("m/") != Aws::String::npos) { - mSectionCount++; - } - } - EXPECT_EQ(1, mSectionCount); - - auto businessMetrics = std::find_if(userAgentParsed.begin(), userAgentParsed.end(), - [](const Aws::String& value) { return value.find("m/") != Aws::String::npos && value.find("C") != Aws::String::npos; }); - EXPECT_TRUE(businessMetrics != userAgentParsed.end()); -} diff --git a/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp b/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp index 057a12f995ac..77e19a4bda62 100644 --- a/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp +++ b/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp @@ -15,6 +15,7 @@ #include #include #include +#include using namespace Aws; using namespace Aws::Client; @@ -671,4 +672,37 @@ TEST_F(S3UnitTest, PartiallyConsumedStreamChecksumReuse) { EXPECT_TRUE(seenChecksum.IsSuccess()); const auto seenChecksumBase64 = base64.Encode(seenChecksum.GetResult()); EXPECT_EQ(seenChecksumBase64, expectedChecksumBase64); -} \ No newline at end of file +} + + +TEST_F(S3UnitTest, ListObjectsV2PaginatorShouldHaveCMetric) { + auto request = ListObjectsV2Request().WithBucket("test-bucket"); + + auto mockRequest = Aws::MakeShared(ALLOCATION_TAG, "test-bucket.s3.amazonaws.com/", HttpMethod::HTTP_GET); + mockRequest->SetResponseStreamFactory([]() -> IOStream* { + return Aws::New(ALLOCATION_TAG, "", std::ios_base::in | std::ios_base::binary); + }); + auto mockResponse = Aws::MakeShared(ALLOCATION_TAG, mockRequest); + mockResponse->SetResponseCode(HttpResponseCode::OK); + mockResponse->GetResponseBody() << + "" + "" + "test-bucket01000false" + ""; + _mockHttpClient->AddResponseToReturn(mockResponse); + + auto paginator = _s3Client->ListObjectsV2Paginator(request); + for (const auto& outcome : paginator) { + AWS_ASSERT_SUCCESS(outcome); + } + + const auto requestSeen = _mockHttpClient->GetMostRecentHttpRequest(); + EXPECT_TRUE(requestSeen.HasUserAgent()); + const auto& userAgent = requestSeen.GetUserAgent(); + EXPECT_FALSE(userAgent.empty()); + const auto userAgentParsed = Utils::StringUtils::Split(userAgent, ' '); + + auto businessMetrics = std::find_if(userAgentParsed.begin(), userAgentParsed.end(), + [](const Aws::String& value) { return value.find("m/") != Aws::String::npos && value.find("C") != Aws::String::npos; }); + EXPECT_TRUE(businessMetrics != userAgentParsed.end()); +} From c2b81f1b80596cd272ad96c328209bdf3788cf1e Mon Sep 17 00:00:00 2001 From: kai lin Date: Fri, 20 Feb 2026 17:09:54 -0500 Subject: [PATCH 3/3] white space change --- tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp b/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp index 77e19a4bda62..0194ccdeb8d0 100644 --- a/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp +++ b/tests/aws-cpp-sdk-s3-unit-tests/S3UnitTests.cpp @@ -674,7 +674,6 @@ TEST_F(S3UnitTest, PartiallyConsumedStreamChecksumReuse) { EXPECT_EQ(seenChecksumBase64, expectedChecksumBase64); } - TEST_F(S3UnitTest, ListObjectsV2PaginatorShouldHaveCMetric) { auto request = ListObjectsV2Request().WithBucket("test-bucket");