• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "fcp/client/http/curl/curl_http_client.h"
18 
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23 
24 #include "absl/time/clock.h"
25 #include "fcp/client/http/in_memory_request_response.h"
26 #include "fcp/client/http/testing/http_test_server.h"
27 #include "fcp/client/http/testing/test_helpers.h"
28 
29 namespace fcp::client::http::curl {
30 namespace {
31 using ::testing::_;
32 using ::testing::AllOf;
33 using ::testing::Field;
34 using ::testing::FieldsAre;
35 using ::testing::StrictMock;
36 using ::testing::UnorderedElementsAreArray;
37 
SetUpOnResponseStarted(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers)38 void SetUpOnResponseStarted(
39     StrictMock<MockHttpRequestCallback>* request_callback,
40     const std::string& request_uri, HttpRequest::Method method,
41     int response_code, const HeaderList& expected_request_extra_headers,
42     bool has_body, const HeaderList& expected_response_headers) {
43   EXPECT_CALL(*request_callback, OnResponseStarted(_, _))
44       .WillOnce(::testing::Invoke([=, &request_uri](
45                                       const HttpRequest& request,
46                                       const HttpResponse& response) {
47         EXPECT_THAT(request.uri(), request_uri);
48         EXPECT_THAT(request.method(), method);
49         EXPECT_THAT(request.extra_headers(),
50                     UnorderedElementsAreArray(expected_request_extra_headers));
51         EXPECT_THAT(request.HasBody(), has_body);
52         EXPECT_THAT(response.code(), response_code);
53         EXPECT_THAT(response.headers(),
54                     UnorderedElementsAreArray(expected_response_headers));
55         return absl::OkStatus();
56       }));
57 }
58 
SetUpOnResponseBody(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers,const std::string & expected_response_body)59 void SetUpOnResponseBody(StrictMock<MockHttpRequestCallback>* request_callback,
60                          const std::string& request_uri,
61                          HttpRequest::Method method, int response_code,
62                          const HeaderList& expected_request_extra_headers,
63                          bool has_body,
64                          const HeaderList& expected_response_headers,
65                          const std::string& expected_response_body) {
66   EXPECT_CALL(*request_callback, OnResponseBody(_, _, _))
67       .WillOnce(::testing::Invoke([=](const HttpRequest& request,
68                                       const HttpResponse& response,
69                                       absl::string_view data) {
70         EXPECT_THAT(request.uri(), request_uri);
71         EXPECT_THAT(request.method(), method);
72         EXPECT_THAT(request.extra_headers(),
73                     UnorderedElementsAreArray(expected_request_extra_headers));
74         EXPECT_THAT(request.HasBody(), has_body);
75         EXPECT_THAT(response.code(), response_code);
76         EXPECT_THAT(response.headers(),
77                     UnorderedElementsAreArray(expected_response_headers));
78         EXPECT_THAT(data, expected_response_body);
79         return absl::OkStatus();
80       }));
81 }
82 
SetUpOnResponseBody(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)83 void SetUpOnResponseBody(StrictMock<MockHttpRequestCallback>* request_callback,
84                          const std::string& request_uri,
85                          HttpRequest::Method method, int response_code,
86                          const HeaderList& expected_request_extra_headers,
87                          bool has_body,
88                          const HeaderList& expected_response_headers,
89                          const std::string& expected_response_body,
90                          size_t& total_bytes_downloaded) {
91   EXPECT_CALL(*request_callback, OnResponseBody(_, _, _))
92       .WillOnce(::testing::Invoke(
93           [=, &total_bytes_downloaded](const HttpRequest& request,
94                                        const HttpResponse& response,
95                                        absl::string_view data) {
96             EXPECT_THAT(request.uri(), request_uri);
97             EXPECT_THAT(request.method(), method);
98             EXPECT_THAT(
99                 request.extra_headers(),
100                 UnorderedElementsAreArray(expected_request_extra_headers));
101             EXPECT_THAT(request.HasBody(), has_body);
102             EXPECT_THAT(response.code(), response_code);
103             EXPECT_THAT(response.headers(),
104                         UnorderedElementsAreArray(expected_response_headers));
105             EXPECT_THAT(data, expected_response_body);
106             total_bytes_downloaded += data.size();
107             return absl::OkStatus();
108           }));
109 }
110 
SetUpOnResponseCompleted(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,HttpRequest::Method method,int response_code,const HeaderList & expected_request_extra_headers,bool has_body,const HeaderList & expected_response_headers)111 void SetUpOnResponseCompleted(
112     StrictMock<MockHttpRequestCallback>* request_callback,
113     const std::string& request_uri, HttpRequest::Method method,
114     int response_code, const HeaderList& expected_request_extra_headers,
115     bool has_body, const HeaderList& expected_response_headers) {
116   EXPECT_CALL(*request_callback, OnResponseCompleted(_, _))
117       .WillOnce(::testing::Invoke([=, &request_uri](
118                                       const HttpRequest& request,
119                                       const HttpResponse& response) {
120         EXPECT_THAT(request.uri(), request_uri);
121         EXPECT_THAT(request.method(), method);
122         EXPECT_THAT(request.extra_headers(),
123                     UnorderedElementsAreArray(expected_request_extra_headers));
124         EXPECT_THAT(request.HasBody(), has_body);
125         EXPECT_THAT(response.code(), response_code);
126         EXPECT_THAT(response.headers(),
127                     UnorderedElementsAreArray(expected_response_headers));
128       }));
129 }
130 
SetUpGetRequestCallback(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,const HeaderList & expected_request_extra_headers,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)131 void SetUpGetRequestCallback(
132     StrictMock<MockHttpRequestCallback>* request_callback,
133     const std::string& request_uri,
134     const HeaderList& expected_request_extra_headers,
135     const HeaderList& expected_response_headers,
136     const std::string& expected_response_body, size_t& total_bytes_downloaded) {
137   SetUpOnResponseStarted(request_callback, request_uri,
138                          HttpRequest::Method::kGet, /*response_code*/ 200,
139                          expected_request_extra_headers,
140                          /*has_body*/ false, expected_response_headers);
141   SetUpOnResponseBody(request_callback, request_uri, HttpRequest::Method::kGet,
142                       /*response_code*/ 200, expected_request_extra_headers,
143                       /*has_body*/ false, expected_response_headers,
144                       expected_response_body, total_bytes_downloaded);
145 
146   SetUpOnResponseCompleted(request_callback, request_uri,
147                            HttpRequest::Method::kGet, /*response_code*/ 200,
148                            expected_request_extra_headers,
149                            /*has_body*/ false, expected_response_headers);
150 }
151 
SetUpPostRequestCallback(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,const HeaderList & expected_request_extra_headers,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)152 void SetUpPostRequestCallback(
153     StrictMock<MockHttpRequestCallback>* request_callback,
154     const std::string& request_uri,
155     const HeaderList& expected_request_extra_headers,
156     const HeaderList& expected_response_headers,
157     const std::string& expected_response_body, size_t& total_bytes_downloaded) {
158   SetUpOnResponseStarted(request_callback, request_uri,
159                          HttpRequest::Method::kPost, /*response_code*/ 200,
160                          expected_request_extra_headers,
161                          /*has_body*/ true, expected_response_headers);
162 
163   SetUpOnResponseBody(request_callback, request_uri, HttpRequest::Method::kPost,
164                       /*response_code*/ 200, expected_request_extra_headers,
165                       /*has_body*/ true, expected_response_headers,
166                       expected_response_body, total_bytes_downloaded);
167 
168   SetUpOnResponseCompleted(request_callback, request_uri,
169                            HttpRequest::Method::kPost, /*response_code*/ 200,
170                            expected_request_extra_headers,
171                            /*has_body*/ true, expected_response_headers);
172 }
173 
SetUpPutRequestCallback(StrictMock<MockHttpRequestCallback> * request_callback,const std::string & request_uri,const HeaderList & expected_request_extra_headers,const HeaderList & expected_response_headers,const std::string & expected_response_body,size_t & total_bytes_downloaded)174 void SetUpPutRequestCallback(
175     StrictMock<MockHttpRequestCallback>* request_callback,
176     const std::string& request_uri,
177     const HeaderList& expected_request_extra_headers,
178     const HeaderList& expected_response_headers,
179     const std::string& expected_response_body, size_t& total_bytes_downloaded) {
180   SetUpOnResponseStarted(request_callback, request_uri,
181                          HttpRequest::Method::kPut, /*response_code*/ 200,
182                          expected_request_extra_headers,
183                          /*has_body*/ true, expected_response_headers);
184 
185   SetUpOnResponseBody(request_callback, request_uri, HttpRequest::Method::kPut,
186                       /*response_code*/ 200, expected_request_extra_headers,
187                       /*has_body*/ true, expected_response_headers,
188                       expected_response_body, total_bytes_downloaded);
189 
190   SetUpOnResponseCompleted(request_callback, request_uri,
191                            HttpRequest::Method::kPut, /*response_code*/ 200,
192                            expected_request_extra_headers,
193                            /*has_body*/ true, expected_response_headers);
194 }
195 
PerformTwoRequests(CurlHttpClient * http_client,int port,const std::string & request_uri1,const std::string & request_uri2)196 void PerformTwoRequests(CurlHttpClient* http_client, int port,
197                         const std::string& request_uri1,
198                         const std::string& request_uri2) {
199   std::string request1_body;
200   std::string request2_body = "test: 123-45";
201 
202   auto request1 = InMemoryHttpRequest::Create(
203       request_uri1, HttpRequest::Method::kGet, HeaderList(), request1_body,
204       /*use_compression*/ false);
205   ASSERT_OK(request1);
206 
207   auto request2 = InMemoryHttpRequest::Create(
208       request_uri2, HttpRequest::Method::kPost, HeaderList(), request2_body,
209       /*use_compression*/ false);
210   ASSERT_OK(request2);
211 
212   auto handle1 = http_client->EnqueueRequest(std::move(request1.value()));
213   auto handle2 = http_client->EnqueueRequest(std::move(request2.value()));
214 
215   auto request_callback1 =
216       std::make_unique<StrictMock<MockHttpRequestCallback>>();
217   auto request_callback2 =
218       std::make_unique<StrictMock<MockHttpRequestCallback>>();
219 
220   size_t total_bytes_downloaded_handle1 = 0;
221   size_t total_bytes_downloaded_handle2 = 0;
222 
223   HeaderList expected_request_extra_headers{{"Content-Length", "12"}};
224   HeaderList expected_response_headers{
225       {"Content-Type", "text/html"},
226       {"Date",
227        absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
228 
229   auto expected_response_body1 = absl::StrCat(
230       "HTTP Method: GET\n", "Request Uri: /test\n", "Request Headers:\n",
231       "Host: localhost:", port, "\nAccept: */*\n", "Accept-Encoding: gzip\n",
232       "Request Body:\n");
233 
234   auto expected_response_body2 = absl::StrCat(
235       "HTTP Method: POST\nRequest Uri: /test\n",
236       "Request Headers:\nHost: localhost:", port,
237       "\nAccept: */*\nAccept-Encoding: gzip\n", "Content-Length: 12\n",
238       "Content-Type: application/x-www-form-urlencoded\n",
239       "Request Body:\ntest: 123-45");
240 
241   SetUpGetRequestCallback(request_callback1.get(), request_uri1,
242                           /*expected_request_extra_headers*/ {},
243                           expected_response_headers, expected_response_body1,
244                           total_bytes_downloaded_handle1);
245   SetUpPostRequestCallback(request_callback2.get(), request_uri2,
246                            expected_request_extra_headers,
247                            expected_response_headers, expected_response_body2,
248                            total_bytes_downloaded_handle2);
249 
250   std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
251       std::make_pair(handle1.get(), request_callback1.get()),
252       std::make_pair(handle2.get(), request_callback2.get())};
253 
254   EXPECT_THAT(handle1->TotalSentReceivedBytes(), FieldsAre(0, 0));
255   EXPECT_THAT(handle2->TotalSentReceivedBytes(), FieldsAre(0, 0));
256 
257   absl::Status status = http_client->PerformRequests(requests);
258 
259   EXPECT_THAT(status, absl::OkStatus());
260   EXPECT_THAT(handle1->TotalSentReceivedBytes(),
261               AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
262                           request1_body.size()),
263                     Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
264                           total_bytes_downloaded_handle1)));
265   EXPECT_THAT(handle2->TotalSentReceivedBytes(),
266               AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
267                           request2_body.size()),
268                     Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
269                           total_bytes_downloaded_handle2)));
270 }
271 
272 // Runs PerformRequests once in one thread.
TEST(CurlHttpClientTest,PerformTwoRequestsInParallelInOneThread)273 TEST(CurlHttpClientTest, PerformTwoRequestsInParallelInOneThread) {
274   const int port = 4568;
275   const std::string request_uri =
276       absl::StrCat("http://localhost:", port, "/test");
277 
278   auto curl_api = std::make_unique<CurlApi>();
279   auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
280   auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 5);
281   EXPECT_THAT(http_server.ok(), true);
282   EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
283 
284   PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
285 
286   curl_api.reset();
287   http_server.value()->Terminate();
288   http_server.value()->WaitForTermination();
289 }
290 
TEST(CurlHttpClientTest,PutRequest)291 TEST(CurlHttpClientTest, PutRequest) {
292   const int port = 4568;
293   const std::string request_uri =
294       absl::StrCat("http://localhost:", port, "/test");
295 
296   auto curl_api = std::make_unique<CurlApi>();
297   auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
298   auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 5);
299   EXPECT_THAT(http_server.ok(), true);
300   EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
301 
302   std::string request_body = "test: 123-45";
303 
304   auto request = InMemoryHttpRequest::Create(
305       request_uri, HttpRequest::Method::kPut, HeaderList(), request_body,
306       /*use_compression*/ false);
307   ASSERT_OK(request);
308 
309   auto handle = http_client->EnqueueRequest(std::move(request.value()));
310 
311   auto request_callback =
312       std::make_unique<StrictMock<MockHttpRequestCallback>>();
313 
314   size_t total_bytes_downloaded_handle = 0;
315 
316   HeaderList expected_request_extra_headers{{"Content-Length", "12"}};
317   HeaderList expected_response_headers{
318       {"Content-Type", "text/html"},
319       {"Date",
320        absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
321 
322   auto expected_response_body =
323       absl::StrCat("HTTP Method: PUT\nRequest Uri: /test\n",
324                    "Request Headers:\nHost: localhost:", port,
325                    "\nAccept: */*\nAccept-Encoding: gzip\n",
326                    "Content-Length: 12\n", "Request Body:\ntest: 123-45");
327 
328   SetUpPutRequestCallback(request_callback.get(), request_uri,
329                           expected_request_extra_headers,
330                           expected_response_headers, expected_response_body,
331                           total_bytes_downloaded_handle);
332 
333   std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
334       std::make_pair(handle.get(), request_callback.get())};
335 
336   EXPECT_THAT(handle->TotalSentReceivedBytes(), FieldsAre(0, 0));
337 
338   absl::Status status = http_client->PerformRequests(requests);
339 
340   EXPECT_THAT(status, absl::OkStatus());
341   EXPECT_THAT(handle->TotalSentReceivedBytes(),
342               AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
343                           request_body.size()),
344                     Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
345                           total_bytes_downloaded_handle)));
346 
347   curl_api.reset();
348   http_server.value()->Terminate();
349   http_server.value()->WaitForTermination();
350 }
351 
352 // Runs PerformRequests in five times in five threads.
TEST(CurlHttpClientTest,PerformTwoRequestsInParallelFiveTimesInFiveThreads)353 TEST(CurlHttpClientTest, PerformTwoRequestsInParallelFiveTimesInFiveThreads) {
354   const int port = 4568;
355   const std::string request_uri =
356       absl::StrCat("http://localhost:", port, "/test");
357 
358   auto curl_api = std::make_unique<CurlApi>();
359   auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
360   auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 10);
361   EXPECT_THAT(http_server.ok(), true);
362   EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
363 
364   auto thread_pool_scheduler = CreateThreadPoolScheduler(5);
365 
366   thread_pool_scheduler->Schedule([&http_client, request_uri]() {
367     PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
368   });
369   thread_pool_scheduler->Schedule([&http_client, request_uri]() {
370     PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
371   });
372   thread_pool_scheduler->Schedule([&http_client, request_uri]() {
373     PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
374   });
375   thread_pool_scheduler->Schedule([&http_client, request_uri]() {
376     PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
377   });
378   thread_pool_scheduler->Schedule([&http_client, request_uri]() {
379     PerformTwoRequests(http_client.get(), port, request_uri, request_uri);
380   });
381 
382   thread_pool_scheduler->WaitUntilIdle();
383 
384   curl_api.reset();
385   http_server.value()->Terminate();
386   http_server.value()->WaitForTermination();
387 }
388 
389 // Runs PerformRequests with two requests and cancels the second after
390 // OnResponseStarted received.
TEST(CurlHttpClientTest,CancelRequest)391 TEST(CurlHttpClientTest, CancelRequest) {
392   const int port = 4568;
393   const std::string request_uri1 =
394       absl::StrCat("http://localhost:", port, "/test");
395   const std::string request_uri2 =
396       absl::StrCat("http://localhost:", port, "/test");
397 
398   auto curl_api = std::make_unique<CurlApi>();
399   auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
400   auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 5);
401   EXPECT_THAT(http_server.ok(), true);
402   EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
403 
404   std::string request1_body;
405   std::string request2_body = "test: 123-45";
406 
407   auto request1 = InMemoryHttpRequest::Create(
408       request_uri1, HttpRequest::Method::kGet, HeaderList(), request1_body,
409       /*use_compression*/ false);
410   ASSERT_OK(request1);
411 
412   auto request2 = InMemoryHttpRequest::Create(
413       request_uri2, HttpRequest::Method::kPost, HeaderList(), request2_body,
414       /*use_compression*/ false);
415   ASSERT_OK(request2);
416 
417   auto handle1 = http_client->EnqueueRequest(std::move(request1.value()));
418   auto handle2 = http_client->EnqueueRequest(std::move(request2.value()));
419 
420   auto request_callback1 =
421       std::make_unique<StrictMock<MockHttpRequestCallback>>();
422   auto request_callback2 =
423       std::make_unique<StrictMock<MockHttpRequestCallback>>();
424 
425   size_t total_bytes_downloaded_handle1 = 0;
426 
427   HeaderList expected_request_extra_headers{{"Content-Length", "12"}};
428   HeaderList expected_response_headers{
429       {"Content-Type", "text/html"},
430       {"Date",
431        absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
432 
433   auto expected_response_body = absl::StrCat(
434       "HTTP Method: GET\n", "Request Uri: /test\n", "Request Headers:\n",
435       "Host: localhost:", port, "\nAccept: */*\n", "Accept-Encoding: gzip\n",
436       "Request Body:\n");
437 
438   SetUpGetRequestCallback(request_callback1.get(), request_uri1,
439                           /*expected_request_extra_headers*/ {},
440                           expected_response_headers, expected_response_body,
441                           total_bytes_downloaded_handle1);
442 
443   EXPECT_CALL(*request_callback2, OnResponseStarted(_, _))
444       .WillOnce(::testing::Invoke(
445           [&handle2](const HttpRequest& request, const HttpResponse& response) {
446             handle2->Cancel();
447             return absl::OkStatus();
448           }));
449 
450   auto expected_response_body2 = absl::StrCat(
451       "HTTP Method: POST\nRequest Uri: /test\n",
452       "Request Headers:\nHost: localhost:", port,
453       "\nAccept: */*\nAccept-Encoding: gzip\n", "Content-Length: 12\n",
454       "Content-Type: application/x-www-form-urlencoded\n",
455       "Request Body:\ntest: 123-45");
456 
457   SetUpOnResponseBody(
458       request_callback2.get(), request_uri2, HttpRequest::Method::kPost,
459       /*response_code*/ 200, expected_request_extra_headers,
460       /*has_body*/ true, expected_response_headers, expected_response_body2);
461 
462   EXPECT_CALL(*request_callback2, OnResponseBodyError(_, _, _))
463       .WillOnce(::testing::Invoke([&request_uri2](const HttpRequest& request,
464                                                   const HttpResponse& response,
465                                                   const absl::Status& error) {
466         EXPECT_THAT(request.uri(), request_uri2);
467         EXPECT_THAT(request.method(), HttpRequest::Method::kPost);
468         EXPECT_THAT(request.extra_headers().size(), 1);
469         EXPECT_THAT(request.HasBody(), true);
470       }));
471 
472   std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
473       std::make_pair(handle1.get(), request_callback1.get()),
474       std::make_pair(handle2.get(), request_callback2.get())};
475 
476   auto thread_pool_scheduler = CreateThreadPoolScheduler(2);
477   thread_pool_scheduler->Schedule([&http_client, &requests]() {
478     absl::Status status = http_client->PerformRequests(requests);
479 
480     EXPECT_THAT(status, absl::OkStatus());
481   });
482 
483   thread_pool_scheduler->WaitUntilIdle();
484 
485   EXPECT_THAT(handle1->TotalSentReceivedBytes(),
486               AllOf(Field(&HttpRequestHandle::SentReceivedBytes::sent_bytes,
487                           request1_body.size()),
488                     Field(&HttpRequestHandle::SentReceivedBytes::received_bytes,
489                           total_bytes_downloaded_handle1)));
490 
491   curl_api.reset();
492   http_server.value()->Terminate();
493   http_server.value()->WaitForTermination();
494 }
495 
496 // Runs PerformRequests once in one thread.
TEST(CurlHttpClientTest,TestExtraHeaders)497 TEST(CurlHttpClientTest, TestExtraHeaders) {
498   const int port = 4568;
499   const std::string request_uri =
500       absl::StrCat("http://localhost:", port, "/test");
501 
502   auto curl_api = std::make_unique<CurlApi>();
503   auto http_client = std::make_unique<CurlHttpClient>(curl_api.get());
504 
505   auto http_server = CreateHttpTestServer("/test", port, /*num_threads*/ 3);
506   EXPECT_THAT(http_server.ok(), true);
507   EXPECT_THAT(http_server.value()->StartAcceptingRequests(), true);
508 
509   std::string request_body = "test: 123-45";
510   HeaderList extra_headers = {{"Content-Type", "application/x-protobuf"}};
511 
512   auto request = InMemoryHttpRequest::Create(
513       request_uri, HttpRequest::Method::kPost, extra_headers, request_body,
514       /*use_compression*/ false);
515   ASSERT_OK(request);
516 
517   auto handle = http_client->EnqueueRequest(std::move(request.value()));
518 
519   auto request_callback =
520       std::make_unique<StrictMock<MockHttpRequestCallback>>();
521 
522   HeaderList expected_request_extra_headers{
523       {"Content-Length", "12"},
524       {"Content-Type", "application/x-protobuf"},
525   };
526   HeaderList expected_response_headers{
527       {"Content-Type", "text/html"},
528       {"Date",
529        absl::FormatTime("%a, %d %b %Y %H", absl::Now(), absl::UTCTimeZone())}};
530   auto expected_response_body =
531       absl::StrCat("HTTP Method: POST\nRequest Uri: /test\n",
532                    "Request Headers:\nHost: localhost:", port,
533                    "\nAccept: */*\nAccept-Encoding: gzip\n",
534                    "Content-Type: application/x-protobuf\n",
535                    "Content-Length: 12\n", "Request Body:\ntest: 123-45");
536 
537   SetUpOnResponseStarted(request_callback.get(), request_uri,
538                          HttpRequest::Method::kPost, /*response_code*/ 200,
539                          expected_request_extra_headers,
540                          /*has_body*/ true, expected_response_headers);
541 
542   SetUpOnResponseBody(
543       request_callback.get(), request_uri, HttpRequest::Method::kPost,
544       /*response_code*/ 200, expected_request_extra_headers,
545       /*has_body*/ true, expected_response_headers, expected_response_body);
546 
547   SetUpOnResponseCompleted(request_callback.get(), request_uri,
548                            HttpRequest::Method::kPost, /*response_code*/ 200,
549                            expected_request_extra_headers,
550                            /*has_body*/ true, expected_response_headers);
551 
552   std::vector<std::pair<HttpRequestHandle*, HttpRequestCallback*>> requests{
553       std::make_pair(handle.get(), request_callback.get())};
554 
555   absl::Status status = http_client->PerformRequests(requests);
556   EXPECT_THAT(status, absl::OkStatus());
557 
558   curl_api.reset();
559   http_server.value()->Terminate();
560   http_server.value()->WaitForTermination();
561 }
562 
563 }  // namespace
564 }  // namespace fcp::client::http::curl
565