| // Copyright 2020 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/base/protobuf_http_client.h" |
| |
| #include <memory> |
| |
| #include "base/callback_helpers.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind.h" |
| #include "base/test/gmock_callback_support.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/task_environment.h" |
| #include "net/http/http_status_code.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "remoting/base/protobuf_http_client_messages.pb.h" |
| #include "remoting/base/protobuf_http_client_test_messages.pb.h" |
| #include "remoting/base/protobuf_http_request.h" |
| #include "remoting/base/protobuf_http_request_config.h" |
| #include "remoting/base/protobuf_http_status.h" |
| #include "remoting/base/protobuf_http_stream_request.h" |
| #include "services/network/public/cpp/shared_url_loader_factory.h" |
| #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h" |
| #include "services/network/test/test_url_loader_factory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| using protobufhttpclient::Status; |
| using protobufhttpclient::StreamBody; |
| using protobufhttpclienttest::EchoRequest; |
| using protobufhttpclienttest::EchoResponse; |
| |
| using ::base::test::RunOnceCallback; |
| using ::testing::_; |
| using ::testing::InSequence; |
| |
| using EchoResponseCallback = |
| ProtobufHttpRequest::ResponseCallback<EchoResponse>; |
| using MockEchoResponseCallback = base::MockCallback<EchoResponseCallback>; |
| using MockEchoMessageCallback = base::MockCallback< |
| ProtobufHttpStreamRequest::MessageCallback<EchoResponse>>; |
| using MockStreamClosedCallback = |
| base::MockCallback<ProtobufHttpStreamRequest::StreamClosedCallback>; |
| |
| constexpr char kTestServerEndpoint[] = "test.com"; |
| constexpr char kTestRpcPath[] = "/v1/echo:echo"; |
| constexpr char kTestFullUrl[] = "https://test.com/v1/echo:echo"; |
| constexpr char kRequestText[] = "This is a request"; |
| constexpr char kResponseText[] = "This is a response"; |
| constexpr char kAuthorizationHeaderKey[] = "Authorization"; |
| constexpr char kFakeAccessToken[] = "fake_access_token"; |
| constexpr char kFakeAccessTokenHeaderValue[] = "Bearer fake_access_token"; |
| |
| MATCHER_P(HasErrorCode, error_code, "") { |
| return arg.error_code() == error_code; |
| } |
| |
| MATCHER_P(EqualsToStatus, expected_status, "") { |
| return arg.error_code() == expected_status.error_code() && |
| arg.error_message() == expected_status.error_message(); |
| } |
| |
| MATCHER(IsDefaultResponseText, "") { |
| return arg->text() == kResponseText; |
| } |
| |
| MATCHER_P(IsResponseText, response_text, "") { |
| return arg->text() == response_text; |
| } |
| |
| MATCHER(IsNullResponse, "") { |
| return arg.get() == nullptr; |
| } |
| |
| class MockOAuthTokenGetter : public OAuthTokenGetter { |
| public: |
| MOCK_METHOD1(CallWithToken, void(TokenCallback)); |
| MOCK_METHOD0(InvalidateCache, void()); |
| }; |
| |
| EchoResponseCallback DoNothingResponse() { |
| return base::DoNothing::Once<const ProtobufHttpStatus&, |
| std::unique_ptr<EchoResponse>>(); |
| } |
| |
| std::unique_ptr<ProtobufHttpRequestConfig> CreateDefaultRequestConfig() { |
| auto request_message = std::make_unique<EchoRequest>(); |
| request_message->set_text(kRequestText); |
| auto request_config = |
| std::make_unique<ProtobufHttpRequestConfig>(TRAFFIC_ANNOTATION_FOR_TESTS); |
| request_config->request_message = std::move(request_message); |
| request_config->path = kTestRpcPath; |
| return request_config; |
| } |
| |
| std::unique_ptr<ProtobufHttpRequest> CreateDefaultTestRequest() { |
| auto request = |
| std::make_unique<ProtobufHttpRequest>(CreateDefaultRequestConfig()); |
| request->SetResponseCallback(DoNothingResponse()); |
| return request; |
| } |
| |
| std::unique_ptr<ProtobufHttpStreamRequest> CreateDefaultTestStreamRequest() { |
| auto request = |
| std::make_unique<ProtobufHttpStreamRequest>(CreateDefaultRequestConfig()); |
| request->SetStreamReadyCallback(base::DoNothing::Once()); |
| request->SetStreamClosedCallback( |
| base::DoNothing::Once<const ProtobufHttpStatus&>()); |
| request->SetMessageCallback( |
| base::DoNothing::Repeatedly<std::unique_ptr<EchoResponse>>()); |
| return request; |
| } |
| |
| std::string CreateSerializedEchoResponse( |
| const std::string& text = kResponseText) { |
| EchoResponse response; |
| response.set_text(text); |
| return response.SerializeAsString(); |
| } |
| |
| std::string CreateSerializedStreamBodyWithText( |
| const std::string& text = kResponseText) { |
| StreamBody stream_body; |
| stream_body.add_messages(CreateSerializedEchoResponse(text)); |
| return stream_body.SerializeAsString(); |
| } |
| |
| std::string CreateSerializedStreamBodyWithStatusCode( |
| ProtobufHttpStatus::Code status_code) { |
| StreamBody stream_body; |
| stream_body.mutable_status()->set_code(static_cast<int32_t>(status_code)); |
| return stream_body.SerializeAsString(); |
| } |
| |
| } // namespace |
| |
| class ProtobufHttpClientTest : public testing::Test { |
| protected: |
| void ExpectCallWithTokenSuccess(); |
| void ExpectCallWithTokenAuthError(); |
| void ExpectCallWithTokenNetworkError(); |
| |
| base::test::SingleThreadTaskEnvironment task_environment_{ |
| base::test::TaskEnvironment::TimeSource::MOCK_TIME}; |
| MockOAuthTokenGetter mock_token_getter_; |
| network::TestURLLoaderFactory test_url_loader_factory_; |
| scoped_refptr<network::SharedURLLoaderFactory> test_shared_loader_factory_ = |
| base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>( |
| &test_url_loader_factory_); |
| ProtobufHttpClient client_{kTestServerEndpoint, &mock_token_getter_, |
| test_shared_loader_factory_}; |
| }; |
| |
| void ProtobufHttpClientTest::ExpectCallWithTokenSuccess() { |
| EXPECT_CALL(mock_token_getter_, CallWithToken(_)) |
| .WillOnce(RunOnceCallback<0>(OAuthTokenGetter::Status::SUCCESS, "", |
| kFakeAccessToken)); |
| } |
| |
| void ProtobufHttpClientTest::ExpectCallWithTokenAuthError() { |
| EXPECT_CALL(mock_token_getter_, CallWithToken(_)) |
| .WillOnce( |
| RunOnceCallback<0>(OAuthTokenGetter::Status::AUTH_ERROR, "", "")); |
| } |
| |
| void ProtobufHttpClientTest::ExpectCallWithTokenNetworkError() { |
| EXPECT_CALL(mock_token_getter_, CallWithToken(_)) |
| .WillOnce( |
| RunOnceCallback<0>(OAuthTokenGetter::Status::NETWORK_ERROR, "", "")); |
| } |
| |
| // Unary request tests. |
| |
| TEST_F(ProtobufHttpClientTest, SendRequestAndDecodeResponse) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, Run(HasErrorCode(ProtobufHttpStatus::Code::OK), |
| IsDefaultResponseText())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| // Verify request. |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| auto* pending_request = test_url_loader_factory_.GetPendingRequest(0); |
| std::string auth_header; |
| ASSERT_TRUE(pending_request->request.headers.GetHeader( |
| kAuthorizationHeaderKey, &auth_header)); |
| ASSERT_EQ(kFakeAccessTokenHeaderValue, auth_header); |
| const auto& data_element = |
| pending_request->request.request_body->elements()->front(); |
| ASSERT_EQ(data_element.type(), network::DataElement::Tag::kBytes); |
| std::string request_body_data( |
| data_element.As<network::DataElementBytes>().AsStringPiece()); |
| EchoRequest request_message; |
| ASSERT_TRUE(request_message.ParseFromString(request_body_data)); |
| ASSERT_EQ(kRequestText, request_message.text()); |
| |
| // Respond. |
| test_url_loader_factory_.AddResponse(kTestFullUrl, |
| CreateSerializedEchoResponse()); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, |
| SendUnauthenticatedRequest_TokenGetterNotCalled) { |
| EXPECT_CALL(mock_token_getter_, CallWithToken(_)).Times(0); |
| |
| auto request_config = CreateDefaultRequestConfig(); |
| request_config->authenticated = false; |
| auto request = |
| std::make_unique<ProtobufHttpRequest>(std::move(request_config)); |
| request->SetResponseCallback(DoNothingResponse()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| // Verify that the request is sent with no auth header. |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| auto* pending_request = test_url_loader_factory_.GetPendingRequest(0); |
| ASSERT_FALSE( |
| pending_request->request.headers.HasHeader(kAuthorizationHeaderKey)); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, |
| FailedToFetchAuthToken_RejectsWithUnauthorizedError) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenAuthError(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED), |
| IsNullResponse())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, |
| FailedToFetchAuthToken_RejectsWithUnavailableError) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenNetworkError(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::UNAVAILABLE), |
| IsNullResponse())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, FailedToParseResponse_GetsInvalidResponseError) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL( |
| response_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::INTERNAL), IsNullResponse())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| // Respond. |
| test_url_loader_factory_.AddResponse(kTestFullUrl, "Invalid content"); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, ServerRespondsWithErrorStatusMessage) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, |
| Run(EqualsToStatus(ProtobufHttpStatus( |
| ProtobufHttpStatus::Code::FAILED_PRECONDITION, |
| "Unauthenticated error message")), |
| IsNullResponse())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| Status status_message; |
| status_message.set_code( |
| static_cast<int>(ProtobufHttpStatus::Code::FAILED_PRECONDITION)); |
| status_message.set_message("Unauthenticated error message"); |
| |
| test_url_loader_factory_.AddResponse( |
| kTestFullUrl, status_message.SerializeAsString(), |
| net::HttpStatusCode::HTTP_INTERNAL_SERVER_ERROR); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, ServerRespondsWithHttpErrorCode) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED), |
| IsNullResponse())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| test_url_loader_factory_.AddResponse(kTestFullUrl, "", |
| net::HttpStatusCode::HTTP_UNAUTHORIZED); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, |
| CancelPendingRequestsBeforeTokenCallback_CallbackNotCalled) { |
| base::RunLoop run_loop; |
| |
| OAuthTokenGetter::TokenCallback token_callback; |
| EXPECT_CALL(mock_token_getter_, CallWithToken(_)) |
| .WillOnce([&](OAuthTokenGetter::TokenCallback callback) { |
| token_callback = std::move(callback); |
| }); |
| |
| MockEchoResponseCallback not_called_response_callback; |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(not_called_response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| client_.CancelPendingRequests(); |
| ASSERT_TRUE(token_callback); |
| std::move(token_callback) |
| .Run(OAuthTokenGetter::Status::SUCCESS, "", kFakeAccessToken); |
| |
| // Verify no request. |
| ASSERT_FALSE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, |
| CancelPendingRequestsAfterTokenCallback_CallbackNotCalled) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| client_.ExecuteRequest(CreateDefaultTestRequest()); |
| |
| // Respond. |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| client_.CancelPendingRequests(); |
| test_url_loader_factory_.AddResponse(kTestFullUrl, |
| CreateSerializedEchoResponse()); |
| run_loop.RunUntilIdle(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, RequestTimeout_ReturnsDeadlineExceeded) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::DEADLINE_EXCEEDED), |
| IsNullResponse())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetTimeoutDuration(base::TimeDelta::FromSeconds(15)); |
| request->SetResponseCallback(response_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| |
| task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(16)); |
| |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, DeletesRequestHolderWhenRequestIsCanceled) { |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback never_called_response_callback; |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(never_called_response_callback.Get()); |
| auto scoped_holder = request->CreateScopedRequest(); |
| client_.ExecuteRequest(std::move(request)); |
| |
| // Verify request. |
| ASSERT_TRUE(client_.HasPendingRequests()); |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| scoped_holder.reset(); |
| ASSERT_FALSE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| |
| // Try to respond. |
| test_url_loader_factory_.AddResponse(kTestFullUrl, |
| CreateSerializedEchoResponse()); |
| // |never_called_response_callback| should not be called. |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, DeletesRequestHolderAfterResponseIsReceived) { |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenSuccess(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(response_callback, Run(HasErrorCode(ProtobufHttpStatus::Code::OK), |
| IsDefaultResponseText())) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestRequest(); |
| request->SetResponseCallback(response_callback.Get()); |
| auto scoped_holder = request->CreateScopedRequest(); |
| client_.ExecuteRequest(std::move(request)); |
| |
| // Verify request. |
| ASSERT_TRUE(client_.HasPendingRequests()); |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| |
| // Try to respond. |
| test_url_loader_factory_.AddResponse(kTestFullUrl, |
| CreateSerializedEchoResponse()); |
| run_loop.Run(); |
| |
| ASSERT_FALSE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| scoped_holder.reset(); |
| } |
| |
| // Stream request tests. |
| |
| TEST_F(ProtobufHttpClientTest, |
| StreamRequestFailedToFetchAuthToken_RejectsWithUnauthorizedError) { |
| base::MockOnceClosure stream_ready_callback; |
| MockEchoMessageCallback message_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenAuthError(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED))) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(stream_ready_callback.Get()); |
| request->SetMessageCallback(message_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, |
| StreamRequestFailedToFetchAuthToken_RejectsWithUnavailableError) { |
| base::MockOnceClosure stream_ready_callback; |
| MockEchoMessageCallback message_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| base::RunLoop run_loop; |
| |
| ExpectCallWithTokenNetworkError(); |
| |
| MockEchoResponseCallback response_callback; |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::UNAVAILABLE))) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(stream_ready_callback.Get()); |
| request->SetMessageCallback(message_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, StartStreamRequestAndDecodeMessages) { |
| base::MockOnceClosure stream_ready_callback; |
| MockEchoMessageCallback message_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| { |
| InSequence s; |
| |
| ExpectCallWithTokenSuccess(); |
| EXPECT_CALL(stream_ready_callback, Run()); |
| EXPECT_CALL(message_callback, Run(IsResponseText("response text 1"))); |
| EXPECT_CALL(message_callback, Run(IsResponseText("response text 2"))); |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::CANCELLED))); |
| } |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(stream_ready_callback.Get()); |
| request->SetMessageCallback(message_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| network::SimpleURLLoaderStreamConsumer* stream_consumer = request.get(); |
| client_.ExecuteRequest(std::move(request)); |
| |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| |
| // TestURLLoaderFactory can't simulate streaming, so we invoke the request |
| // directly. |
| stream_consumer->OnDataReceived( |
| CreateSerializedStreamBodyWithText("response text 1"), |
| base::DoNothing::Once()); |
| stream_consumer->OnDataReceived( |
| CreateSerializedStreamBodyWithText("response text 2"), |
| base::DoNothing::Once()); |
| stream_consumer->OnDataReceived(CreateSerializedStreamBodyWithStatusCode( |
| ProtobufHttpStatus::Code::CANCELLED), |
| base::DoNothing::Once()); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, InvalidStreamData_Ignored) { |
| base::RunLoop run_loop; |
| base::MockOnceClosure stream_ready_callback; |
| MockEchoMessageCallback not_called_message_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| { |
| InSequence s; |
| |
| ExpectCallWithTokenSuccess(); |
| EXPECT_CALL(stream_ready_callback, Run()); |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::OK))) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| } |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(stream_ready_callback.Get()); |
| request->SetMessageCallback(not_called_message_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| test_url_loader_factory_.AddResponse(kTestFullUrl, "Invalid stream data", |
| net::HttpStatusCode::HTTP_OK); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, SendHttpStatusOnly_StreamClosesWithHttpStatus) { |
| base::RunLoop run_loop; |
| base::MockOnceClosure stream_ready_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| { |
| InSequence s; |
| |
| ExpectCallWithTokenSuccess(); |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::UNAUTHENTICATED))) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| } |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(stream_ready_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| test_url_loader_factory_.AddResponse(kTestFullUrl, /* response_body= */ "", |
| net::HttpStatusCode::HTTP_UNAUTHORIZED); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, SendStreamStatusAndHttpStatus_StreamStatusWins) { |
| base::RunLoop run_loop; |
| base::MockOnceClosure stream_ready_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| { |
| InSequence s; |
| |
| ExpectCallWithTokenSuccess(); |
| EXPECT_CALL(stream_ready_callback, Run()); |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::CANCELLED))) |
| .WillOnce([&]() { run_loop.Quit(); }); |
| } |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(stream_ready_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| test_url_loader_factory_.AddResponse(kTestFullUrl, |
| CreateSerializedStreamBodyWithStatusCode( |
| ProtobufHttpStatus::Code::CANCELLED), |
| net::HttpStatusCode::HTTP_OK); |
| run_loop.Run(); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| TEST_F(ProtobufHttpClientTest, StreamReadyTimeout) { |
| base::MockOnceClosure not_called_stream_ready_callback; |
| MockEchoMessageCallback not_called_message_callback; |
| MockStreamClosedCallback stream_closed_callback; |
| |
| { |
| InSequence s; |
| |
| ExpectCallWithTokenSuccess(); |
| EXPECT_CALL(stream_closed_callback, |
| Run(HasErrorCode(ProtobufHttpStatus::Code::DEADLINE_EXCEEDED))); |
| } |
| |
| auto request = CreateDefaultTestStreamRequest(); |
| request->SetStreamReadyCallback(not_called_stream_ready_callback.Get()); |
| request->SetMessageCallback(not_called_message_callback.Get()); |
| request->SetStreamClosedCallback(stream_closed_callback.Get()); |
| client_.ExecuteRequest(std::move(request)); |
| |
| ASSERT_TRUE(client_.HasPendingRequests()); |
| ASSERT_TRUE(test_url_loader_factory_.IsPending(kTestFullUrl)); |
| ASSERT_EQ(1, test_url_loader_factory_.NumPending()); |
| |
| task_environment_.FastForwardBy( |
| ProtobufHttpStreamRequest::kStreamReadyTimeoutDuration + |
| base::TimeDelta::FromSeconds(1)); |
| ASSERT_FALSE(client_.HasPendingRequests()); |
| } |
| |
| } // namespace remoting |