protobuf_http_client_unittest.cc 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "remoting/base/protobuf_http_client.h"
  5. #include <memory>
  6. #include "base/callback_helpers.h"
  7. #include "base/run_loop.h"
  8. #include "base/test/bind.h"
  9. #include "base/test/gmock_callback_support.h"
  10. #include "base/test/mock_callback.h"
  11. #include "base/test/task_environment.h"
  12. #include "net/http/http_status_code.h"
  13. #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
  14. #include "remoting/base/protobuf_http_client_messages.pb.h"
  15. #include "remoting/base/protobuf_http_client_test_messages.pb.h"
  16. #include "remoting/base/protobuf_http_request.h"
  17. #include "remoting/base/protobuf_http_request_config.h"
  18. #include "remoting/base/protobuf_http_status.h"
  19. #include "remoting/base/protobuf_http_stream_request.h"
  20. #include "services/network/public/cpp/shared_url_loader_factory.h"
  21. #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
  22. #include "services/network/test/test_url_loader_factory.h"
  23. #include "testing/gmock/include/gmock/gmock.h"
  24. #include "testing/gtest/include/gtest/gtest.h"
  25. namespace remoting {
  26. namespace {
  27. using protobufhttpclient::Status;
  28. using protobufhttpclient::StreamBody;
  29. using protobufhttpclienttest::EchoRequest;
  30. using protobufhttpclienttest::EchoResponse;
  31. using ::base::test::RunOnceCallback;
  32. using ::testing::_;
  33. using ::testing::InSequence;
  34. using EchoResponseCallback =
  35. ProtobufHttpRequest::ResponseCallback<EchoResponse>;
  36. using MockEchoResponseCallback = base::MockCallback<EchoResponseCallback>;
  37. using MockEchoMessageCallback = base::MockCallback<
  38. ProtobufHttpStreamRequest::MessageCallback<EchoResponse>>;
  39. using MockStreamClosedCallback =
  40. base::MockCallback<ProtobufHttpStreamRequest::StreamClosedCallback>;
  41. constexpr char kTestServerEndpoint[] = "test.com";
  42. constexpr char kTestRpcPath[] = "/v1/echo:echo";
  43. constexpr char kTestFullUrl[] = "https://test.com/v1/echo:echo";
  44. constexpr char kRequestText[] = "This is a request";
  45. constexpr char kResponseText[] = "This is a response";
  46. constexpr char kAuthorizationHeaderKey[] = "Authorization";
  47. constexpr char kFakeAccessToken[] = "fake_access_token";
  48. constexpr char kFakeAccessTokenHeaderValue[] = "Bearer fake_access_token";
  49. MATCHER_P(HasErrorCode, error_code, "") {
  50. return arg.error_code() == error_code;
  51. }
  52. MATCHER_P(EqualsToStatus, expected_status, "") {
  53. return arg.error_code() == expected_status.error_code() &&
  54. arg.error_message() == expected_status.error_message();
  55. }
  56. MATCHER(IsDefaultResponseText, "") {
  57. return arg->text() == kResponseText;
  58. }
  59. MATCHER_P(IsResponseText, response_text, "") {
  60. return arg->text() == response_text;
  61. }
  62. MATCHER(IsNullResponse, "") {
  63. return arg.get() == nullptr;
  64. }
  65. class MockOAuthTokenGetter : public OAuthTokenGetter {
  66. public:
  67. MOCK_METHOD1(CallWithToken, void(TokenCallback));
  68. MOCK_METHOD0(InvalidateCache, void());
  69. };
  70. EchoResponseCallback DoNothingResponse() {
  71. return base::DoNothing();
  72. }
  73. std::unique_ptr<ProtobufHttpRequestConfig> CreateDefaultRequestConfig() {
  74. auto request_message = std::make_unique<EchoRequest>();
  75. request_message->set_text(kRequestText);
  76. auto request_config =
  77. std::make_unique<ProtobufHttpRequestConfig>(TRAFFIC_ANNOTATION_FOR_TESTS);
  78. request_config->request_message = std::move(request_message);
  79. request_config->path = kTestRpcPath;
  80. return request_config;
  81. }
  82. std::unique_ptr<ProtobufHttpRequest> CreateDefaultTestRequest() {
  83. auto request =
  84. std::make_unique<ProtobufHttpRequest>(CreateDefaultRequestConfig());
  85. request->SetResponseCallback(DoNothingResponse());
  86. return request;
  87. }
  88. std::unique_ptr<ProtobufHttpStreamRequest> CreateDefaultTestStreamRequest() {
  89. auto request =
  90. std::make_unique<ProtobufHttpStreamRequest>(CreateDefaultRequestConfig());
  91. request->SetStreamReadyCallback(base::DoNothing());
  92. request->SetStreamClosedCallback(base::DoNothing());
  93. request->SetMessageCallback(
  94. base::BindRepeating([](std::unique_ptr<EchoResponse>) {}));
  95. return request;
  96. }
  97. std::string CreateSerializedEchoResponse(
  98. const std::string& text = kResponseText) {
  99. EchoResponse response;
  100. response.set_text(text);
  101. return response.SerializeAsString();
  102. }
  103. std::string CreateSerializedStreamBodyWithText(
  104. const std::string& text = kResponseText) {
  105. StreamBody stream_body;
  106. stream_body.add_messages(CreateSerializedEchoResponse(text));
  107. return stream_body.SerializeAsString();
  108. }
  109. std::string CreateSerializedStreamBodyWithStatusCode(
  110. ProtobufHttpStatus::Code status_code) {
  111. StreamBody stream_body;
  112. stream_body.mutable_status()->set_code(static_cast<int32_t>(status_code));
  113. return stream_body.SerializeAsString();
  114. }
  115. } // namespace
  116. class ProtobufHttpClientTest : public testing::Test {
  117. protected:
  118. void ExpectCallWithTokenSuccess();
  119. void ExpectCallWithTokenAuthError();
  120. void ExpectCallWithTokenNetworkError();
  121. base::test::SingleThreadTaskEnvironment task_environment_{
  122. base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  123. MockOAuthTokenGetter mock_token_getter_;
  124. network::TestURLLoaderFactory test_url_loader_factory_;
  125. scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ =
  126. base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
  127. &test_url_loader_factory_);
  128. ProtobufHttpClient client_{kTestServerEndpoint, &mock_token_getter_,
  129. test_shared_loader_factory_};
  130. };
  131. void ProtobufHttpClientTest::ExpectCallWithTokenSuccess() {
  132. EXPECT_CALL(mock_token_getter_, CallWithToken(_))
  133. .WillOnce(RunOnceCallback<0>(OAuthTokenGetter::Status::SUCCESS, "",
  134. kFakeAccessToken));
  135. }
  136. void ProtobufHttpClientTest::ExpectCallWithTokenAuthError() {
  137. EXPECT_CALL(mock_token_getter_, CallWithToken(_))
  138. .WillOnce(
  139. RunOnceCallback<0>(OAuthTokenGetter::Status::AUTH_ERROR, "", ""));
  140. }
  141. void ProtobufHttpClientTest::ExpectCallWithTokenNetworkError() {
  142. EXPECT_CALL(mock_token_getter_, CallWithToken(_))
  143. .WillOnce(
  144. RunOnceCallback<0>(OAuthTokenGetter::Status::NETWORK_ERROR, "", ""));
  145. }
  146. // Unary request tests.
  147. TEST_F(ProtobufHttpClientTest, SendRequestAndDecodeResponse) {
  148. base::RunLoop run_loop;
  149. ExpectCallWithTokenSuccess();
  150. MockEchoResponseCallback response_callback;
  151. EXPECT_CALL(response_callback, Run(HasErrorCode(ProtobufHttpStatus::Code::OK),
  152. IsDefaultResponseText()))
  153. .WillOnce([&]() { run_loop.Quit(); });
  154. auto request = CreateDefaultTestRequest();
  155. request->SetResponseCallback(response_callback.Get());
  156. client_.ExecuteRequest(std::move(request));
  157. // Verify request.
  158. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  159. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  160. auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
  161. std::string auth_header;
  162. ASSERT_TRUE(pending_request->request.headers.GetHeader(
  163. kAuthorizationHeaderKey, &auth_header));
  164. ASSERT_EQ(kFakeAccessTokenHeaderValue, auth_header);
  165. const auto& data_element =
  166. pending_request->request.request_body->elements()->front();
  167. ASSERT_EQ(data_element.type(), network::DataElement::Tag::kBytes);
  168. std::string request_body_data(
  169. data_element.As<network::DataElementBytes>().AsStringPiece());
  170. EchoRequest request_message;
  171. ASSERT_TRUE(request_message.ParseFromString(request_body_data));
  172. ASSERT_EQ(kRequestText, request_message.text());
  173. // Respond.
  174. test_url_loader_factory_.AddResponse(kTestFullUrl,
  175. CreateSerializedEchoResponse());
  176. run_loop.Run();
  177. ASSERT_FALSE(client_.HasPendingRequests());
  178. }
  179. TEST_F(ProtobufHttpClientTest,
  180. SendUnauthenticatedRequest_TokenGetterNotCalled) {
  181. EXPECT_CALL(mock_token_getter_, CallWithToken(_)).Times(0);
  182. auto request_config = CreateDefaultRequestConfig();
  183. request_config->authenticated = false;
  184. auto request =
  185. std::make_unique<ProtobufHttpRequest>(std::move(request_config));
  186. request->SetResponseCallback(DoNothingResponse());
  187. client_.ExecuteRequest(std::move(request));
  188. // Verify that the request is sent with no auth header.
  189. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  190. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  191. auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
  192. ASSERT_FALSE(
  193. pending_request->request.headers.HasHeader(kAuthorizationHeaderKey));
  194. }
  195. TEST_F(ProtobufHttpClientTest,
  196. FailedToFetchAuthToken_RejectsWithUnauthorizedError) {
  197. base::RunLoop run_loop;
  198. ExpectCallWithTokenAuthError();
  199. MockEchoResponseCallback response_callback;
  200. EXPECT_CALL(response_callback,
  201. Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED),
  202. IsNullResponse()))
  203. .WillOnce([&]() { run_loop.Quit(); });
  204. auto request = CreateDefaultTestRequest();
  205. request->SetResponseCallback(response_callback.Get());
  206. client_.ExecuteRequest(std::move(request));
  207. run_loop.Run();
  208. ASSERT_FALSE(client_.HasPendingRequests());
  209. }
  210. TEST_F(ProtobufHttpClientTest,
  211. FailedToFetchAuthToken_RejectsWithUnavailableError) {
  212. base::RunLoop run_loop;
  213. ExpectCallWithTokenNetworkError();
  214. MockEchoResponseCallback response_callback;
  215. EXPECT_CALL(response_callback,
  216. Run(HasErrorCode(ProtobufHttpStatus::Code::UNAVAILABLE),
  217. IsNullResponse()))
  218. .WillOnce([&]() { run_loop.Quit(); });
  219. auto request = CreateDefaultTestRequest();
  220. request->SetResponseCallback(response_callback.Get());
  221. client_.ExecuteRequest(std::move(request));
  222. run_loop.Run();
  223. ASSERT_FALSE(client_.HasPendingRequests());
  224. }
  225. TEST_F(ProtobufHttpClientTest, FailedToParseResponse_GetsInvalidResponseError) {
  226. base::RunLoop run_loop;
  227. ExpectCallWithTokenSuccess();
  228. MockEchoResponseCallback response_callback;
  229. EXPECT_CALL(
  230. response_callback,
  231. Run(HasErrorCode(ProtobufHttpStatus::Code::INTERNAL), IsNullResponse()))
  232. .WillOnce([&]() { run_loop.Quit(); });
  233. auto request = CreateDefaultTestRequest();
  234. request->SetResponseCallback(response_callback.Get());
  235. client_.ExecuteRequest(std::move(request));
  236. // Respond.
  237. test_url_loader_factory_.AddResponse(kTestFullUrl, "Invalid content");
  238. run_loop.Run();
  239. ASSERT_FALSE(client_.HasPendingRequests());
  240. }
  241. TEST_F(ProtobufHttpClientTest, ServerRespondsWithErrorStatusMessage) {
  242. base::RunLoop run_loop;
  243. ExpectCallWithTokenSuccess();
  244. MockEchoResponseCallback response_callback;
  245. EXPECT_CALL(response_callback,
  246. Run(EqualsToStatus(ProtobufHttpStatus(
  247. ProtobufHttpStatus::Code::FAILED_PRECONDITION,
  248. "Unauthenticated error message")),
  249. IsNullResponse()))
  250. .WillOnce([&]() { run_loop.Quit(); });
  251. auto request = CreateDefaultTestRequest();
  252. request->SetResponseCallback(response_callback.Get());
  253. client_.ExecuteRequest(std::move(request));
  254. Status status_message;
  255. status_message.set_code(
  256. static_cast<int>(ProtobufHttpStatus::Code::FAILED_PRECONDITION));
  257. status_message.set_message("Unauthenticated error message");
  258. test_url_loader_factory_.AddResponse(
  259. kTestFullUrl, status_message.SerializeAsString(),
  260. net::HttpStatusCode::HTTP_INTERNAL_SERVER_ERROR);
  261. run_loop.Run();
  262. ASSERT_FALSE(client_.HasPendingRequests());
  263. }
  264. TEST_F(ProtobufHttpClientTest, ServerRespondsWithHttpErrorCode) {
  265. base::RunLoop run_loop;
  266. ExpectCallWithTokenSuccess();
  267. MockEchoResponseCallback response_callback;
  268. EXPECT_CALL(response_callback,
  269. Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED),
  270. IsNullResponse()))
  271. .WillOnce([&]() { run_loop.Quit(); });
  272. auto request = CreateDefaultTestRequest();
  273. request->SetResponseCallback(response_callback.Get());
  274. client_.ExecuteRequest(std::move(request));
  275. test_url_loader_factory_.AddResponse(kTestFullUrl, "",
  276. net::HttpStatusCode::HTTP_UNAUTHORIZED);
  277. run_loop.Run();
  278. ASSERT_FALSE(client_.HasPendingRequests());
  279. }
  280. TEST_F(ProtobufHttpClientTest,
  281. CancelPendingRequestsBeforeTokenCallback_CallbackNotCalled) {
  282. base::RunLoop run_loop;
  283. OAuthTokenGetter::TokenCallback token_callback;
  284. EXPECT_CALL(mock_token_getter_, CallWithToken(_))
  285. .WillOnce([&](OAuthTokenGetter::TokenCallback callback) {
  286. token_callback = std::move(callback);
  287. });
  288. MockEchoResponseCallback not_called_response_callback;
  289. auto request = CreateDefaultTestRequest();
  290. request->SetResponseCallback(not_called_response_callback.Get());
  291. client_.ExecuteRequest(std::move(request));
  292. client_.CancelPendingRequests();
  293. ASSERT_TRUE(token_callback);
  294. std::move(token_callback)
  295. .Run(OAuthTokenGetter::Status::SUCCESS, "", kFakeAccessToken);
  296. // Verify no request.
  297. ASSERT_FALSE(test_url_loader_factory_.IsPending(kTestFullUrl));
  298. ASSERT_FALSE(client_.HasPendingRequests());
  299. }
  300. TEST_F(ProtobufHttpClientTest,
  301. CancelPendingRequestsAfterTokenCallback_CallbackNotCalled) {
  302. base::RunLoop run_loop;
  303. ExpectCallWithTokenSuccess();
  304. client_.ExecuteRequest(CreateDefaultTestRequest());
  305. // Respond.
  306. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  307. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  308. client_.CancelPendingRequests();
  309. test_url_loader_factory_.AddResponse(kTestFullUrl,
  310. CreateSerializedEchoResponse());
  311. run_loop.RunUntilIdle();
  312. ASSERT_FALSE(client_.HasPendingRequests());
  313. }
  314. TEST_F(ProtobufHttpClientTest, RequestTimeout_ReturnsDeadlineExceeded) {
  315. base::RunLoop run_loop;
  316. ExpectCallWithTokenSuccess();
  317. MockEchoResponseCallback response_callback;
  318. EXPECT_CALL(response_callback,
  319. Run(HasErrorCode(ProtobufHttpStatus::Code::DEADLINE_EXCEEDED),
  320. IsNullResponse()))
  321. .WillOnce([&]() { run_loop.Quit(); });
  322. auto request = CreateDefaultTestRequest();
  323. request->SetTimeoutDuration(base::Seconds(15));
  324. request->SetResponseCallback(response_callback.Get());
  325. client_.ExecuteRequest(std::move(request));
  326. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  327. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  328. task_environment_.FastForwardBy(base::Seconds(16));
  329. run_loop.Run();
  330. ASSERT_FALSE(client_.HasPendingRequests());
  331. }
  332. TEST_F(ProtobufHttpClientTest, DeletesRequestHolderWhenRequestIsCanceled) {
  333. ExpectCallWithTokenSuccess();
  334. MockEchoResponseCallback never_called_response_callback;
  335. auto request = CreateDefaultTestRequest();
  336. request->SetResponseCallback(never_called_response_callback.Get());
  337. auto scoped_holder = request->CreateScopedRequest();
  338. client_.ExecuteRequest(std::move(request));
  339. // Verify request.
  340. ASSERT_TRUE(client_.HasPendingRequests());
  341. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  342. scoped_holder.reset();
  343. ASSERT_FALSE(test_url_loader_factory_.IsPending(kTestFullUrl));
  344. ASSERT_FALSE(client_.HasPendingRequests());
  345. // Try to respond.
  346. test_url_loader_factory_.AddResponse(kTestFullUrl,
  347. CreateSerializedEchoResponse());
  348. // |never_called_response_callback| should not be called.
  349. base::RunLoop().RunUntilIdle();
  350. }
  351. TEST_F(ProtobufHttpClientTest, DeletesRequestHolderAfterResponseIsReceived) {
  352. base::RunLoop run_loop;
  353. ExpectCallWithTokenSuccess();
  354. MockEchoResponseCallback response_callback;
  355. EXPECT_CALL(response_callback, Run(HasErrorCode(ProtobufHttpStatus::Code::OK),
  356. IsDefaultResponseText()))
  357. .WillOnce([&]() { run_loop.Quit(); });
  358. auto request = CreateDefaultTestRequest();
  359. request->SetResponseCallback(response_callback.Get());
  360. auto scoped_holder = request->CreateScopedRequest();
  361. client_.ExecuteRequest(std::move(request));
  362. // Verify request.
  363. ASSERT_TRUE(client_.HasPendingRequests());
  364. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  365. // Try to respond.
  366. test_url_loader_factory_.AddResponse(kTestFullUrl,
  367. CreateSerializedEchoResponse());
  368. run_loop.Run();
  369. ASSERT_FALSE(test_url_loader_factory_.IsPending(kTestFullUrl));
  370. ASSERT_FALSE(client_.HasPendingRequests());
  371. scoped_holder.reset();
  372. }
  373. // Stream request tests.
  374. TEST_F(ProtobufHttpClientTest,
  375. StreamRequestFailedToFetchAuthToken_RejectsWithUnauthorizedError) {
  376. base::MockOnceClosure stream_ready_callback;
  377. MockEchoMessageCallback message_callback;
  378. MockStreamClosedCallback stream_closed_callback;
  379. base::RunLoop run_loop;
  380. ExpectCallWithTokenAuthError();
  381. MockEchoResponseCallback response_callback;
  382. EXPECT_CALL(stream_closed_callback,
  383. Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED)))
  384. .WillOnce([&]() { run_loop.Quit(); });
  385. auto request = CreateDefaultTestStreamRequest();
  386. request->SetStreamReadyCallback(stream_ready_callback.Get());
  387. request->SetMessageCallback(message_callback.Get());
  388. request->SetStreamClosedCallback(stream_closed_callback.Get());
  389. client_.ExecuteRequest(std::move(request));
  390. run_loop.Run();
  391. ASSERT_FALSE(client_.HasPendingRequests());
  392. }
  393. TEST_F(ProtobufHttpClientTest,
  394. StreamRequestFailedToFetchAuthToken_RejectsWithUnavailableError) {
  395. base::MockOnceClosure stream_ready_callback;
  396. MockEchoMessageCallback message_callback;
  397. MockStreamClosedCallback stream_closed_callback;
  398. base::RunLoop run_loop;
  399. ExpectCallWithTokenNetworkError();
  400. MockEchoResponseCallback response_callback;
  401. EXPECT_CALL(stream_closed_callback,
  402. Run(HasErrorCode(ProtobufHttpStatus::Code::UNAVAILABLE)))
  403. .WillOnce([&]() { run_loop.Quit(); });
  404. auto request = CreateDefaultTestStreamRequest();
  405. request->SetStreamReadyCallback(stream_ready_callback.Get());
  406. request->SetMessageCallback(message_callback.Get());
  407. request->SetStreamClosedCallback(stream_closed_callback.Get());
  408. client_.ExecuteRequest(std::move(request));
  409. run_loop.Run();
  410. ASSERT_FALSE(client_.HasPendingRequests());
  411. }
  412. TEST_F(ProtobufHttpClientTest, StartStreamRequestAndDecodeMessages) {
  413. base::MockOnceClosure stream_ready_callback;
  414. MockEchoMessageCallback message_callback;
  415. MockStreamClosedCallback stream_closed_callback;
  416. {
  417. InSequence s;
  418. ExpectCallWithTokenSuccess();
  419. EXPECT_CALL(stream_ready_callback, Run());
  420. EXPECT_CALL(message_callback, Run(IsResponseText("response text 1")));
  421. EXPECT_CALL(message_callback, Run(IsResponseText("response text 2")));
  422. EXPECT_CALL(stream_closed_callback,
  423. Run(HasErrorCode(ProtobufHttpStatus::Code::CANCELLED)));
  424. }
  425. auto request = CreateDefaultTestStreamRequest();
  426. request->SetStreamReadyCallback(stream_ready_callback.Get());
  427. request->SetMessageCallback(message_callback.Get());
  428. request->SetStreamClosedCallback(stream_closed_callback.Get());
  429. network::SimpleURLLoaderStreamConsumer* stream_consumer = request.get();
  430. client_.ExecuteRequest(std::move(request));
  431. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  432. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  433. // TestURLLoaderFactory can't simulate streaming, so we invoke the request
  434. // directly.
  435. stream_consumer->OnDataReceived(
  436. CreateSerializedStreamBodyWithText("response text 1"), base::DoNothing());
  437. stream_consumer->OnDataReceived(
  438. CreateSerializedStreamBodyWithText("response text 2"), base::DoNothing());
  439. stream_consumer->OnDataReceived(CreateSerializedStreamBodyWithStatusCode(
  440. ProtobufHttpStatus::Code::CANCELLED),
  441. base::DoNothing());
  442. ASSERT_FALSE(client_.HasPendingRequests());
  443. }
  444. TEST_F(ProtobufHttpClientTest, InvalidStreamData_Ignored) {
  445. base::RunLoop run_loop;
  446. base::MockOnceClosure stream_ready_callback;
  447. MockEchoMessageCallback not_called_message_callback;
  448. MockStreamClosedCallback stream_closed_callback;
  449. {
  450. InSequence s;
  451. ExpectCallWithTokenSuccess();
  452. EXPECT_CALL(stream_ready_callback, Run());
  453. EXPECT_CALL(stream_closed_callback,
  454. Run(HasErrorCode(ProtobufHttpStatus::Code::OK)))
  455. .WillOnce([&]() { run_loop.Quit(); });
  456. }
  457. auto request = CreateDefaultTestStreamRequest();
  458. request->SetStreamReadyCallback(stream_ready_callback.Get());
  459. request->SetMessageCallback(not_called_message_callback.Get());
  460. request->SetStreamClosedCallback(stream_closed_callback.Get());
  461. client_.ExecuteRequest(std::move(request));
  462. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  463. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  464. test_url_loader_factory_.AddResponse(kTestFullUrl, "Invalid stream data",
  465. net::HttpStatusCode::HTTP_OK);
  466. run_loop.Run();
  467. ASSERT_FALSE(client_.HasPendingRequests());
  468. }
  469. TEST_F(ProtobufHttpClientTest, SendHttpStatusOnly_StreamClosesWithHttpStatus) {
  470. base::RunLoop run_loop;
  471. base::MockOnceClosure stream_ready_callback;
  472. MockStreamClosedCallback stream_closed_callback;
  473. {
  474. InSequence s;
  475. ExpectCallWithTokenSuccess();
  476. EXPECT_CALL(stream_closed_callback,
  477. Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED)))
  478. .WillOnce([&]() { run_loop.Quit(); });
  479. }
  480. auto request = CreateDefaultTestStreamRequest();
  481. request->SetStreamReadyCallback(stream_ready_callback.Get());
  482. request->SetStreamClosedCallback(stream_closed_callback.Get());
  483. client_.ExecuteRequest(std::move(request));
  484. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  485. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  486. test_url_loader_factory_.AddResponse(kTestFullUrl, /* response_body= */ "",
  487. net::HttpStatusCode::HTTP_UNAUTHORIZED);
  488. run_loop.Run();
  489. ASSERT_FALSE(client_.HasPendingRequests());
  490. }
  491. TEST_F(ProtobufHttpClientTest, SendStreamStatusAndHttpStatus_StreamStatusWins) {
  492. base::RunLoop run_loop;
  493. base::MockOnceClosure stream_ready_callback;
  494. MockStreamClosedCallback stream_closed_callback;
  495. {
  496. InSequence s;
  497. ExpectCallWithTokenSuccess();
  498. EXPECT_CALL(stream_ready_callback, Run());
  499. EXPECT_CALL(stream_closed_callback,
  500. Run(HasErrorCode(ProtobufHttpStatus::Code::CANCELLED)))
  501. .WillOnce([&]() { run_loop.Quit(); });
  502. }
  503. auto request = CreateDefaultTestStreamRequest();
  504. request->SetStreamReadyCallback(stream_ready_callback.Get());
  505. request->SetStreamClosedCallback(stream_closed_callback.Get());
  506. client_.ExecuteRequest(std::move(request));
  507. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  508. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  509. test_url_loader_factory_.AddResponse(kTestFullUrl,
  510. CreateSerializedStreamBodyWithStatusCode(
  511. ProtobufHttpStatus::Code::CANCELLED),
  512. net::HttpStatusCode::HTTP_OK);
  513. run_loop.Run();
  514. ASSERT_FALSE(client_.HasPendingRequests());
  515. }
  516. TEST_F(ProtobufHttpClientTest, StreamReadyTimeout) {
  517. base::MockOnceClosure not_called_stream_ready_callback;
  518. MockEchoMessageCallback not_called_message_callback;
  519. MockStreamClosedCallback stream_closed_callback;
  520. {
  521. InSequence s;
  522. ExpectCallWithTokenSuccess();
  523. EXPECT_CALL(stream_closed_callback,
  524. Run(HasErrorCode(ProtobufHttpStatus::Code::DEADLINE_EXCEEDED)));
  525. }
  526. auto request = CreateDefaultTestStreamRequest();
  527. request->SetStreamReadyCallback(not_called_stream_ready_callback.Get());
  528. request->SetMessageCallback(not_called_message_callback.Get());
  529. request->SetStreamClosedCallback(stream_closed_callback.Get());
  530. client_.ExecuteRequest(std::move(request));
  531. ASSERT_TRUE(client_.HasPendingRequests());
  532. ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl));
  533. ASSERT_EQ(1, test_url_loader_factory_.NumPending());
  534. task_environment_.FastForwardBy(
  535. ProtobufHttpStreamRequest::kStreamReadyTimeoutDuration +
  536. base::Seconds(1));
  537. ASSERT_FALSE(client_.HasPendingRequests());
  538. }
  539. } // namespace remoting