1 /**
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0.
4 */
5
6 #include <aws/external/gtest.h>
7 #include <aws/testing/mocks/aws/client/MockAWSClient.h>
8 #include <aws/core/monitoring/CoreMetrics.h>
9 #include <aws/core/monitoring/MonitoringInterface.h>
10 #include <aws/core/monitoring/MonitoringFactory.h>
11 #include <aws/core/monitoring/MonitoringManager.h>
12 #include <aws/core/monitoring/DefaultMonitoring.h>
13
14 using namespace Aws::Client;
15 using namespace Aws::Http;
16 using namespace Aws::Http::Standard;
17 using namespace Aws::Monitoring;
18
19 static const char ALLOCATION_TAG[] = "MonitoringTest";
20 static const char URI_STRING[] = "http://domain.com/something";
21
22 static int MonitorOneAPICalledFlag = 0x0;
23 static int MonitorTwoAPICalledFlag = 0x0;
24
25 static const int MonitorAPIsNum = 5;
26 static std::vector<int> MonitorOneAPICalledCounter(MonitorAPIsNum);
27 static std::vector<int> MonitorTwoAPICalledCounter(MonitorAPIsNum);
28
29 class MockMonitoringOne : public MonitoringInterface
30 {
31 public:
OnRequestStarted(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request) const32 void* OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request) const override
33 {
34 EXPECT_STREQ(URI_STRING, request->GetURIString().c_str());
35 EXPECT_STREQ("MockAWSClient", serviceName.c_str());
36 EXPECT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
37 MonitorOneAPICalledFlag |= 0x1;
38 MonitorOneAPICalledCounter[0] ++;
39 return reinterpret_cast<void*>(1);
40 }
41
42
OnRequestSucceeded(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,const Aws::Client::HttpResponseOutcome & outcome,const CoreMetricsCollection & metricsFromCore,void * context) const43 void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request,
44 const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const override
45 {
46 ASSERT_TRUE(outcome.IsSuccess());
47 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
48 ASSERT_STREQ(URI_STRING, outcome.GetResult()->GetOriginatingRequest().GetURIString().c_str());
49 ASSERT_TRUE(metricsFromCore.httpClientMetrics.size() == 0);
50 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
51 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
52 ASSERT_EQ(1u, reinterpret_cast<size_t>(context));
53 MonitorOneAPICalledFlag |= 0x2;
54 MonitorOneAPICalledCounter[1] ++;
55 }
56
OnRequestFailed(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,const Aws::Client::HttpResponseOutcome & outcome,const CoreMetricsCollection & metricsFromCore,void * context) const57 void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request,
58 const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const override
59 {
60 ASSERT_FALSE(outcome.IsSuccess());
61 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
62 ASSERT_TRUE(metricsFromCore.httpClientMetrics.size() == 0);
63 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
64 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
65 ASSERT_EQ(1u, reinterpret_cast<size_t>(context));
66 MonitorOneAPICalledFlag |= 0x4;
67 MonitorOneAPICalledCounter[2] ++;
68 }
69
OnRequestRetry(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,void * context) const70 void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName,
71 const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const override
72 {
73 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
74 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
75 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
76 ASSERT_EQ(1u, reinterpret_cast<size_t>(context));
77 MonitorOneAPICalledFlag |= 0x8;
78 MonitorOneAPICalledCounter[3] ++;
79 }
80
OnFinish(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,void * context) const81 void OnFinish(const Aws::String& serviceName, const Aws::String& requestName,
82 const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const override
83 {
84 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
85 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
86 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
87 ASSERT_EQ(1u, reinterpret_cast<size_t>(context));
88 MonitorOneAPICalledFlag |= 0x10;
89 MonitorOneAPICalledCounter[4] ++;
90 }
91 };
92
93 class MockMonitoringFactoryOne : public MonitoringFactory
94 {
95 public:
CreateMonitoringInstance() const96 Aws::UniquePtr<MonitoringInterface> CreateMonitoringInstance() const override
97 {
98 return Aws::MakeUnique<MockMonitoringOne>(ALLOCATION_TAG);
99 }
100 };
101
CreateMonitoringFactoryOne()102 Aws::UniquePtr<MonitoringFactory> CreateMonitoringFactoryOne()
103 {
104 return Aws::MakeUnique<MockMonitoringFactoryOne>(ALLOCATION_TAG);
105 }
106
107 class MockMonitoringTwo : public MonitoringInterface
108 {
109 public:
OnRequestStarted(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request) const110 void* OnRequestStarted(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request) const override
111 {
112 EXPECT_STREQ("MockAWSClient", serviceName.c_str());
113 EXPECT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
114 EXPECT_STREQ(URI_STRING, request->GetURIString().c_str());
115 MonitorTwoAPICalledFlag |= 0x1;
116 MonitorTwoAPICalledCounter[0] ++;
117 return reinterpret_cast<void*>(2);
118 }
119
120
OnRequestSucceeded(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,const Aws::Client::HttpResponseOutcome & outcome,const CoreMetricsCollection & metricsFromCore,void * context) const121 void OnRequestSucceeded(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request,
122 const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const override
123 {
124 ASSERT_TRUE(outcome.IsSuccess());
125 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
126 ASSERT_STREQ(URI_STRING, outcome.GetResult()->GetOriginatingRequest().GetURIString().c_str());
127 ASSERT_TRUE(metricsFromCore.httpClientMetrics.size() == 0);
128 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
129 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
130 ASSERT_EQ(2u, reinterpret_cast<size_t>(context));
131 MonitorTwoAPICalledCounter[1] ++;
132 MonitorTwoAPICalledFlag |= 0x2;
133 }
134
OnRequestFailed(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,const Aws::Client::HttpResponseOutcome & outcome,const CoreMetricsCollection & metricsFromCore,void * context) const135 void OnRequestFailed(const Aws::String& serviceName, const Aws::String& requestName, const std::shared_ptr<const Aws::Http::HttpRequest>& request,
136 const Aws::Client::HttpResponseOutcome& outcome, const CoreMetricsCollection& metricsFromCore, void* context) const override
137 {
138 ASSERT_FALSE(outcome.IsSuccess());
139 ASSERT_TRUE(metricsFromCore.httpClientMetrics.size() == 0);
140 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
141 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
142 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
143 ASSERT_EQ(2u, reinterpret_cast<size_t>(context));
144 MonitorTwoAPICalledFlag |= 0x4;
145 MonitorTwoAPICalledCounter[2] ++;
146 }
147
OnRequestRetry(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,void * context) const148 void OnRequestRetry(const Aws::String& serviceName, const Aws::String& requestName,
149 const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const override
150 {
151 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
152 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
153 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
154 ASSERT_EQ(2u, reinterpret_cast<size_t>(context));
155 MonitorTwoAPICalledFlag |= 0x8;
156 MonitorTwoAPICalledCounter[3] ++;
157 }
158
OnFinish(const Aws::String & serviceName,const Aws::String & requestName,const std::shared_ptr<const Aws::Http::HttpRequest> & request,void * context) const159 void OnFinish(const Aws::String& serviceName, const Aws::String& requestName,
160 const std::shared_ptr<const Aws::Http::HttpRequest>& request, void* context) const override
161 {
162 ASSERT_STREQ("MockAWSClient", serviceName.c_str());
163 ASSERT_STREQ("AmazonWebServiceRequestMock", requestName.c_str());
164 ASSERT_STREQ(URI_STRING, request->GetURIString().c_str());
165 ASSERT_EQ(2u, reinterpret_cast<size_t>(context));
166 MonitorTwoAPICalledFlag |= 0x10;
167 MonitorTwoAPICalledCounter[4] ++;
168 }
169 };
170
171 class MockMonitoringFactoryTwo : public MonitoringFactory
172 {
173 public:
CreateMonitoringInstance() const174 Aws::UniquePtr<MonitoringInterface> CreateMonitoringInstance() const override
175 {
176 return Aws::MakeUnique<MockMonitoringTwo>(ALLOCATION_TAG);
177 }
178 };
179
CreateMonitoringFactoryTwo()180 Aws::UniquePtr<MonitoringFactory> CreateMonitoringFactoryTwo()
181 {
182 return Aws::MakeUnique<MockMonitoringFactoryTwo>(ALLOCATION_TAG);
183 }
184
185 class MonitoringTestSuite : public ::testing::Test
186 {
187 protected:
188 std::shared_ptr<MockHttpClient> mockHttpClient;
189 std::shared_ptr<MockHttpClientFactory> mockHttpClientFactory;
190 Aws::UniquePtr<MockAWSClient> client;
191
SetUp()192 void SetUp()
193 {
194 ClientConfiguration config;
195 config.scheme = Scheme::HTTP;
196 config.connectTimeoutMs = 30000;
197 config.requestTimeoutMs = 30000;
198 auto countedRetryStrategy = Aws::MakeShared<CountedRetryStrategy>(ALLOCATION_TAG);
199 config.retryStrategy = std::static_pointer_cast<DefaultRetryStrategy>(countedRetryStrategy);
200
201 mockHttpClient = Aws::MakeShared<MockHttpClient>(ALLOCATION_TAG);
202 mockHttpClientFactory = Aws::MakeShared<MockHttpClientFactory>(ALLOCATION_TAG);
203 mockHttpClientFactory->SetClient(mockHttpClient);
204 SetHttpClientFactory(mockHttpClientFactory);
205 client = Aws::MakeUnique<MockAWSClient>(ALLOCATION_TAG, config);
206
207 Aws::Monitoring::CleanupMonitoring();
208 std::vector<MonitoringFactoryCreateFunction> factoryFunctions;
209 factoryFunctions.emplace_back(CreateMonitoringFactoryOne);
210 factoryFunctions.emplace_back(CreateMonitoringFactoryTwo);
211 Aws::Monitoring::InitMonitoring(factoryFunctions);
212
213 MonitorOneAPICalledFlag = 0;
214 MonitorTwoAPICalledFlag = 0;
215 std::fill(MonitorOneAPICalledCounter.begin(), MonitorOneAPICalledCounter.end(), 0);
216 std::fill(MonitorTwoAPICalledCounter.begin(), MonitorTwoAPICalledCounter.end(), 0);
217 }
218
TearDown()219 void TearDown()
220 {
221 client = nullptr;
222 mockHttpClient = nullptr;
223 mockHttpClientFactory = nullptr;
224
225 CleanupMonitoring();
226 CleanupHttp();
227 InitHttp();
228 InitMonitoring(std::vector<Aws::Monitoring::MonitoringFactoryCreateFunction>());
229 }
230
QueueMockResponse(HttpResponseCode code,const HeaderValueCollection & headers)231 void QueueMockResponse(HttpResponseCode code, const HeaderValueCollection& headers)
232 {
233 auto httpRequest = CreateHttpRequest(URI(URI_STRING),
234 HttpMethod::HTTP_GET, Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
235 auto httpResponse = Aws::MakeShared<StandardHttpResponse>(ALLOCATION_TAG, httpRequest);
236 httpResponse->SetResponseCode(code);
237 httpResponse->GetResponseBody() << "";
238 for(auto&& header : headers)
239 {
240 httpResponse->AddHeader(header.first, header.second);
241 }
242 mockHttpClient->AddResponseToReturn(httpResponse);
243 }
244 };
245
TEST_F(MonitoringTestSuite,TestMonitoringListenersAreCalledCorrectlyWithRetryAndSucceededRequest)246 TEST_F(MonitoringTestSuite, TestMonitoringListenersAreCalledCorrectlyWithRetryAndSucceededRequest)
247 {
248 HeaderValueCollection responseHeaders, requestHeaders;
249 responseHeaders.emplace("Date", (Aws::Utils::DateTime::Now() + std::chrono::hours(1)).ToGmtString(Aws::Utils::DateFormat::RFC822)); // server is ahead of us by 1 hour
250 AmazonWebServiceRequestMock request;
251 requestHeaders.emplace("X-Amz-Date", Aws::Utils::DateTime::Now().ToGmtString(Aws::Utils::DateFormat::ISO_8601));
252 request.SetHeaders(requestHeaders);
253 // BAD_REQUEST is not retryable, but since this is triggered by clock skew, it's set to mandatory retryable.
254 QueueMockResponse(HttpResponseCode::BAD_REQUEST, responseHeaders);
255 QueueMockResponse(HttpResponseCode::OK, responseHeaders);
256 auto outcome = client->MakeRequest(request);
257 ASSERT_TRUE(outcome.IsSuccess());
258 ASSERT_EQ(1, client->GetRequestAttemptedRetries());
259 ASSERT_EQ(0x1F, MonitorOneAPICalledFlag);
260 ASSERT_EQ(0x1F, MonitorTwoAPICalledFlag);
261 ASSERT_EQ(1, MonitorOneAPICalledCounter[0]); // started 1 time
262 ASSERT_EQ(1, MonitorOneAPICalledCounter[1]); // succeeded 1 time
263 ASSERT_EQ(1, MonitorOneAPICalledCounter[2]); // failed 1 times
264 ASSERT_EQ(1, MonitorOneAPICalledCounter[3]); // retried 1 times
265 ASSERT_EQ(1, MonitorOneAPICalledCounter[4]); // finished 1 time
266 }
267
TEST_F(MonitoringTestSuite,TestMonitoringListenersAreCalledCorrectlyWithRetryAndFailedRequest)268 TEST_F(MonitoringTestSuite, TestMonitoringListenersAreCalledCorrectlyWithRetryAndFailedRequest)
269 {
270 HeaderValueCollection responseHeaders, requestHeaders;
271 responseHeaders.emplace("Date", (Aws::Utils::DateTime::Now() + std::chrono::hours(1)).ToGmtString(Aws::Utils::DateFormat::RFC822)); // server is ahead of us by 1 hour
272 AmazonWebServiceRequestMock request;
273 requestHeaders.emplace("X-Amz-Date", Aws::Utils::DateTime::Now().ToGmtString(Aws::Utils::DateFormat::ISO_8601));
274 request.SetHeaders(requestHeaders);
275 QueueMockResponse(HttpResponseCode::BAD_REQUEST, responseHeaders);
276 QueueMockResponse(HttpResponseCode::BAD_REQUEST, responseHeaders);
277 auto outcome = client->MakeRequest(request);
278 ASSERT_FALSE(outcome.IsSuccess());
279 ASSERT_EQ(1, client->GetRequestAttemptedRetries());
280 ASSERT_EQ(0x1D, MonitorOneAPICalledFlag);
281 ASSERT_EQ(0x1D, MonitorTwoAPICalledFlag);
282 ASSERT_EQ(1, MonitorOneAPICalledCounter[0]); // started 1 time
283 ASSERT_EQ(0, MonitorOneAPICalledCounter[1]); // succeeded 0 time
284 ASSERT_EQ(2, MonitorOneAPICalledCounter[2]); // failed 2 times
285 ASSERT_EQ(1, MonitorOneAPICalledCounter[3]); // retried 1 time
286 ASSERT_EQ(1, MonitorOneAPICalledCounter[4]); // finished 1 time
287 }
288
TEST_F(MonitoringTestSuite,TestMonitoringListenersAreCalledCorrectlyWithoutRetryAndSucceededRequest)289 TEST_F(MonitoringTestSuite, TestMonitoringListenersAreCalledCorrectlyWithoutRetryAndSucceededRequest)
290 {
291 HeaderValueCollection responseHeaders, requestHeaders;
292 responseHeaders.emplace("Date", (Aws::Utils::DateTime::Now() + std::chrono::hours(1)).ToGmtString(Aws::Utils::DateFormat::RFC822)); // server is ahead of us by 1 hour
293 AmazonWebServiceRequestMock request;
294 requestHeaders.emplace("X-Amz-Date", Aws::Utils::DateTime::Now().ToGmtString(Aws::Utils::DateFormat::ISO_8601));
295 request.SetHeaders(requestHeaders);
296 QueueMockResponse(HttpResponseCode::OK, responseHeaders);
297 auto outcome = client->MakeRequest(request);
298 ASSERT_TRUE(outcome.IsSuccess());
299 ASSERT_EQ(0, client->GetRequestAttemptedRetries());
300 ASSERT_EQ(0x13, MonitorOneAPICalledFlag);
301 ASSERT_EQ(0x13, MonitorTwoAPICalledFlag);
302 ASSERT_EQ(1, MonitorOneAPICalledCounter[0]); // started 1 time
303 ASSERT_EQ(1, MonitorOneAPICalledCounter[1]); // succeeded 1 time
304 ASSERT_EQ(0, MonitorOneAPICalledCounter[2]); // failed 0 time
305 ASSERT_EQ(0, MonitorOneAPICalledCounter[3]); // retried 0 time
306 ASSERT_EQ(1, MonitorOneAPICalledCounter[4]); // finished 1 time
307 }
308
TEST_F(MonitoringTestSuite,TestHttpClientMetrics)309 TEST_F(MonitoringTestSuite, TestHttpClientMetrics)
310 {
311 ASSERT_EQ(HttpClientMetricsType::DestinationIp, GetHttpClientMetricTypeByName("DestinationIp"));
312 ASSERT_EQ(HttpClientMetricsType::AcquireConnectionLatency, GetHttpClientMetricTypeByName("AcquireConnectionLatency"));
313 ASSERT_EQ(HttpClientMetricsType::ConnectionReused, GetHttpClientMetricTypeByName("ConnectionReused"));
314 ASSERT_EQ(HttpClientMetricsType::ConnectLatency, GetHttpClientMetricTypeByName("ConnectLatency"));
315 ASSERT_EQ(HttpClientMetricsType::RequestLatency, GetHttpClientMetricTypeByName("RequestLatency"));
316 ASSERT_EQ(HttpClientMetricsType::DnsLatency, GetHttpClientMetricTypeByName("DnsLatency"));
317 ASSERT_EQ(HttpClientMetricsType::TcpLatency, GetHttpClientMetricTypeByName("TcpLatency"));
318 ASSERT_EQ(HttpClientMetricsType::SslLatency, GetHttpClientMetricTypeByName("SslLatency"));
319 ASSERT_EQ(HttpClientMetricsType::Unknown, GetHttpClientMetricTypeByName("Unknown"));
320 ASSERT_EQ(HttpClientMetricsType::Unknown, GetHttpClientMetricTypeByName("RandomMetricsUnknown"));
321
322 ASSERT_STREQ("DestinationIp", GetHttpClientMetricNameByType(HttpClientMetricsType::DestinationIp).c_str());
323 ASSERT_STREQ("AcquireConnectionLatency", GetHttpClientMetricNameByType(HttpClientMetricsType::AcquireConnectionLatency).c_str());
324 ASSERT_STREQ("ConnectionReused", GetHttpClientMetricNameByType(HttpClientMetricsType::ConnectionReused).c_str());
325 ASSERT_STREQ("ConnectLatency", GetHttpClientMetricNameByType(HttpClientMetricsType::ConnectLatency).c_str());
326 ASSERT_STREQ("RequestLatency", GetHttpClientMetricNameByType(HttpClientMetricsType::RequestLatency).c_str());
327 ASSERT_STREQ("DnsLatency", GetHttpClientMetricNameByType(HttpClientMetricsType::DnsLatency).c_str());
328 ASSERT_STREQ("TcpLatency", GetHttpClientMetricNameByType(HttpClientMetricsType::TcpLatency).c_str());
329 ASSERT_STREQ("SslLatency", GetHttpClientMetricNameByType(HttpClientMetricsType::SslLatency).c_str());
330 ASSERT_STREQ("Unknown", GetHttpClientMetricNameByType(HttpClientMetricsType::Unknown).c_str());
331 }
332