123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711 |
- // Copyright 2018 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 "components/cast_channel/cast_message_handler.h"
- #include <string>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/json/json_reader.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/strings/stringprintf.h"
- #include "base/test/mock_callback.h"
- #include "base/test/task_environment.h"
- #include "base/test/test_simple_task_runner.h"
- #include "base/test/values_test_util.h"
- #include "components/cast_channel/cast_message_util.h"
- #include "components/cast_channel/cast_test_util.h"
- #include "content/public/test/browser_task_environment.h"
- #include "services/data_decoder/public/cpp/data_decoder.h"
- #include "services/data_decoder/public/cpp/test_support/in_process_data_decoder.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- using base::test::IsJson;
- using base::test::ParseJson;
- using testing::_;
- using testing::AnyNumber;
- using testing::InSequence;
- using testing::Return;
- using testing::SaveArg;
- using testing::WithArg;
- namespace cast_channel {
- namespace {
- constexpr char kAppId1[] = "0F5096E8";
- constexpr char kAppId2[] = "85CDB22F";
- constexpr char kTestUserAgentString[] =
- "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) "
- "Chrome/66.0.3331.0 Safari/537.36";
- constexpr char kSessionId[] = "theSessionId";
- constexpr char kSourceId[] = "theSourceId";
- constexpr char kDestinationId[] = "theDestinationId";
- constexpr char kAppParams[] = R"(
- {
- "requiredFeatures" : ["STREAM_TRANSFER"],
- "launchCheckerParams" : {
- "credentialsData" : {
- "credentialsType" : "mobile",
- "credentials" : "99843n2idsguyhga"
- }
- }
- }
- )";
- constexpr int kMaxProtocolMessageSize = 64 * 1024;
- data_decoder::DataDecoder::ValueOrError ParseJsonLikeDataDecoder(
- base::StringPiece json) {
- return ParseJson(json);
- }
- absl::optional<base::Value::Dict> GetDictionaryFromCastMessage(
- const CastMessage& message) {
- if (!message.has_payload_utf8())
- return absl::nullopt;
- absl::optional<base::Value> value =
- base::JSONReader::Read(message.payload_utf8());
- if (!value || !value->is_dict())
- return absl::nullopt;
- return std::move(value->GetDict());
- }
- CastMessageType GetMessageType(const CastMessage& message) {
- absl::optional<base::Value::Dict> dict =
- GetDictionaryFromCastMessage(message);
- if (!dict)
- return CastMessageType::kOther;
- const std::string* message_type = dict->FindString("type");
- if (!message_type)
- return CastMessageType::kOther;
- return CastMessageTypeFromString(*message_type);
- }
- MATCHER_P(HasMessageType, type, "") {
- return GetMessageType(arg) == type;
- }
- MATCHER_P(HasPayloadUtf8, payload, "") {
- return arg.payload_utf8() == payload;
- }
- } // namespace
- class CastMessageHandlerTest : public testing::Test {
- public:
- CastMessageHandlerTest()
- : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME),
- cast_socket_service_(new base::TestSimpleTaskRunner()),
- handler_(
- &cast_socket_service_,
- base::BindRepeating(&data_decoder::DataDecoder::ParseJsonIsolated),
- kTestUserAgentString,
- "66.0.3331.0",
- "en-US") {
- ON_CALL(cast_socket_service_, GetSocket(testing::Matcher<int>(_)))
- .WillByDefault(testing::Return(&cast_socket_));
- }
- CastMessageHandlerTest(const CastMessageHandlerTest&) = delete;
- CastMessageHandlerTest& operator=(const CastMessageHandlerTest&) = delete;
- ~CastMessageHandlerTest() override = default;
- void OnMessage(const CastMessage& message) {
- handler_.OnMessage(cast_socket_, message);
- }
- void OnError(ChannelError error) { handler_.OnError(cast_socket_, error); }
- void OnAppAvailability(const std::string& app_id,
- GetAppAvailabilityResult result) {
- if (run_loop_)
- run_loop_->Quit();
- DoOnAppAvailability(app_id, result);
- }
- MOCK_METHOD2(DoOnAppAvailability,
- void(const std::string& app_id,
- GetAppAvailabilityResult result));
- void ExpectSessionLaunchResult(LaunchSessionResponse::Result expected_result,
- LaunchSessionResponse response) {
- if (run_loop_)
- run_loop_->Quit();
- ++session_launch_response_count_;
- EXPECT_EQ(expected_result, response.result);
- if (response.result == LaunchSessionResponse::Result::kOk)
- EXPECT_TRUE(response.receiver_status);
- }
- void ExpectEnsureConnection() {
- EXPECT_CALL(*transport_,
- SendMessage_(HasMessageType(CastMessageType::kConnect), _));
- }
- void ExpectEnsureConnectionThen(CastMessageType next_type,
- int request_count = 1) {
- InSequence dummy;
- ExpectEnsureConnection();
- EXPECT_CALL(*transport_, SendMessage_(HasMessageType(next_type), _))
- .Times(request_count)
- .WillRepeatedly(SaveArg<0>(&last_request_));
- }
- void CreatePendingRequests() {
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
- handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(),
- {"WEB"}, /* appParams */ absl::nullopt,
- launch_session_callback_.Get());
- for (int i = 0; i < 2; i++) {
- handler_.RequestAppAvailability(&cast_socket_, kAppId1,
- get_app_availability_callback_.Get());
- handler_.SendSetVolumeRequest(
- channel_id_,
- ParseJson(R"({"sessionId": "theSessionId", "type": "SET_VOLUME"})"),
- kSourceId, set_volume_callback_.Get());
- }
- handler_.StopSession(channel_id_, kSessionId, kSourceId,
- stop_session_callback_.Get());
- }
- void SendMessageAndExpectConnection(const std::string& destination_id,
- VirtualConnectionType connection_type) {
- CastMessage message = CreateCastMessage(
- "namespace", base::Value(base::Value::Type::DICTIONARY), kSourceId,
- destination_id);
- {
- InSequence dummy;
- // We should first send a CONNECT request to ensure a connection.
- EXPECT_CALL(*transport_,
- SendMessage_(HasMessageType(CastMessageType::kConnect), _))
- .WillOnce(WithArg<0>([&](const CastMessage& message) {
- absl::optional<base::Value::Dict> dict =
- GetDictionaryFromCastMessage(message);
- EXPECT_EQ(connection_type, dict->FindInt("connType").value());
- }));
- // Then we send the actual message.
- EXPECT_CALL(*transport_, SendMessage_(_, _));
- }
- EXPECT_EQ(Result::kOk, handler_.SendAppMessage(channel_id_, message));
- }
- void HandlePendingLaunchSessionRequest(int request_id) {
- handler_.HandleCastInternalMessage(channel_id_, kSourceId, kDestinationId,
- "theNamespace",
- ParseJsonLikeDataDecoder(R"(
- {
- "requestId": )" + base::NumberToString(request_id) + R"(,
- "type": "RECEIVER_STATUS",
- "status": {"foo": "bar"},
- })"));
- }
- void HandlePendingGeneralRequest(int request_id) {
- handler_.HandleCastInternalMessage(channel_id_, kSourceId, kDestinationId,
- "theNamespace",
- ParseJsonLikeDataDecoder(R"(
- {
- "requestId": )" + base::NumberToString(request_id) + R"(
- })"));
- }
- void HandleAppAvailabilityRequest(int request_id) {
- handler_.HandleCastInternalMessage(channel_id_, kSourceId, kDestinationId,
- "theNamespace",
- ParseJsonLikeDataDecoder(R"(
- {
- "requestId": )" + base::NumberToString(request_id) + R"(,
- "availability": {")" + kAppId1 + R"(": "APP_AVAILABLE"},
- })"));
- }
- protected:
- content::BrowserTaskEnvironment task_environment_;
- std::unique_ptr<base::RunLoop> run_loop_;
- testing::NiceMock<MockCastSocketService> cast_socket_service_;
- data_decoder::test::InProcessDataDecoder in_process_data_decoder_;
- CastMessageHandler handler_;
- MockCastSocket cast_socket_;
- const int channel_id_ = cast_socket_.id();
- const raw_ptr<MockCastTransport> transport_ = cast_socket_.mock_transport();
- int session_launch_response_count_ = 0;
- CastMessage last_request_;
- base::MockCallback<LaunchSessionCallback> launch_session_callback_;
- base::MockCallback<GetAppAvailabilityCallback> get_app_availability_callback_;
- base::MockCallback<ResultCallback> set_volume_callback_;
- base::MockCallback<ResultCallback> stop_session_callback_;
- };
- TEST_F(CastMessageHandlerTest, VirtualConnectionCreatedOnlyOnce) {
- ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability, 2);
- handler_.RequestAppAvailability(
- &cast_socket_, kAppId1,
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- handler_.RequestAppAvailability(
- &cast_socket_, kAppId2,
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- }
- TEST_F(CastMessageHandlerTest, RecreateVirtualConnectionAfterError) {
- ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability);
- handler_.RequestAppAvailability(
- &cast_socket_, kAppId1,
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- EXPECT_CALL(*this,
- DoOnAppAvailability(kAppId1, GetAppAvailabilityResult::kUnknown));
- OnError(ChannelError::TRANSPORT_ERROR);
- ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability);
- handler_.RequestAppAvailability(
- &cast_socket_, kAppId2,
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- // The callback is invoked with kUnknown before the PendingRequests is
- // destroyed.
- EXPECT_CALL(*this,
- DoOnAppAvailability(kAppId2, GetAppAvailabilityResult::kUnknown));
- }
- TEST_F(CastMessageHandlerTest, RequestAppAvailability) {
- ExpectEnsureConnectionThen(CastMessageType::kGetAppAvailability);
- handler_.RequestAppAvailability(
- &cast_socket_, "ABCDEFAB",
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- absl::optional<base::Value::Dict> dict =
- GetDictionaryFromCastMessage(last_request_);
- ASSERT_TRUE(dict);
- const absl::optional<int> request_id_value = dict->FindInt("requestId");
- ASSERT_TRUE(request_id_value);
- int request_id = *request_id_value;
- EXPECT_GT(request_id, 0);
- CastMessage response;
- response.set_namespace_("urn:x-cast:com.google.cast.receiver");
- response.set_source_id("receiver-0");
- response.set_destination_id(handler_.sender_id());
- response.set_payload_type(
- CastMessage::PayloadType::CastMessage_PayloadType_STRING);
- response.set_payload_utf8(
- base::StringPrintf("{\"requestId\": %d, \"availability\": {\"ABCDEFAB\": "
- "\"APP_AVAILABLE\"}}",
- request_id));
- run_loop_ = std::make_unique<base::RunLoop>();
- EXPECT_CALL(*this, DoOnAppAvailability("ABCDEFAB",
- GetAppAvailabilityResult::kAvailable));
- OnMessage(response);
- run_loop_->Run();
- }
- TEST_F(CastMessageHandlerTest, RequestAppAvailabilityTimesOut) {
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(2);
- handler_.RequestAppAvailability(
- &cast_socket_, "ABCDEFAB",
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- EXPECT_CALL(*this, DoOnAppAvailability("ABCDEFAB",
- GetAppAvailabilityResult::kUnknown));
- task_environment_.FastForwardBy(base::Seconds(5));
- }
- TEST_F(CastMessageHandlerTest, AppAvailabilitySentOnlyOnceWhilePending) {
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(2);
- handler_.RequestAppAvailability(
- &cast_socket_, "ABCDEFAB",
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(0);
- handler_.RequestAppAvailability(
- &cast_socket_, "ABCDEFAB",
- base::BindOnce(&CastMessageHandlerTest::OnAppAvailability,
- base::Unretained(this)));
- }
- TEST_F(CastMessageHandlerTest, EnsureConnection) {
- ExpectEnsureConnection();
- handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
- VirtualConnectionType::kStrong);
- // No-op because connection is already created the first time.
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(0);
- handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
- VirtualConnectionType::kStrong);
- }
- TEST_F(CastMessageHandlerTest, CloseConnection) {
- ExpectEnsureConnection();
- handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
- VirtualConnectionType::kStrong);
- EXPECT_CALL(
- *transport_,
- SendMessage_(HasMessageType(CastMessageType::kCloseConnection), _));
- handler_.CloseConnection(channel_id_, kSourceId, kDestinationId);
- // Re-open virtual connection should cause CONNECT message to be sent.
- ExpectEnsureConnection();
- handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
- VirtualConnectionType::kStrong);
- }
- TEST_F(CastMessageHandlerTest, CloseConnectionFromReceiver) {
- ExpectEnsureConnection();
- handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
- VirtualConnectionType::kStrong);
- CastMessage response;
- response.set_namespace_("urn:x-cast:com.google.cast.tp.connection");
- response.set_source_id(kDestinationId);
- response.set_destination_id(kSourceId);
- response.set_payload_type(
- CastMessage::PayloadType::CastMessage_PayloadType_STRING);
- response.set_payload_utf8(R"({
- "type": "CLOSE"
- })");
- OnMessage(response);
- // Wait for message to be parsed and handled.
- task_environment_.RunUntilIdle();
- // Re-open virtual connection should cause message to be sent.
- EXPECT_CALL(*transport_, SendMessage_(_, _));
- handler_.EnsureConnection(channel_id_, kSourceId, kDestinationId,
- VirtualConnectionType::kStrong);
- }
- TEST_F(CastMessageHandlerTest, LaunchSession) {
- ExpectEnsureConnectionThen(CastMessageType::kLaunch);
- const absl::optional<base::Value> json = base::JSONReader::Read(kAppParams);
- handler_.LaunchSession(
- channel_id_, kAppId1, base::Seconds(30), {"WEB"}, json,
- base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
- base::Unretained(this),
- LaunchSessionResponse::Result::kOk));
- absl::optional<base::Value::Dict> dict =
- GetDictionaryFromCastMessage(last_request_);
- ASSERT_TRUE(dict);
- const absl::optional<int> request_id_value = dict->FindInt("requestId");
- ASSERT_TRUE(request_id_value);
- int request_id = *request_id_value;
- EXPECT_GT(request_id, 0);
- const base::Value* app_params = dict->Find("appParams");
- EXPECT_EQ(json.value(), *app_params);
- CastMessage response;
- response.set_namespace_("urn:x-cast:com.google.cast.receiver");
- response.set_source_id("receiver-0");
- response.set_destination_id(handler_.sender_id());
- response.set_payload_type(
- CastMessage::PayloadType::CastMessage_PayloadType_STRING);
- response.set_payload_utf8(
- base::StringPrintf("{"
- "\"type\": \"RECEIVER_STATUS\","
- "\"requestId\": %d,"
- "\"status\": {}"
- "}",
- request_id));
- run_loop_ = std::make_unique<base::RunLoop>();
- OnMessage(response);
- run_loop_->Run();
- EXPECT_EQ(1, session_launch_response_count_);
- }
- TEST_F(CastMessageHandlerTest, LaunchSessionTimedOut) {
- ExpectEnsureConnectionThen(CastMessageType::kLaunch);
- handler_.LaunchSession(
- channel_id_, kAppId1, base::Seconds(30), {"WEB"},
- /* appParams */ absl::nullopt,
- base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
- base::Unretained(this),
- LaunchSessionResponse::Result::kTimedOut));
- task_environment_.FastForwardBy(base::Seconds(30));
- EXPECT_EQ(1, session_launch_response_count_);
- }
- TEST_F(CastMessageHandlerTest, LaunchSessionMessageExceedsSizeLimit) {
- std::string invalid_url(kMaxProtocolMessageSize, 'a');
- base::Value::Dict json;
- json.Set("key", invalid_url);
- handler_.LaunchSession(
- channel_id_, kAppId1, base::Seconds(30), {"WEB"},
- absl::make_optional<base::Value>(std::move(json)),
- base::BindOnce(&CastMessageHandlerTest::ExpectSessionLaunchResult,
- base::Unretained(this),
- LaunchSessionResponse::Result::kError));
- EXPECT_EQ(1, session_launch_response_count_);
- }
- TEST_F(CastMessageHandlerTest, SendAppMessage) {
- base::Value::Dict body;
- body.Set("foo", "bar");
- CastMessage message = CreateCastMessage(
- "namespace", base::Value(std::move(body)), kSourceId, kDestinationId);
- {
- InSequence dummy;
- ExpectEnsureConnection();
- EXPECT_CALL(*transport_,
- SendMessage_(HasPayloadUtf8(message.payload_utf8()), _));
- }
- EXPECT_EQ(Result::kOk, handler_.SendAppMessage(channel_id_, message));
- }
- TEST_F(CastMessageHandlerTest, SendMessageOnInvisibleConnection) {
- // For destinations other than receiver-0, we should default to an invisible
- // connection.
- SendMessageAndExpectConnection("non-platform-receiver-id",
- VirtualConnectionType::kInvisible);
- }
- TEST_F(CastMessageHandlerTest, SendMessageToPlatformReceiver) {
- // For receiver-0, we should default to a strong connection because some
- // commands (e.g. LAUNCH) are not accepted from invisible connections.
- SendMessageAndExpectConnection("receiver-0", VirtualConnectionType::kStrong);
- }
- TEST_F(CastMessageHandlerTest, SendAppMessageExceedsSizeLimit) {
- std::string invalid_msg(kMaxProtocolMessageSize, 'a');
- base::Value::Dict body;
- body.Set("foo", invalid_msg);
- CastMessage message = CreateCastMessage(
- "namespace", base::Value(std::move(body)), kSourceId, kDestinationId);
- EXPECT_EQ(Result::kFailed, handler_.SendAppMessage(channel_id_, message));
- }
- // Check that SendMediaRequest sends a message created by CreateMediaRequest and
- // returns a request ID.
- TEST_F(CastMessageHandlerTest, SendMediaRequest) {
- {
- InSequence dummy;
- ExpectEnsureConnection();
- EXPECT_CALL(*transport_, SendMessage_(_, _))
- .WillOnce(WithArg<0>([&](const auto& message) {
- std::string expected_body = R"({
- "requestId": 1,
- "type": "PLAY",
- })";
- auto expected = CreateMediaRequest(ParseJson(expected_body), 1,
- "theSourceId", kDestinationId);
- EXPECT_EQ(expected.namespace_(), message.namespace_());
- EXPECT_EQ(expected.source_id(), message.source_id());
- EXPECT_EQ(expected.destination_id(), message.destination_id());
- EXPECT_EQ(expected.payload_utf8(), message.payload_utf8());
- // Future-proofing. This matcher gives terrible error messages but it
- // might catch errors the above matchers miss.
- EXPECT_THAT(message, EqualsProto(expected));
- }));
- }
- std::string message_str = R"({
- "type": "PLAY",
- })";
- absl::optional<int> request_id = handler_.SendMediaRequest(
- channel_id_, ParseJson(message_str), "theSourceId", kDestinationId);
- EXPECT_EQ(1, request_id);
- }
- TEST_F(CastMessageHandlerTest, SendBroadcastMessage) {
- BroadcastRequest request = BroadcastRequest("namespace", "message");
- CastMessage message = CreateBroadcastRequest(
- "theSourceId", /* request_id */ 1, {kAppId1}, request);
- {
- InSequence dummy;
- ExpectEnsureConnection();
- EXPECT_CALL(*transport_,
- SendMessage_(HasPayloadUtf8(message.payload_utf8()), _));
- }
- EXPECT_EQ(Result::kOk,
- handler_.SendBroadcastMessage(channel_id_, {kAppId1}, request));
- }
- TEST_F(CastMessageHandlerTest, SendBroadcastMessageExceedsSizeLimit) {
- BroadcastRequest request =
- BroadcastRequest("namespace", std::string(kMaxProtocolMessageSize, 'a'));
- CastMessage message = CreateBroadcastRequest(
- "theSourceId", /* request_id */ 1, {kAppId1}, request);
- EXPECT_EQ(Result::kFailed,
- handler_.SendBroadcastMessage(channel_id_, {kAppId1}, request));
- }
- // Check that SendVolumeCommand sends a message created by CreateVolumeRequest
- // and registers a pending request.
- TEST_F(CastMessageHandlerTest, SendVolumeCommand) {
- {
- InSequence dummy;
- ExpectEnsureConnection();
- EXPECT_CALL(*transport_, SendMessage_(_, _))
- .WillOnce(WithArg<0>([&](const auto& message) {
- std::string expected_body = R"({
- "requestId": 1,
- "type": "SET_VOLUME",
- })";
- auto expected = CreateSetVolumeRequest(ParseJson(expected_body), 1,
- "theSourceId");
- EXPECT_EQ(expected.namespace_(), message.namespace_());
- EXPECT_EQ(expected.source_id(), message.source_id());
- EXPECT_EQ(expected.destination_id(), message.destination_id());
- EXPECT_EQ(expected.payload_utf8(), message.payload_utf8());
- // Future-proofing. This matcher gives terrible error messages but it
- // might catch errors the above matchers miss.
- EXPECT_THAT(message, EqualsProto(expected));
- }));
- }
- std::string message_str = R"({
- "sessionId": "theSessionId",
- "type": "SET_VOLUME",
- })";
- handler_.SendSetVolumeRequest(channel_id_, ParseJson(message_str),
- "theSourceId", base::DoNothing());
- }
- // Check that closing a socket removes pending requests, and that the pending
- // request callbacks are called appropriately.
- TEST_F(CastMessageHandlerTest, PendingRequestsDestructor) {
- CreatePendingRequests();
- // Set up expanctions for pending request callbacks.
- EXPECT_CALL(launch_session_callback_, Run(_))
- .WillOnce([&](LaunchSessionResponse response) {
- EXPECT_EQ(LaunchSessionResponse::kError, response.result);
- EXPECT_EQ(absl::nullopt, response.receiver_status);
- });
- EXPECT_CALL(get_app_availability_callback_,
- Run(kAppId1, GetAppAvailabilityResult::kUnknown))
- .Times(2);
- EXPECT_CALL(set_volume_callback_, Run(Result::kFailed)).Times(2);
- EXPECT_CALL(stop_session_callback_, Run(Result::kFailed));
- // Force callbacks to be called through PendingRequests destructor by
- // simulating a socket closing.
- EXPECT_CALL(cast_socket_, ready_state()).WillOnce(Return(ReadyState::CLOSED));
- handler_.OnReadyStateChanged(cast_socket_);
- }
- TEST_F(CastMessageHandlerTest, HandlePendingRequest) {
- int next_request_id = 1;
- CreatePendingRequests();
- // Set up expanctions for pending request callbacks.
- EXPECT_CALL(launch_session_callback_, Run(_))
- .WillOnce([&](LaunchSessionResponse response) {
- EXPECT_EQ(LaunchSessionResponse::kOk, response.result);
- EXPECT_THAT(response.receiver_status,
- testing::Optional(IsJson(R"({"foo": "bar"})")));
- });
- EXPECT_CALL(get_app_availability_callback_,
- Run(kAppId1, GetAppAvailabilityResult::kAvailable))
- .Times(2);
- EXPECT_CALL(set_volume_callback_, Run(Result::kOk)).Times(2);
- EXPECT_CALL(stop_session_callback_, Run(Result::kOk));
- HandlePendingLaunchSessionRequest(next_request_id++);
- // Handle both pending get app availability requests.
- HandleAppAvailabilityRequest(next_request_id++);
- // Handle pending set volume request (1 of 2).
- HandlePendingGeneralRequest(next_request_id++);
- // Skip request_id == 4, since it was used by the second get app availability
- // request.
- next_request_id++;
- // Handle pending set volume request (2 of 2).
- HandlePendingGeneralRequest(next_request_id++);
- // Handle pending stop session request.
- HandlePendingGeneralRequest(next_request_id++);
- }
- // Check that set volume requests time out correctly.
- TEST_F(CastMessageHandlerTest, SetVolumeTimedOut) {
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
- std::string message_str = R"({
- "sessionId": "theSessionId",
- "type": "SET_VOLUME",
- })";
- base::MockCallback<ResultCallback> callback;
- handler_.SendSetVolumeRequest(channel_id_, ParseJson(message_str),
- "theSourceId", callback.Get());
- EXPECT_CALL(callback, Run(Result::kFailed));
- task_environment_.FastForwardBy(kRequestTimeout);
- }
- TEST_F(CastMessageHandlerTest, SendMultipleLaunchRequests) {
- int next_request_id = 1;
- base::MockCallback<LaunchSessionCallback> expect_success_callback;
- base::MockCallback<LaunchSessionCallback> expect_failure_callback;
- EXPECT_CALL(expect_success_callback, Run(_))
- .WillOnce(WithArg<0>([](LaunchSessionResponse response) {
- EXPECT_EQ(LaunchSessionResponse::Result::kOk, response.result);
- }));
- EXPECT_CALL(expect_failure_callback, Run(_))
- .WillOnce(WithArg<0>([](LaunchSessionResponse response) {
- EXPECT_EQ(LaunchSessionResponse::Result::kError, response.result);
- }));
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
- handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
- /* appParams */ absl::nullopt,
- expect_success_callback.Get());
- // When there already is a launch request queued, we expect subsequent
- // requests to fail.
- handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
- /* appParams */ absl::nullopt,
- expect_failure_callback.Get());
- // This resolves the first launch request.
- HandlePendingLaunchSessionRequest(next_request_id++);
- }
- TEST_F(CastMessageHandlerTest, SendMultipleStopRequests) {
- int next_request_id = 1;
- base::MockCallback<ResultCallback> expect_success_callback;
- base::MockCallback<ResultCallback> expect_failure_callback;
- EXPECT_CALL(*transport_, SendMessage_(_, _)).Times(AnyNumber());
- handler_.LaunchSession(channel_id_, kAppId1, base::TimeDelta::Max(), {"WEB"},
- /* appParams */ absl::nullopt,
- launch_session_callback_.Get());
- HandlePendingLaunchSessionRequest(next_request_id++);
- EXPECT_CALL(expect_success_callback, Run(Result::kOk));
- EXPECT_CALL(expect_failure_callback, Run(Result::kFailed));
- handler_.StopSession(channel_id_, kSessionId, kSourceId,
- expect_success_callback.Get());
- // When there already is a stop request queued, we expect subsequent requests
- // to fail.
- handler_.StopSession(channel_id_, kSessionId, kSourceId,
- expect_failure_callback.Get());
- // This resolves the first stop request.
- HandlePendingGeneralRequest(next_request_id++);
- }
- } // namespace cast_channel
|