From 18b4c2beb853a70511ccfaece3bceb5a24384ced Mon Sep 17 00:00:00 2001 From: Scott Macdonald <57190223+scmacdon@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:26:52 -0400 Subject: [PATCH 1/2] Java V2 Update the Amazon DynamoDB Rest example to use Spring BOOT 3 (#6233) * updated POM to use Spring BOOT 3 --- .../creating_dynamodb_web_app/Readme.md | 19 +++++++++++-------- .../creating_dynamodb_web_app/pom.xml | 12 +----------- 2 files changed, 12 insertions(+), 19 deletions(-) diff --git a/javav2/usecases/creating_dynamodb_web_app/Readme.md b/javav2/usecases/creating_dynamodb_web_app/Readme.md index 1039356bd96..90189107773 100644 --- a/javav2/usecases/creating_dynamodb_web_app/Readme.md +++ b/javav2/usecases/creating_dynamodb_web_app/Readme.md @@ -2,11 +2,11 @@ ## Overview -| Heading | Description | -| ----------- | ----------- | -| Description | Discusses how to develop a Spring Boot application that queries Amazon DynamoDB data. The Spring Boot application uses the AWS SDK for Java (v2) to invoke AWS services and is used by a React application that displays the data. The React application uses Cloudscape. For information, see [Cloudscape](https://cloudscape.design/). | -| Audience | Developer (intermediate) | -| Required skills | Java, Maven, JavaScript | +| Heading | Description | +|------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Description | Discusses how to develop a Spring Boot 3.x application that queries Amazon DynamoDB data. The Spring Boot application uses the AWS SDK for Java (v2) to invoke AWS services and is used by a React application that displays the data. The React application uses Cloudscape. For information, see [Cloudscape](https://cloudscape.design/). | +| Audience | Developer (intermediate) | +| Required skills | Java, Maven, JavaScript | ## Purpose @@ -15,7 +15,9 @@ You can develop a dynamic web application that tracks and reports on work items + Amazon DynamoDB + Amazon Simple Email Service (Amazon SES). (The SDK for Java (v2) is used to access Amazon SES.) -The application you create is a decoupled React application that uses a Spring REST API to work with Amazon DynamoDB data. That is, the React application is a single-page application (SPA) that interacts with a Spring REST API by making RESTful GET and POST requests. The Spring REST API uses the Amazon DynamoDB Java API to perform CRUD operations on the Amazon DynamoDB database. Then, the Spring REST API returns JSON data in an HTTP response, as shown in the following illustration. +The application you create is a decoupled React application that uses a Spring REST API to work with Amazon DynamoDB data. +That is, the React application is a single-page application (SPA) that interacts with a Spring REST API by making RESTful GET and POST requests. +The Spring REST API uses the Amazon DynamoDB Java API to perform CRUD operations on the Amazon DynamoDB database. Then, the Spring REST API returns JSON data in an HTTP response, as shown in the following illustration. ![AWS Tracking Application](images/overview.png) @@ -42,7 +44,7 @@ see [Get started with the SDK for Java](https://docs.aws.amazon.com/sdk-for-java ### Important + The AWS services in this document are included in the [AWS Free Tier](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc). -+ This code has not been tested in all AWS Regions. Some AWS services are available only in specific Regions. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). ++ This code has not been tested in all AWS Regions. Some AWS services are available only in specific Regions. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + Running this code might result in charges to your AWS account. + Be sure to delete all of the resources that you create during this tutorial so that you won't be charged. @@ -132,7 +134,8 @@ Active items are queried from the database and used to dynamically create an Exc ## Add the POM dependencies to your project -Make sure that your project's pom.xml file looks like the POM file in this Github repository. +Make sure that your project's pom.xml file looks like the POM file in this Github repository. Notice that dependencies for +Spring Boot 3.x are included. ## Create the Java classes diff --git a/javav2/usecases/creating_dynamodb_web_app/pom.xml b/javav2/usecases/creating_dynamodb_web_app/pom.xml index c2436753ba4..ebf906a8432 100644 --- a/javav2/usecases/creating_dynamodb_web_app/pom.xml +++ b/javav2/usecases/creating_dynamodb_web_app/pom.xml @@ -9,7 +9,7 @@ org.springframework.boot spring-boot-starter-parent - 2.0.4.RELEASE + 3.0.6 @@ -36,11 +36,6 @@ 5.8.2 test - - mysql - mysql-connector-java - runtime - software.amazon.awssdk dynamodb @@ -94,11 +89,6 @@ jakarta.mail 1.6.5 - - mysql - mysql-connector-java - runtime - net.sourceforge.jexcelapi jxl From 3d2905fb916f436d925c39b392ec18ee02cf1ab5 Mon Sep 17 00:00:00 2001 From: Steven Meyer <108885656+meyertst-aws@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:26:57 -0400 Subject: [PATCH 2/2] Cpp: Weathertop - fix false negatives (#6234) Fixing tests --- .../4-DescribeDBClusterParameters.xml | 31 ++++--- .../5-DescribeDBClusterParameters.xml | 27 ++++-- .../9-DescribeDBClusterParameters.xml | 11 +++ .../autoscaling/tests/autoscaling_gtests.cpp | 1 - cpp/example_code/iam/tests/CMakeLists.txt | 1 + ...t_iam_create_user_assume_role_scenario.cpp | 50 +++++++++- cpp/example_code/iam/tests/iam_gtests.cpp | 85 +++++++++++++++++ cpp/example_code/iam/tests/iam_gtests.h | 24 ++++- .../iam/tests/mock_input/1-CreateUser.xml | 14 +++ .../iam/tests/mock_input/10-AssumeRole.xml | 17 ++++ .../tests/mock_input/11-AttachRolePolicy.xml | 5 + .../tests/mock_input/12-DetachRolePolicy.xml | 5 + .../iam/tests/mock_input/13-DeletePolicy.xml | 5 + .../iam/tests/mock_input/14-DeleteRole.xml | 5 + .../iam/tests/mock_input/15-DeleteUser.xml | 5 + .../iam/tests/mock_input/2-GetUser.xml | 15 +++ .../iam/tests/mock_input/3-CreateRole.xml | 15 +++ .../iam/tests/mock_input/4-CreatePolicy.xml | 19 ++++ .../iam/tests/mock_input/5-AssumeRole.xml | 8 ++ .../iam/tests/mock_input/ListBuckets.xml | 16 ++++ .../tests/mock_input/ListBucketsFailed.xml | 1 + cpp/example_code/iot/describe_thing.cpp | 1 - cpp/example_code/iot/list_topic_rules.cpp | 1 - cpp/example_code/mediaconvert/get_job.cpp | 2 +- .../medical-imaging/get_image_frame.cpp | 2 +- .../get_image_set_metadata.cpp | 2 +- cpp/example_code/s3/list_buckets.cpp | 1 - cpp/example_code/s3/tests/CMakeLists.txt | 1 + cpp/example_code/s3/tests/S3_GTests.cpp | 91 +++++++++++++++++++ cpp/example_code/s3/tests/S3_GTests.h | 19 ++++ .../s3/tests/gtest_delete_bucket_policy.cpp | 21 ++++- .../s3/tests/gtest_get_bucket_policy.cpp | 14 ++- .../s3/tests/gtest_put_bucket_policy.cpp | 28 +++++- .../tests/mock_input/DeleteBucketPolicy.xml | 4 + .../s3/tests/mock_input/GetBucketPolicy.json | 14 +++ .../s3/tests/mock_input/PutBucketPolicy.xml | 4 + .../ses/verify_email_identity.cpp | 2 +- cpp/example_code/sns/subscribe_lambda.cpp | 2 +- cpp/example_code/sts/tests/CMakeLists.txt | 1 + .../sts/tests/gtest_assume_role.cpp | 27 +++++- .../sts/tests/mock_input/AssumeRole.xml | 17 ++++ cpp/example_code/sts/tests/sts_gtests.cpp | 86 ++++++++++++++++++ cpp/example_code/sts/tests/sts_gtests.h | 25 ++++- .../transcribe/get_transcript.cpp | 2 +- .../transfer-manager/transferOnStream.cpp | 1 - 45 files changed, 680 insertions(+), 48 deletions(-) create mode 100644 cpp/example_code/iam/tests/mock_input/1-CreateUser.xml create mode 100644 cpp/example_code/iam/tests/mock_input/10-AssumeRole.xml create mode 100644 cpp/example_code/iam/tests/mock_input/11-AttachRolePolicy.xml create mode 100644 cpp/example_code/iam/tests/mock_input/12-DetachRolePolicy.xml create mode 100644 cpp/example_code/iam/tests/mock_input/13-DeletePolicy.xml create mode 100644 cpp/example_code/iam/tests/mock_input/14-DeleteRole.xml create mode 100644 cpp/example_code/iam/tests/mock_input/15-DeleteUser.xml create mode 100644 cpp/example_code/iam/tests/mock_input/2-GetUser.xml create mode 100644 cpp/example_code/iam/tests/mock_input/3-CreateRole.xml create mode 100644 cpp/example_code/iam/tests/mock_input/4-CreatePolicy.xml create mode 100644 cpp/example_code/iam/tests/mock_input/5-AssumeRole.xml create mode 100644 cpp/example_code/iam/tests/mock_input/ListBuckets.xml create mode 100644 cpp/example_code/iam/tests/mock_input/ListBucketsFailed.xml create mode 100644 cpp/example_code/s3/tests/mock_input/DeleteBucketPolicy.xml create mode 100644 cpp/example_code/s3/tests/mock_input/GetBucketPolicy.json create mode 100644 cpp/example_code/s3/tests/mock_input/PutBucketPolicy.xml create mode 100644 cpp/example_code/sts/tests/mock_input/AssumeRole.xml diff --git a/cpp/example_code/aurora/tests/mock_input/4-DescribeDBClusterParameters.xml b/cpp/example_code/aurora/tests/mock_input/4-DescribeDBClusterParameters.xml index 37c9349f603..a4f5c0f48dd 100644 --- a/cpp/example_code/aurora/tests/mock_input/4-DescribeDBClusterParameters.xml +++ b/cpp/example_code/aurora/tests/mock_input/4-DescribeDBClusterParameters.xml @@ -3,19 +3,26 @@ aW5ub2RiX2NoZWNrc3Vtcw== - 0,1 - static - boolean - Controls whether user-defined functions that have only an xxx symbol for the main function - can be loaded - + 1-65535 + dynamic + integer + Description text pending-reboot - engine-default - allow-suspicious-udfs - false - - provisioned - + user + auto_increment_increment + true + 3 + + + 1-65535 + dynamic + integer + Description text + pending-reboot + user + auto_decrement_decrement + true + 3 diff --git a/cpp/example_code/aurora/tests/mock_input/5-DescribeDBClusterParameters.xml b/cpp/example_code/aurora/tests/mock_input/5-DescribeDBClusterParameters.xml index 0a12898d89d..19ee9d4d423 100644 --- a/cpp/example_code/aurora/tests/mock_input/5-DescribeDBClusterParameters.xml +++ b/cpp/example_code/aurora/tests/mock_input/5-DescribeDBClusterParameters.xml @@ -2,19 +2,26 @@ - 0,1 + 1-65535 dynamic - boolean - Enables per-index compression-related statistics in the - INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX table. - + integer + Description text pending-reboot - engine-default - innodb_cmp_per_index_enabled + user + auto_increment_increment true - - provisioned - + 3 + + + 1-65535 + dynamic + integer + Description text + pending-reboot + user + auto_decrement_decrement + true + 3 diff --git a/cpp/example_code/aurora/tests/mock_input/9-DescribeDBClusterParameters.xml b/cpp/example_code/aurora/tests/mock_input/9-DescribeDBClusterParameters.xml index c15b23b1d91..e903780db47 100644 --- a/cpp/example_code/aurora/tests/mock_input/9-DescribeDBClusterParameters.xml +++ b/cpp/example_code/aurora/tests/mock_input/9-DescribeDBClusterParameters.xml @@ -12,6 +12,17 @@ true 3 + + 1-65535 + dynamic + integer + Description text + pending-reboot + user + auto_decrement_decrement + true + 3 + diff --git a/cpp/example_code/autoscaling/tests/autoscaling_gtests.cpp b/cpp/example_code/autoscaling/tests/autoscaling_gtests.cpp index 2c04d7f003b..5dd07a7dd3b 100644 --- a/cpp/example_code/autoscaling/tests/autoscaling_gtests.cpp +++ b/cpp/example_code/autoscaling/tests/autoscaling_gtests.cpp @@ -59,7 +59,6 @@ class CustomMockHTTPClient : public MockHttpClient { }; void AwsDocTest::AutoScaling_GTests::SetUpTestSuite() { - s_options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; InitAPI(s_options); // s_clientConfig must be a pointer because the client config must be initialized diff --git a/cpp/example_code/iam/tests/CMakeLists.txt b/cpp/example_code/iam/tests/CMakeLists.txt index fcd57ec0313..31467d9a845 100644 --- a/cpp/example_code/iam/tests/CMakeLists.txt +++ b/cpp/example_code/iam/tests/CMakeLists.txt @@ -119,6 +119,7 @@ target_compile_definitions( ${CURRENT_TARGET} PUBLIC TESTING_BUILD + SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries( diff --git a/cpp/example_code/iam/tests/gtest_iam_create_user_assume_role_scenario.cpp b/cpp/example_code/iam/tests/gtest_iam_create_user_assume_role_scenario.cpp index a1986366720..19420b5f5b6 100644 --- a/cpp/example_code/iam/tests/gtest_iam_create_user_assume_role_scenario.cpp +++ b/cpp/example_code/iam/tests/gtest_iam_create_user_assume_role_scenario.cpp @@ -15,10 +15,58 @@ namespace AwsDocTest { + // This test requires a user. It fails when running in an EC2 instance that assumes a role. + // Add the 'U' indicating it only runs in a user environment. // NOLINTNEXTLINE(readability-named-parameter) - TEST_F(IAM_GTests, create_user_assume_role_scenario_2_) { + TEST_F(IAM_GTests, create_user_assume_role_scenario_2U_) { auto result = AwsDoc::IAM::iamCreateUserAssumeRoleScenario(*s_clientConfig); EXPECT_TRUE(result); } + + // NOLINTNEXTLINE(readability-named-parameter) + TEST_F(IAM_GTests, create_user_assume_role_scenario_3_) { + MockHTTP mockHttp; + bool result = mockHttp.addResponseWithBody("mock_input/1-CreateUser.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/2-GetUser.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/3-CreateRole.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/4-CreatePolicy.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/5-AssumeRole.xml", Aws::Http::HttpResponseCode::FORBIDDEN); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/10-AssumeRole.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/ListBucketsFailed.xml", Aws::Http::HttpResponseCode::FORBIDDEN); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/11-AttachRolePolicy.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/ListBuckets.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/12-DetachRolePolicy.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/13-DeletePolicy.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/14-DeleteRole.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = mockHttp.addResponseWithBody("mock_input/15-DeleteUser.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = AwsDoc::IAM::iamCreateUserAssumeRoleScenario(*s_clientConfig); + EXPECT_TRUE(result); + } } // namespace AwsDocTest \ No newline at end of file diff --git a/cpp/example_code/iam/tests/iam_gtests.cpp b/cpp/example_code/iam/tests/iam_gtests.cpp index 95f04e8e619..7cf4f42a153 100644 --- a/cpp/example_code/iam/tests/iam_gtests.cpp +++ b/cpp/example_code/iam/tests/iam_gtests.cpp @@ -19,6 +19,7 @@ #include #include #include +#include Aws::SDKOptions AwsDocTest::IAM_GTests::s_options; std::unique_ptr AwsDocTest::IAM_GTests::s_clientConfig; @@ -26,6 +27,54 @@ Aws::String AwsDocTest::IAM_GTests::s_accessKey; Aws::String AwsDocTest::IAM_GTests::s_role; Aws::String AwsDocTest::IAM_GTests::s_userName; Aws::String AwsDocTest::IAM_GTests::s_policyArn; +static const char ALLOCATION_TAG[] = "IAM_GTEST"; + +/* + * Subclass MockHTTPCLient to respond to credential requests. + * Otherwise, the stored responses are returned for credential requests + * and not the service API calls. + */ +class CustomMockHTTPClient : public MockHttpClient { +public: + explicit CustomMockHTTPClient( + const std::shared_ptr &requestTmp) { + std::shared_ptr goodResponse = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + goodResponse->AddHeader("Content-Type", "text/json"); + goodResponse->SetResponseCode(Aws::Http::HttpResponseCode::OK); + Aws::Utils::DateTime expiration = + Aws::Utils::DateTime::Now() + std::chrono::milliseconds(60000); + + goodResponse->GetResponseBody() << "{" + << R"("RoleArn":"arn:aws:iam::123456789012:role/MockRole",)" + << R"("AccessKeyId":"ABCDEFGHIJK",)" + << R"("SecretAccessKey":"ABCDEFGHIJK",)" + << R"(Token":"ABCDEFGHIJK==","Expiration":")" << expiration.ToGmtString(Aws::Utils::DateFormat::ISO_8601) << "\"" + << "}"; + this->AddResponseToReturn(goodResponse); + + mCredentialsResponse = MockHttpClient::MakeRequest(requestTmp); + } + + std::shared_ptr + MakeRequest(const std::shared_ptr &request, + Aws::Utils::RateLimits::RateLimiterInterface *readLimiter, + Aws::Utils::RateLimits::RateLimiterInterface *writeLimiter) const override { + + // Do not use stored responses for a credentials request. + if (request->GetURIString().find("/credentials/") != std::string::npos) { + std::cout << "CustomMockHTTPClient returning credentials request." + << std::endl; + return mCredentialsResponse; + } + else { + return MockHttpClient::MakeRequest(request, readLimiter, writeLimiter);; + } + } + +private: + std::shared_ptr mCredentialsResponse; +}; void AwsDocTest::IAM_GTests::SetUpTestSuite() { InitAPI(s_options); @@ -380,5 +429,41 @@ bool AwsDocTest::IAM_GTests::suppressStdOut() { return std::getenv("EXAMPLE_TESTS_LOG_ON") == nullptr; } +AwsDocTest::MockHTTP::MockHTTP() { + requestTmp = CreateHttpRequest(Aws::Http::URI("https://test.com/"), + Aws::Http::HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + mockHttpClient = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + mockHttpClientFactory = Aws::MakeShared(ALLOCATION_TAG); + mockHttpClientFactory->SetClient(mockHttpClient); + SetHttpClientFactory(mockHttpClientFactory); +} +AwsDocTest::MockHTTP::~MockHTTP() { + Aws::Http::CleanupHttp(); + Aws::Http::InitHttp(); +} + +bool AwsDocTest::MockHTTP::addResponseWithBody(const std::string &fileName, + Aws::Http::HttpResponseCode httpResponseCode) { + std::string filePath = std::string(SRC_DIR) + "/" + fileName; + + std::ifstream inStream(filePath); + if (inStream) { + std::shared_ptr goodResponse = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + goodResponse->AddHeader("Content-Type", "text/json"); + goodResponse->SetResponseCode(httpResponseCode); + goodResponse->GetResponseBody() << inStream.rdbuf(); + mockHttpClient->AddResponseToReturn(goodResponse); + + return true; + } + + std::cerr << "MockHTTP::addResponseWithBody open file error '" << filePath << "'." + << std::endl; + + return false; +} diff --git a/cpp/example_code/iam/tests/iam_gtests.h b/cpp/example_code/iam/tests/iam_gtests.h index 8914ec7a5b7..6ca15c3fd3f 100644 --- a/cpp/example_code/iam/tests/iam_gtests.h +++ b/cpp/example_code/iam/tests/iam_gtests.h @@ -2,12 +2,13 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#ifndef S3_EXAMPLES_S3_GTESTS_H -#define S3_EXAMPLES_S3_GTESTS_H +#ifndef IAM_EXAMPLES_IAM_GTESTS_H +#define IAM_EXAMPLES_IAM_GTESTS_H #include #include #include +#include namespace AwsDocTest { @@ -88,6 +89,23 @@ namespace AwsDocTest { static Aws::String s_userName; static Aws::String s_policyArn; }; + + class MockHTTP { + public: + MockHTTP(); + + virtual ~MockHTTP(); + + bool addResponseWithBody(const std::string &fileName, + Aws::Http::HttpResponseCode httpResponseCode = Aws::Http::HttpResponseCode::OK); + + private: + + std::shared_ptr mockHttpClient; + std::shared_ptr mockHttpClientFactory; + std::shared_ptr requestTmp; + }; // MockHTTP + } // AwsDocTest -#endif //S3_EXAMPLES_S3_GTESTS_H +#endif //IAM_EXAMPLES_IAM_GTESTS_H diff --git a/cpp/example_code/iam/tests/mock_input/1-CreateUser.xml b/cpp/example_code/iam/tests/mock_input/1-CreateUser.xml new file mode 100644 index 00000000000..3904b15f8d5 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/1-CreateUser.xml @@ -0,0 +1,14 @@ + + + / + iam-demo-user + arn:aws:iam::1111111222222:user/iam-demo-user + AIDARZQKN6ARC25I5FZPP + 2024-03-11T14:18:54Z + + + + 4c7cd91f-dace-4832-b892-cdfdf1f7c861 + + + diff --git a/cpp/example_code/iam/tests/mock_input/10-AssumeRole.xml b/cpp/example_code/iam/tests/mock_input/10-AssumeRole.xml new file mode 100644 index 00000000000..7266c326bee --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/10-AssumeRole.xml @@ -0,0 +1,17 @@ + + + AROARZQKN6ARBA3MU7HQ4:iam-demo-role-session-facb92a0-a797-44e1-8430-c79a5b067201 + arn:aws:sts::1111111222222:assumed-role/iam-demo-role/iam-demo-role-session-facb92a0-a797-44e1-8430-c79a5b067201 + + + AAABBBBBBBBB + AAABBBBBBBBB + AAABBBBBBBBB+USs + 2040-03-11T15:19:02Z + + + + d52b113b-597f-41e6-99d6-ed6e53a915bf + + + diff --git a/cpp/example_code/iam/tests/mock_input/11-AttachRolePolicy.xml b/cpp/example_code/iam/tests/mock_input/11-AttachRolePolicy.xml new file mode 100644 index 00000000000..eca1ea1d1e1 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/11-AttachRolePolicy.xml @@ -0,0 +1,5 @@ + + 0c6e3333-33ae-4269-8338-979a8bd0346d + + + diff --git a/cpp/example_code/iam/tests/mock_input/12-DetachRolePolicy.xml b/cpp/example_code/iam/tests/mock_input/12-DetachRolePolicy.xml new file mode 100644 index 00000000000..42946b72f51 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/12-DetachRolePolicy.xml @@ -0,0 +1,5 @@ + + 61891e46-50ca-48d0-8b50-0d958d863fb4 + + + diff --git a/cpp/example_code/iam/tests/mock_input/13-DeletePolicy.xml b/cpp/example_code/iam/tests/mock_input/13-DeletePolicy.xml new file mode 100644 index 00000000000..eb8ebc7f52b --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/13-DeletePolicy.xml @@ -0,0 +1,5 @@ + + 37c90b6c-06de-4a4d-9b1c-f5cdc19e6ef1 + + + diff --git a/cpp/example_code/iam/tests/mock_input/14-DeleteRole.xml b/cpp/example_code/iam/tests/mock_input/14-DeleteRole.xml new file mode 100644 index 00000000000..168df714604 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/14-DeleteRole.xml @@ -0,0 +1,5 @@ + + 0843a35e-a598-44a1-9eb1-f1adda10b162 + + + diff --git a/cpp/example_code/iam/tests/mock_input/15-DeleteUser.xml b/cpp/example_code/iam/tests/mock_input/15-DeleteUser.xml new file mode 100644 index 00000000000..ab8f0760f33 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/15-DeleteUser.xml @@ -0,0 +1,5 @@ + + 545004dc-b93c-4174-8b7e-8abd11577996 + + + diff --git a/cpp/example_code/iam/tests/mock_input/2-GetUser.xml b/cpp/example_code/iam/tests/mock_input/2-GetUser.xml new file mode 100644 index 00000000000..db86a547dec --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/2-GetUser.xml @@ -0,0 +1,15 @@ + + + / + 2023-04-10T19:34:28Z + UnitTester + arn:aws:iam::1111111222222:user/UnitTester + AIDARZQKN6ARLXIC6YK7J + 2022-08-10T13:38:30Z + + + + 12edbe2c-76a6-416d-9470-4010556b1c59 + + + diff --git a/cpp/example_code/iam/tests/mock_input/3-CreateRole.xml b/cpp/example_code/iam/tests/mock_input/3-CreateRole.xml new file mode 100644 index 00000000000..9f460925948 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/3-CreateRole.xml @@ -0,0 +1,15 @@ + + + / + %7B%22Version%22%3A%222012-10-17%22%2C%22Statement%22%3A%5B%7B%22 + AROARZQKN6ARBA3MU7HQ4 + iam-demo-role + arn:aws:iam::1111111222222:role/iam-demo-role + 2024-03-11T14:18:55Z + + + + 2ebda984-7277-4aac-87bb-7f64853faaeb + + + diff --git a/cpp/example_code/iam/tests/mock_input/4-CreatePolicy.xml b/cpp/example_code/iam/tests/mock_input/4-CreatePolicy.xml new file mode 100644 index 00000000000..1aa49143b64 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/4-CreatePolicy.xml @@ -0,0 +1,19 @@ + + + 0 + / + 2024-03-11T14:18:55Z + v1 + ANPARZQKN6ARLSIG5ZFTU + true + iam-demo-policy + 0 + arn:aws:iam::1111111222222:policy/iam-demo-policy + 2024-03-11T14:18:55Z + + + + 20aa0584-03a3-4578-8729-a59e32d52160 + + + diff --git a/cpp/example_code/iam/tests/mock_input/5-AssumeRole.xml b/cpp/example_code/iam/tests/mock_input/5-AssumeRole.xml new file mode 100644 index 00000000000..e25770c794e --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/5-AssumeRole.xml @@ -0,0 +1,8 @@ + + Sender + AccessDenied + User: arn:aws:iam::1111111222222:user/UnitTester is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::1111111222222:role/iam-demo-role + + ba519513-71e5-4f0c-8aa9-1edd264cd084 + + diff --git a/cpp/example_code/iam/tests/mock_input/ListBuckets.xml b/cpp/example_code/iam/tests/mock_input/ListBuckets.xml new file mode 100644 index 00000000000..fb80d336235 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/ListBuckets.xml @@ -0,0 +1,16 @@ + + + + 2019-12-11T23:32:47+00:00 + DOC-EXAMPLE-BUCKET + + + 2019-11-10T23:32:13+00:00 + DOC-EXAMPLE-BUCKET2 + + + + Account+Name + AIDACKCEVSQ6C2EXAMPLE + + diff --git a/cpp/example_code/iam/tests/mock_input/ListBucketsFailed.xml b/cpp/example_code/iam/tests/mock_input/ListBucketsFailed.xml new file mode 100644 index 00000000000..90bb7868232 --- /dev/null +++ b/cpp/example_code/iam/tests/mock_input/ListBucketsFailed.xml @@ -0,0 +1 @@ +AccessDeniedAccess Denied87ZC5R1YAC541JGBW3lf80Mi3D0OoIsiP1zwu39CHW7gjm785cs9Gu2uVicrGGo/BWJaXanLT6Kil/sle0Tk7mHUVzY= \ No newline at end of file diff --git a/cpp/example_code/iot/describe_thing.cpp b/cpp/example_code/iot/describe_thing.cpp index 3603affd37a..54138a510ec 100644 --- a/cpp/example_code/iot/describe_thing.cpp +++ b/cpp/example_code/iot/describe_thing.cpp @@ -72,7 +72,6 @@ int main(int argc, char **argv) { return 1; } Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; Aws::InitAPI(options); { diff --git a/cpp/example_code/iot/list_topic_rules.cpp b/cpp/example_code/iot/list_topic_rules.cpp index a4dcb3c133c..3d82cf57f3e 100644 --- a/cpp/example_code/iot/list_topic_rules.cpp +++ b/cpp/example_code/iot/list_topic_rules.cpp @@ -78,7 +78,6 @@ bool AwsDoc::IoT::listTopicRules( int main(int argc, char **argv) { Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; Aws::InitAPI(options); { diff --git a/cpp/example_code/mediaconvert/get_job.cpp b/cpp/example_code/mediaconvert/get_job.cpp index a6b64d9f215..2aefa7a89ea 100644 --- a/cpp/example_code/mediaconvert/get_job.cpp +++ b/cpp/example_code/mediaconvert/get_job.cpp @@ -66,7 +66,7 @@ int main(int argc, char **argv) { )"; } Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; + Aws::InitAPI(options); { Aws::String jobID = argv[1]; diff --git a/cpp/example_code/medical-imaging/get_image_frame.cpp b/cpp/example_code/medical-imaging/get_image_frame.cpp index 5b71fb81e53..27a5e8bd09a 100644 --- a/cpp/example_code/medical-imaging/get_image_frame.cpp +++ b/cpp/example_code/medical-imaging/get_image_frame.cpp @@ -86,7 +86,7 @@ int main(int argc, char **argv) { return 1; } Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; + Aws::InitAPI(options); { Aws::String dataStoreID = argv[1]; diff --git a/cpp/example_code/medical-imaging/get_image_set_metadata.cpp b/cpp/example_code/medical-imaging/get_image_set_metadata.cpp index 4b4fb570476..d7501c4ad7a 100644 --- a/cpp/example_code/medical-imaging/get_image_set_metadata.cpp +++ b/cpp/example_code/medical-imaging/get_image_set_metadata.cpp @@ -80,7 +80,7 @@ int main(int argc, char **argv) { return 1; } Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; + Aws::InitAPI(options); { Aws::String dataStoreID = argv[1]; diff --git a/cpp/example_code/s3/list_buckets.cpp b/cpp/example_code/s3/list_buckets.cpp index 769fa44487d..1e93ae53b74 100644 --- a/cpp/example_code/s3/list_buckets.cpp +++ b/cpp/example_code/s3/list_buckets.cpp @@ -61,7 +61,6 @@ int main() { //An instance of Aws::SDKOptions is passed to the Aws::InitAPI and //Aws::ShutdownAPI methods. The same instance should be sent to both methods. Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; //The AWS SDK for C++ must be initialized by calling Aws::InitAPI. InitAPI(options); diff --git a/cpp/example_code/s3/tests/CMakeLists.txt b/cpp/example_code/s3/tests/CMakeLists.txt index 04a2ef4182f..2a6da6ed7fe 100644 --- a/cpp/example_code/s3/tests/CMakeLists.txt +++ b/cpp/example_code/s3/tests/CMakeLists.txt @@ -122,6 +122,7 @@ target_compile_definitions( ${CURRENT_TARGET} PUBLIC TESTING_BUILD + SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries( diff --git a/cpp/example_code/s3/tests/S3_GTests.cpp b/cpp/example_code/s3/tests/S3_GTests.cpp index ef1d528239b..dd31cecf145 100644 --- a/cpp/example_code/s3/tests/S3_GTests.cpp +++ b/cpp/example_code/s3/tests/S3_GTests.cpp @@ -20,6 +20,54 @@ std::vector AwsDocTest::S3_GTests::s_cachedS3Buckets; Aws::String AwsDocTest::S3_GTests::s_testFilePath; Aws::String AwsDocTest::S3_GTests::s_canonicalUserID; Aws::String AwsDocTest::S3_GTests::s_userArn; +static const char ALLOCATION_TAG[] = "S3_GTEST"; + +/* + * Subclass MockHTTPCLient to respond to credential requests. + * Otherwise, the stored responses are returned for credential requests + * and not the service API calls. + */ +class CustomMockHTTPClient : public MockHttpClient { +public: + explicit CustomMockHTTPClient( + const std::shared_ptr &requestTmp) { + std::shared_ptr goodResponse = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + goodResponse->AddHeader("Content-Type", "text/json"); + goodResponse->SetResponseCode(Aws::Http::HttpResponseCode::OK); + Aws::Utils::DateTime expiration = + Aws::Utils::DateTime::Now() + std::chrono::milliseconds(60000); + + goodResponse->GetResponseBody() << "{" + << R"("RoleArn":"arn:aws:iam::123456789012:role/MockRole",)" + << R"("AccessKeyId":"ABCDEFGHIJK",)" + << R"("SecretAccessKey":"ABCDEFGHIJK",)" + << R"(Token":"ABCDEFGHIJK==","Expiration":")" << expiration.ToGmtString(Aws::Utils::DateFormat::ISO_8601) << "\"" + << "}"; + this->AddResponseToReturn(goodResponse); + + mCredentialsResponse = MockHttpClient::MakeRequest(requestTmp); + } + + std::shared_ptr + MakeRequest(const std::shared_ptr &request, + Aws::Utils::RateLimits::RateLimiterInterface *readLimiter, + Aws::Utils::RateLimits::RateLimiterInterface *writeLimiter) const override { + + // Do not use stored responses for a credentials request. + if (request->GetURIString().find("/credentials/") != std::string::npos) { + std::cout << "CustomMockHTTPClient returning credentials request." + << std::endl; + return mCredentialsResponse; + } + else { + return MockHttpClient::MakeRequest(request, readLimiter, writeLimiter);; + } + } + +private: + std::shared_ptr mCredentialsResponse; +}; void AwsDocTest::S3_GTests::SetUpTestSuite() { InitAPI(s_options); @@ -345,9 +393,52 @@ void AwsDocTest::S3_GTests::TearDown() { } } + +Aws::String AwsDocTest::S3_GTests::preconditionError() { + return "Failed to meet precondition."; +} + bool AwsDocTest::S3_GTests::suppressStdOut() { return std::getenv("EXAMPLE_TESTS_LOG_ON") == nullptr; } +AwsDocTest::MockHTTP::MockHTTP() { + requestTmp = CreateHttpRequest(Aws::Http::URI("https://test.com/"), + Aws::Http::HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + mockHttpClient = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + mockHttpClientFactory = Aws::MakeShared(ALLOCATION_TAG); + mockHttpClientFactory->SetClient(mockHttpClient); + SetHttpClientFactory(mockHttpClientFactory); +} + +AwsDocTest::MockHTTP::~MockHTTP() { + Aws::Http::CleanupHttp(); + Aws::Http::InitHttp(); +} + +bool AwsDocTest::MockHTTP::addResponseWithBody(const std::string &fileName, + Aws::Http::HttpResponseCode httpResponseCode) { + std::string filePath = std::string(SRC_DIR) + "/" + fileName; + + std::ifstream inStream(filePath); + if (inStream) { + std::shared_ptr goodResponse = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + goodResponse->AddHeader("Content-Type", "text/json"); + goodResponse->SetResponseCode(httpResponseCode); + goodResponse->GetResponseBody() << inStream.rdbuf(); + mockHttpClient->AddResponseToReturn(goodResponse); + + return true; + } + + std::cerr << "MockHTTP::addResponseWithBody open file error '" << filePath << "'." + << std::endl; + + return false; +} + diff --git a/cpp/example_code/s3/tests/S3_GTests.h b/cpp/example_code/s3/tests/S3_GTests.h index d278ab2835d..727a494f82a 100644 --- a/cpp/example_code/s3/tests/S3_GTests.h +++ b/cpp/example_code/s3/tests/S3_GTests.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace AwsDocTest { @@ -49,6 +50,8 @@ namespace AwsDocTest { static Aws::String GetCanonicalUserID(); + static Aws::String preconditionError(); + // s_clientConfig must be a pointer because the client config must be initialized after InitAPI. static std::unique_ptr s_clientConfig; @@ -67,6 +70,22 @@ namespace AwsDocTest { std::stringbuf m_coutBuffer; // used just to silence cout. std::streambuf *m_savedBuffer = nullptr; }; + + class MockHTTP { + public: + MockHTTP(); + + virtual ~MockHTTP(); + + bool addResponseWithBody(const std::string &fileName, + Aws::Http::HttpResponseCode httpResponseCode = Aws::Http::HttpResponseCode::OK); + + private: + + std::shared_ptr mockHttpClient; + std::shared_ptr mockHttpClientFactory; + std::shared_ptr requestTmp; + }; // MockHTTP } // AwsDocTest #endif //S3_EXAMPLES_S3_GTESTS_H diff --git a/cpp/example_code/s3/tests/gtest_delete_bucket_policy.cpp b/cpp/example_code/s3/tests/gtest_delete_bucket_policy.cpp index c6b50ad2292..e422acdd424 100644 --- a/cpp/example_code/s3/tests/gtest_delete_bucket_policy.cpp +++ b/cpp/example_code/s3/tests/gtest_delete_bucket_policy.cpp @@ -18,16 +18,31 @@ static const int BUCKETS_NEEDED = 1; namespace AwsDocTest { + // This test requires a user. It fails when running in an EC2 instance that assumes a role. + // Add the 'U' indicating it only runs in a user environment. // NOLINTNEXTLINE(readability-named-parameter) - TEST_F(S3_GTests, delete_bucket_policy_2_) { + TEST_F(S3_GTests, delete_bucket_policy_2U_) { std::vector bucketNames = GetCachedS3Buckets(BUCKETS_NEEDED); ASSERT_GE(bucketNames.size(), BUCKETS_NEEDED) - << "Unable to create bucket as precondition for test" << std::endl; + << "Unable to create bucket as precondition for test" + << std::endl; bool result = AddPolicyToBucket(bucketNames[0]); - ASSERT_TRUE(result) << "Unable to add policy to bucket as precondition for test" << std::endl; + ASSERT_TRUE(result) << "Unable to add policy to bucket as precondition for test" + << std::endl; result = AwsDoc::S3::DeleteBucketPolicy(bucketNames[0], *s_clientConfig); ASSERT_TRUE(result); } + +// NOLINTNEXTLINE(readability-named-parameter) + TEST_F(S3_GTests, delete_bucket_policy_3_) { + MockHTTP mockHttp; + bool result = mockHttp.addResponseWithBody("mock_input/DeleteBucketPolicy.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = AwsDoc::S3::DeleteBucketPolicy("test_bucket", *s_clientConfig); + ASSERT_TRUE(result); + } + } // namespace AwsDocTest diff --git a/cpp/example_code/s3/tests/gtest_get_bucket_policy.cpp b/cpp/example_code/s3/tests/gtest_get_bucket_policy.cpp index 6aed44ec3e3..5ecf6fa8c37 100644 --- a/cpp/example_code/s3/tests/gtest_get_bucket_policy.cpp +++ b/cpp/example_code/s3/tests/gtest_get_bucket_policy.cpp @@ -17,8 +17,10 @@ static const int BUCKETS_NEEDED = 1; namespace AwsDocTest { + // This test requires a user. It fails when running in an EC2 instance that assumes a role. + // Add the 'U' indicating it only runs in a user environment. // NOLINTNEXTLINE(readability-named-parameter) - TEST_F(S3_GTests, get_bucket_policy_2_) { + TEST_F(S3_GTests, get_bucket_policy_2U_) { std::vector bucketNames = GetCachedS3Buckets(BUCKETS_NEEDED); ASSERT_GE(bucketNames.size(), BUCKETS_NEEDED) << "Unable to create bucket as precondition for test" << std::endl; @@ -29,4 +31,14 @@ namespace AwsDocTest { result = AwsDoc::S3::GetBucketPolicy(bucketNames[0], *s_clientConfig); ASSERT_TRUE(result); } + + // NOLINTNEXTLINE(readability-named-parameter) + TEST_F(S3_GTests, get_bucket_policy_3_) { + MockHTTP mockHttp; + bool result = mockHttp.addResponseWithBody("mock_input/GetBucketPolicy.json"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + result = AwsDoc::S3::GetBucketPolicy("test_bucket", *s_clientConfig); + ASSERT_TRUE(result); + } } // namespace AwsDocTest diff --git a/cpp/example_code/s3/tests/gtest_put_bucket_policy.cpp b/cpp/example_code/s3/tests/gtest_put_bucket_policy.cpp index ceeb3dbe19c..71e0a3e324a 100644 --- a/cpp/example_code/s3/tests/gtest_put_bucket_policy.cpp +++ b/cpp/example_code/s3/tests/gtest_put_bucket_policy.cpp @@ -17,8 +17,10 @@ static const int BUCKETS_NEEDED = 1; namespace AwsDocTest { + // This test requires a user. It fails when running in an EC2 instance that assumes a role. + // Add the 'U' indicating it only runs in a user environment. // NOLINTNEXTLINE(readability-named-parameter) - TEST_F(S3_GTests, put_bucket_policy_2_) { + TEST_F(S3_GTests, put_bucket_policy_2U_) { std::vector bucketNames = GetCachedS3Buckets(BUCKETS_NEEDED); ASSERT_GE(bucketNames.size(), BUCKETS_NEEDED) << "Unable to create bucket as precondition for test" << std::endl; @@ -29,4 +31,28 @@ namespace AwsDocTest { bool result = AwsDoc::S3::PutBucketPolicy(bucketNames[0], policyString, *s_clientConfig); ASSERT_TRUE(result); } + +// NOLINTNEXTLINE(readability-named-parameter) + TEST_F(S3_GTests, put_bucket_policy_3_) { + MockHTTP mockHttp; + bool result = mockHttp.addResponseWithBody("mock_input/DeleteBucketPolicy.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + Aws::String policyString = R"({ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "1", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::111111222222:user/UnitTester" + }, + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::doc-example-bucket/*" + } + ] +})"; + + result = AwsDoc::S3::PutBucketPolicy("doc-example-bucket", policyString, *s_clientConfig); + ASSERT_TRUE(result); + } } // namespace AwsDocTest diff --git a/cpp/example_code/s3/tests/mock_input/DeleteBucketPolicy.xml b/cpp/example_code/s3/tests/mock_input/DeleteBucketPolicy.xml new file mode 100644 index 00000000000..a1288b94dc5 --- /dev/null +++ b/cpp/example_code/s3/tests/mock_input/DeleteBucketPolicy.xml @@ -0,0 +1,4 @@ + +37c90b6c-06de-4a4d-9b1c-f5cdc19e6ef1 + + \ No newline at end of file diff --git a/cpp/example_code/s3/tests/mock_input/GetBucketPolicy.json b/cpp/example_code/s3/tests/mock_input/GetBucketPolicy.json new file mode 100644 index 00000000000..1b0d7b59c88 --- /dev/null +++ b/cpp/example_code/s3/tests/mock_input/GetBucketPolicy.json @@ -0,0 +1,14 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "1", + "Effect": "Allow", + "Principal": { + "AWS": "arn:aws:iam::111111222222:user/UnitTester" + }, + "Action": "s3:GetObject", + "Resource": "arn:aws:s3:::doc-example-bucket/*" + } + ] +} \ No newline at end of file diff --git a/cpp/example_code/s3/tests/mock_input/PutBucketPolicy.xml b/cpp/example_code/s3/tests/mock_input/PutBucketPolicy.xml new file mode 100644 index 00000000000..cadd2e868ca --- /dev/null +++ b/cpp/example_code/s3/tests/mock_input/PutBucketPolicy.xml @@ -0,0 +1,4 @@ + + 37c90b6c-06de-4a4d-9b1c-f5cdc19e6ef1 + + \ No newline at end of file diff --git a/cpp/example_code/ses/verify_email_identity.cpp b/cpp/example_code/ses/verify_email_identity.cpp index 79d678d8bf8..dbe75dcdff5 100644 --- a/cpp/example_code/ses/verify_email_identity.cpp +++ b/cpp/example_code/ses/verify_email_identity.cpp @@ -70,7 +70,7 @@ int main(int argc, char **argv) return 1; } Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; + Aws::InitAPI(options); { Aws::String emailAddress(argv[1]); diff --git a/cpp/example_code/sns/subscribe_lambda.cpp b/cpp/example_code/sns/subscribe_lambda.cpp index d8788718923..ac94e3c4617 100644 --- a/cpp/example_code/sns/subscribe_lambda.cpp +++ b/cpp/example_code/sns/subscribe_lambda.cpp @@ -74,7 +74,7 @@ int main(int argc, char **argv) { } Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug; + Aws::InitAPI(options); { Aws::String topicARN = argv[1]; diff --git a/cpp/example_code/sts/tests/CMakeLists.txt b/cpp/example_code/sts/tests/CMakeLists.txt index 3759a37cf34..b8e754d39e5 100644 --- a/cpp/example_code/sts/tests/CMakeLists.txt +++ b/cpp/example_code/sts/tests/CMakeLists.txt @@ -117,6 +117,7 @@ target_compile_definitions( ${CURRENT_TARGET} PUBLIC TESTING_BUILD + SRC_DIR="${CMAKE_CURRENT_SOURCE_DIR}" ) target_link_libraries( diff --git a/cpp/example_code/sts/tests/gtest_assume_role.cpp b/cpp/example_code/sts/tests/gtest_assume_role.cpp index bd2eee8cdf0..e104d9f2b5e 100644 --- a/cpp/example_code/sts/tests/gtest_assume_role.cpp +++ b/cpp/example_code/sts/tests/gtest_assume_role.cpp @@ -16,8 +16,10 @@ #include "sts_gtests.h" namespace AwsDocTest { + // This test requires a user. It fails when running in an EC2 instance that assumes a role. + // Add the 'U' indicating it only runs in a user environment. // NOLINTNEXTLINE(readability-named-parameter) - TEST_F(STS_GTests, assume_role_2_) { + TEST_F(STS_GTests, assume_role_2U_) { Aws::String roleArn = getRoleArn(); ASSERT_FALSE(roleArn.empty()) << preconditionError() << std::endl; @@ -31,12 +33,31 @@ namespace AwsDocTest { for (int i = 0; i < 20; ++i) { std::this_thread::sleep_for(std::chrono::seconds(1)); if (AwsDoc::STS::assumeRole(roleArn, roleSessionName, externalId, - credentials, *s_clientConfig)) + credentials, *s_clientConfig)) { result = true; break; } } ASSERT_TRUE(result); -} + } + + // NOLINTNEXTLINE(readability-named-parameter) + TEST_F(STS_GTests, assume_role_3_) { + MockHTTP mockHttp; + bool result = mockHttp.addResponseWithBody("mock_input/AssumeRole.xml"); + ASSERT_TRUE(result) << preconditionError() << std::endl; + + Aws::String roleSessionName = uuidName("role-session"); + roleSessionName.resize(std::min(static_cast(62), roleSessionName.length())); + Aws::String externalId = "012345"; // Optional, but recommended + + Aws::String roleArn = "arn:aws:sts::1111112222222:assumed-role/doc-example-tests-role/doc-example-tests-role-session"; + + Aws::Auth::AWSCredentials credentials; + + result = AwsDoc::STS::assumeRole(roleArn, roleSessionName, externalId, + credentials, *s_clientConfig); + ASSERT_TRUE(result); + } } // namespace AwsDocTest diff --git a/cpp/example_code/sts/tests/mock_input/AssumeRole.xml b/cpp/example_code/sts/tests/mock_input/AssumeRole.xml new file mode 100644 index 00000000000..57a4c510bea --- /dev/null +++ b/cpp/example_code/sts/tests/mock_input/AssumeRole.xml @@ -0,0 +1,17 @@ + + + + AAAAAAAAAAA:doc-example-tests-role-session- + arn:aws:sts::1111112222222:assumed-role/doc-example-tests-role/doc-example-tests-role-session + + + AAAAAAAAA + BBBBBBBBB/QF + IQ/CCCCCCCCCC/tQ== + 2040-03-11T20:26:49Z + + + + 8112f069-93fd-45ae-b9ae-4c9411539635 + + \ No newline at end of file diff --git a/cpp/example_code/sts/tests/sts_gtests.cpp b/cpp/example_code/sts/tests/sts_gtests.cpp index c31a505091e..f37a66e9622 100644 --- a/cpp/example_code/sts/tests/sts_gtests.cpp +++ b/cpp/example_code/sts/tests/sts_gtests.cpp @@ -13,6 +13,55 @@ Aws::SDKOptions AwsDocTest::STS_GTests::s_options; std::unique_ptr AwsDocTest::STS_GTests::s_clientConfig; Aws::IAM::Model::Role AwsDocTest::STS_GTests::s_role; Aws::String AwsDocTest::STS_GTests::s_userArn; +static const char ALLOCATION_TAG[] = "IAM_GTEST"; + +/* + * Subclass MockHTTPCLient to respond to credential requests. + * Otherwise, the stored responses are returned for credential requests + * and not the service API calls. + */ +class CustomMockHTTPClient : public MockHttpClient { +public: + explicit CustomMockHTTPClient( + const std::shared_ptr &requestTmp) { + std::shared_ptr goodResponse = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + goodResponse->AddHeader("Content-Type", "text/json"); + goodResponse->SetResponseCode(Aws::Http::HttpResponseCode::OK); + Aws::Utils::DateTime expiration = + Aws::Utils::DateTime::Now() + std::chrono::milliseconds(60000); + + goodResponse->GetResponseBody() << "{" + << R"("RoleArn":"arn:aws:iam::123456789012:role/MockRole",)" + << R"("AccessKeyId":"ABCDEFGHIJK",)" + << R"("SecretAccessKey":"ABCDEFGHIJK",)" + << R"(Token":"ABCDEFGHIJK==","Expiration":")" << expiration.ToGmtString(Aws::Utils::DateFormat::ISO_8601) << "\"" + << "}"; + this->AddResponseToReturn(goodResponse); + + mCredentialsResponse = MockHttpClient::MakeRequest(requestTmp); + } + + std::shared_ptr + MakeRequest(const std::shared_ptr &request, + Aws::Utils::RateLimits::RateLimiterInterface *readLimiter, + Aws::Utils::RateLimits::RateLimiterInterface *writeLimiter) const override { + + // Do not use stored responses for a credentials request. + if (request->GetURIString().find("/credentials/") != std::string::npos) { + std::cout << "CustomMockHTTPClient returning credentials request." + << std::endl; + return mCredentialsResponse; + } + else { + return MockHttpClient::MakeRequest(request, readLimiter, writeLimiter);; + } + } + +private: + std::shared_ptr mCredentialsResponse; +}; + void AwsDocTest::STS_GTests::SetUpTestSuite() { InitAPI(s_options); @@ -139,6 +188,43 @@ Aws::String AwsDocTest::STS_GTests::preconditionError() { bool AwsDocTest::STS_GTests::suppressStdOut() { return std::getenv("EXAMPLE_TESTS_LOG_ON") == nullptr; } +AwsDocTest::MockHTTP::MockHTTP() { + requestTmp = CreateHttpRequest(Aws::Http::URI("https://test.com/"), + Aws::Http::HttpMethod::HTTP_GET, + Aws::Utils::Stream::DefaultResponseStreamFactoryMethod); + mockHttpClient = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + mockHttpClientFactory = Aws::MakeShared(ALLOCATION_TAG); + mockHttpClientFactory->SetClient(mockHttpClient); + SetHttpClientFactory(mockHttpClientFactory); +} + +AwsDocTest::MockHTTP::~MockHTTP() { + Aws::Http::CleanupHttp(); + Aws::Http::InitHttp(); +} + +bool AwsDocTest::MockHTTP::addResponseWithBody(const std::string &fileName, + Aws::Http::HttpResponseCode httpResponseCode) { + std::string filePath = std::string(SRC_DIR) + "/" + fileName; + + std::ifstream inStream(filePath); + if (inStream) { + std::shared_ptr goodResponse = Aws::MakeShared( + ALLOCATION_TAG, requestTmp); + goodResponse->AddHeader("Content-Type", "text/json"); + goodResponse->SetResponseCode(httpResponseCode); + goodResponse->GetResponseBody() << inStream.rdbuf(); + mockHttpClient->AddResponseToReturn(goodResponse); + + return true; + } + + std::cerr << "MockHTTP::addResponseWithBody open file error '" << filePath << "'." + << std::endl; + + return false; +} diff --git a/cpp/example_code/sts/tests/sts_gtests.h b/cpp/example_code/sts/tests/sts_gtests.h index b0ddc7f0450..e8ac0ac1d6d 100644 --- a/cpp/example_code/sts/tests/sts_gtests.h +++ b/cpp/example_code/sts/tests/sts_gtests.h @@ -2,14 +2,15 @@ // SPDX-License-Identifier: Apache-2.0 #pragma once -#ifndef S3_EXAMPLES_S3_GTESTS_H -#define S3_EXAMPLES_S3_GTESTS_H +#ifndef STS_EXAMPLES_STS_GTESTS_H +#define STS_EXAMPLES_STS_GTESTS_H #include #include #include #include #include +#include namespace AwsDocTest { @@ -54,6 +55,24 @@ namespace AwsDocTest { static Aws::IAM::Model::Role s_role; static Aws::String s_userArn; }; + + + class MockHTTP { + public: + MockHTTP(); + + virtual ~MockHTTP(); + + bool addResponseWithBody(const std::string &fileName, + Aws::Http::HttpResponseCode httpResponseCode = Aws::Http::HttpResponseCode::OK); + + private: + + std::shared_ptr mockHttpClient; + std::shared_ptr mockHttpClientFactory; + std::shared_ptr requestTmp; + }; // MockHTTP + } // AwsDocTest -#endif //S3_EXAMPLES_S3_GTESTS_H +#endif //STS_EXAMPLES_STS_GTESTS_H diff --git a/cpp/example_code/transcribe/get_transcript.cpp b/cpp/example_code/transcribe/get_transcript.cpp index 40a2bc97ee6..609b26da380 100644 --- a/cpp/example_code/transcribe/get_transcript.cpp +++ b/cpp/example_code/transcribe/get_transcript.cpp @@ -28,7 +28,7 @@ static const int BUFFER_SIZE = CHUNK_LENGTH * SAMPLE_RATE / 1000 * 2; // snippet-start:[transcribe.cpp.stream_transcription_async.code] int main() { Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; + Aws::InitAPI(options); { //TODO(User): Set to the region of your AWS account. diff --git a/cpp/example_code/transfer-manager/transferOnStream.cpp b/cpp/example_code/transfer-manager/transferOnStream.cpp index ba2fe50b19f..124acd971d1 100644 --- a/cpp/example_code/transfer-manager/transferOnStream.cpp +++ b/cpp/example_code/transfer-manager/transferOnStream.cpp @@ -67,7 +67,6 @@ int main(int argc, char** argv) LOCAL_FILE_COPY += "_copy"; Aws::SDKOptions options; - options.loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Trace; //Turn on logging. Aws::InitAPI(options); {