blob: b05d10e3a600d14a1590a91e6e75a6e4573c7635 [file] [log] [blame]
// Copyright 2019 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 "cast/common/channel/virtual_connection_router.h"
#include <utility>
#include "cast/common/channel/message_util.h"
#include "cast/common/channel/proto/cast_channel.pb.h"
#include "cast/common/channel/testing/fake_cast_socket.h"
#include "cast/common/channel/testing/mock_cast_message_handler.h"
#include "cast/common/channel/testing/mock_socket_error_handler.h"
#include "cast/common/channel/virtual_connection_manager.h"
#include "cast/common/public/cast_socket.h"
#include "gtest/gtest.h"
namespace openscreen {
namespace cast {
namespace {
using ::cast::channel::CastMessage;
using ::testing::_;
using ::testing::Invoke;
using ::testing::SaveArg;
using ::testing::WithArg;
class VirtualConnectionRouterTest : public ::testing::Test {
public:
void SetUp() override {
local_socket_ = fake_cast_socket_pair_.socket.get();
local_router_.TakeSocket(&mock_error_handler_,
std::move(fake_cast_socket_pair_.socket));
remote_socket_ = fake_cast_socket_pair_.peer_socket.get();
remote_router_.TakeSocket(&mock_error_handler_,
std::move(fake_cast_socket_pair_.peer_socket));
}
protected:
FakeCastSocketPair fake_cast_socket_pair_;
CastSocket* local_socket_;
CastSocket* remote_socket_;
MockSocketErrorHandler mock_error_handler_;
VirtualConnectionManager local_manager_;
VirtualConnectionRouter local_router_{&local_manager_};
VirtualConnectionManager remote_manager_;
VirtualConnectionRouter remote_router_{&remote_manager_};
};
} // namespace
TEST_F(VirtualConnectionRouterTest, LocalIdHandler) {
MockCastMessageHandler mock_message_handler;
local_router_.AddHandlerForLocalId("receiver-1234", &mock_message_handler);
local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-9873",
local_socket_->socket_id()},
{});
CastMessage message;
message.set_protocol_version(
::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
message.set_namespace_("zrqvn");
message.set_source_id("sender-9873");
message.set_destination_id("receiver-1234");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _));
EXPECT_TRUE(remote_socket_->Send(message).ok());
EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _));
EXPECT_TRUE(remote_socket_->Send(message).ok());
message.set_destination_id("receiver-4321");
EXPECT_CALL(mock_message_handler, OnMessage(_, _, _)).Times(0);
EXPECT_TRUE(remote_socket_->Send(message).ok());
local_router_.RemoveHandlerForLocalId("receiver-1234");
}
TEST_F(VirtualConnectionRouterTest, RemoveLocalIdHandler) {
MockCastMessageHandler mock_message_handler;
local_router_.AddHandlerForLocalId("receiver-1234", &mock_message_handler);
local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-9873",
local_socket_->socket_id()},
{});
CastMessage message;
message.set_protocol_version(
::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
message.set_namespace_("zrqvn");
message.set_source_id("sender-9873");
message.set_destination_id("receiver-1234");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _));
EXPECT_TRUE(remote_socket_->Send(message).ok());
local_router_.RemoveHandlerForLocalId("receiver-1234");
EXPECT_CALL(mock_message_handler, OnMessage(_, local_socket_, _)).Times(0);
EXPECT_TRUE(remote_socket_->Send(message).ok());
local_router_.RemoveHandlerForLocalId("receiver-1234");
}
TEST_F(VirtualConnectionRouterTest, SendMessage) {
local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-4321",
local_socket_->socket_id()},
{});
MockCastMessageHandler destination;
remote_router_.AddHandlerForLocalId("sender-4321", &destination);
remote_manager_.AddConnection(
VirtualConnection{"sender-4321", "receiver-1234",
remote_socket_->socket_id()},
{});
CastMessage message;
message.set_protocol_version(
::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
message.set_namespace_("zrqvn");
message.set_source_id("receiver-1234");
message.set_destination_id("sender-4321");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
ASSERT_TRUE(message.IsInitialized());
EXPECT_CALL(destination, OnMessage(&remote_router_, remote_socket_, _))
.WillOnce(
WithArg<2>(Invoke([&message](CastMessage message_at_destination) {
ASSERT_TRUE(message_at_destination.IsInitialized());
EXPECT_EQ(message.SerializeAsString(),
message_at_destination.SerializeAsString());
})));
local_router_.Send(VirtualConnection{"receiver-1234", "sender-4321",
local_socket_->socket_id()},
message);
}
TEST_F(VirtualConnectionRouterTest, CloseSocketRemovesVirtualConnections) {
local_manager_.AddConnection(VirtualConnection{"receiver-1234", "sender-4321",
local_socket_->socket_id()},
{});
EXPECT_CALL(mock_error_handler_, OnClose(local_socket_)).Times(1);
int id = local_socket_->socket_id();
local_router_.CloseSocket(id);
EXPECT_FALSE(local_manager_.GetConnectionData(
VirtualConnection{"receiver-1234", "sender-4321", id}));
}
// Tests that VirtualConnectionRouter::Send() broadcasts a message from a local
// source to both: 1) all other local peers; and 2) all remote peers.
TEST_F(VirtualConnectionRouterTest, BroadcastsFromLocalSource) {
// Local peers.
MockCastMessageHandler alice, bob;
local_router_.AddHandlerForLocalId("alice", &alice);
local_router_.AddHandlerForLocalId("bob", &bob);
// Remote peers.
MockCastMessageHandler charlie, dave, eve;
remote_router_.AddHandlerForLocalId("charlie", &charlie);
remote_router_.AddHandlerForLocalId("dave", &dave);
remote_router_.AddHandlerForLocalId("eve", &eve);
// The local broadcaster, which should never receive her own messages.
MockCastMessageHandler wendy;
local_router_.AddHandlerForLocalId("wendy", &wendy);
EXPECT_CALL(wendy, OnMessage(_, _, _)).Times(0);
CastMessage message;
message.set_protocol_version(
::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
message.set_namespace_("zrqvn");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
CastMessage message_alice_got, message_bob_got, message_charlie_got,
message_dave_got, message_eve_got;
EXPECT_CALL(alice, OnMessage(&local_router_, nullptr, _))
.WillOnce(SaveArg<2>(&message_alice_got))
.RetiresOnSaturation();
EXPECT_CALL(bob, OnMessage(&local_router_, nullptr, _))
.WillOnce(SaveArg<2>(&message_bob_got))
.RetiresOnSaturation();
EXPECT_CALL(charlie, OnMessage(&remote_router_, remote_socket_, _))
.WillOnce(SaveArg<2>(&message_charlie_got))
.RetiresOnSaturation();
EXPECT_CALL(dave, OnMessage(&remote_router_, remote_socket_, _))
.WillOnce(SaveArg<2>(&message_dave_got))
.RetiresOnSaturation();
EXPECT_CALL(eve, OnMessage(&remote_router_, remote_socket_, _))
.WillOnce(SaveArg<2>(&message_eve_got))
.RetiresOnSaturation();
ASSERT_TRUE(local_router_.BroadcastFromLocalPeer("wendy", message).ok());
// Confirm message data is correct.
message.set_source_id("wendy");
message.set_destination_id(kBroadcastId);
ASSERT_TRUE(message.IsInitialized());
ASSERT_TRUE(message_alice_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(), message_alice_got.SerializeAsString());
ASSERT_TRUE(message_bob_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(), message_bob_got.SerializeAsString());
ASSERT_TRUE(message_charlie_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(),
message_charlie_got.SerializeAsString());
ASSERT_TRUE(message_dave_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(), message_dave_got.SerializeAsString());
ASSERT_TRUE(message_eve_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(), message_eve_got.SerializeAsString());
// Remove one local peer and one remote peer, and confirm only the correct
// entities receive a broadcast message.
local_router_.RemoveHandlerForLocalId("bob");
remote_router_.RemoveHandlerForLocalId("charlie");
EXPECT_CALL(alice, OnMessage(&local_router_, nullptr, _)).Times(1);
EXPECT_CALL(bob, OnMessage(_, _, _)).Times(0);
EXPECT_CALL(charlie, OnMessage(_, _, _)).Times(0);
EXPECT_CALL(dave, OnMessage(&remote_router_, remote_socket_, _)).Times(1);
EXPECT_CALL(eve, OnMessage(&remote_router_, remote_socket_, _)).Times(1);
ASSERT_TRUE(local_router_.BroadcastFromLocalPeer("wendy", message).ok());
}
// Tests that VirtualConnectionRouter::OnMessage() broadcasts a message from a
// remote source to all local peers.
TEST_F(VirtualConnectionRouterTest, BroadcastsFromRemoteSource) {
// Local peers.
MockCastMessageHandler alice, bob, charlie;
local_router_.AddHandlerForLocalId("alice", &alice);
local_router_.AddHandlerForLocalId("bob", &bob);
local_router_.AddHandlerForLocalId("charlie", &charlie);
// The remote broadcaster, which should never receive her own messages.
MockCastMessageHandler wendy;
remote_router_.AddHandlerForLocalId("wendy", &wendy);
EXPECT_CALL(wendy, OnMessage(_, _, _)).Times(0);
CastMessage message;
message.set_protocol_version(
::cast::channel::CastMessage_ProtocolVersion_CASTV2_1_0);
message.set_namespace_("zrqvn");
message.set_payload_type(CastMessage::STRING);
message.set_payload_utf8("cnlybnq");
CastMessage message_alice_got, message_bob_got, message_charlie_got;
EXPECT_CALL(alice, OnMessage(&local_router_, local_socket_, _))
.WillOnce(SaveArg<2>(&message_alice_got))
.RetiresOnSaturation();
EXPECT_CALL(bob, OnMessage(&local_router_, local_socket_, _))
.WillOnce(SaveArg<2>(&message_bob_got))
.RetiresOnSaturation();
EXPECT_CALL(charlie, OnMessage(&local_router_, local_socket_, _))
.WillOnce(SaveArg<2>(&message_charlie_got))
.RetiresOnSaturation();
ASSERT_TRUE(remote_router_.BroadcastFromLocalPeer("wendy", message).ok());
// Confirm message data is correct.
message.set_source_id("wendy");
message.set_destination_id(kBroadcastId);
ASSERT_TRUE(message.IsInitialized());
ASSERT_TRUE(message_alice_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(), message_alice_got.SerializeAsString());
ASSERT_TRUE(message_bob_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(), message_bob_got.SerializeAsString());
ASSERT_TRUE(message_charlie_got.IsInitialized());
EXPECT_EQ(message.SerializeAsString(),
message_charlie_got.SerializeAsString());
// Remove one local peer, and confirm only the two remaining local peers
// receive a broadcast message from the remote source.
local_router_.RemoveHandlerForLocalId("bob");
EXPECT_CALL(alice, OnMessage(&local_router_, local_socket_, _)).Times(1);
EXPECT_CALL(bob, OnMessage(_, _, _)).Times(0);
EXPECT_CALL(charlie, OnMessage(&local_router_, local_socket_, _)).Times(1);
ASSERT_TRUE(remote_router_.BroadcastFromLocalPeer("wendy", message).ok());
}
} // namespace cast
} // namespace openscreen