blob: 6f5dd3eaca26cb96b5820a01a33dabf502c3de6d [file] [log] [blame]
// 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 "cast/streaming/session_messager.h"
#include "cast/streaming/testing/message_pipe.h"
#include "cast/streaming/testing/simple_message_port.h"
#include "gtest/gtest.h"
#include "platform/test/fake_clock.h"
#include "platform/test/fake_task_runner.h"
namespace openscreen {
namespace cast {
using ::testing::ElementsAre;
namespace {
constexpr char kSenderId[] = "sender-12345";
constexpr char kReceiverId[] = "receiver-12345";
// Generally the messages are inlined below, with the exception of the Offer,
// simply because it is massive.
Offer kExampleOffer{
CastMode::kMirroring,
false,
{AudioStream{Stream{0,
Stream::Type::kAudioSource,
2,
RtpPayloadType::kAudioOpus,
12344442,
std::chrono::milliseconds{2000},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
false,
"",
48000},
AudioCodec::kOpus, 1400}},
{VideoStream{Stream{1,
Stream::Type::kVideoSource,
1,
RtpPayloadType::kVideoVp8,
12344444,
std::chrono::milliseconds{2000},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
false,
"",
90000},
VideoCodec::kVp8,
SimpleFraction{30, 1},
3000000,
"",
"",
"",
{Resolution{640, 480}},
""}}};
struct SessionMessageStore {
public:
SenderSessionMessager::ReplyCallback GetReplyCallback() {
return [this](ReceiverMessage message) {
receiver_messages.push_back(std::move(message));
};
}
ReceiverSessionMessager::RequestCallback GetRequestCallback() {
return [this](SenderMessage message) {
sender_messages.push_back(std::move(message));
};
}
SessionMessager::ErrorCallback GetErrorCallback() {
return [this](Error error) { errors.push_back(std::move(error)); };
}
std::vector<SenderMessage> sender_messages;
std::vector<ReceiverMessage> receiver_messages;
std::vector<Error> errors;
};
} // namespace
class SessionMessagerTest : public ::testing::Test {
public:
SessionMessagerTest()
: clock_{Clock::now()},
task_runner_(&clock_),
message_store_(),
pipe_(kSenderId, kReceiverId),
receiver_messager_(pipe_.right(),
kReceiverId,
message_store_.GetErrorCallback()),
sender_messager_(pipe_.left(),
kSenderId,
kReceiverId,
message_store_.GetErrorCallback(),
&task_runner_)
{}
void SetUp() override {
sender_messager_.SetHandler(ReceiverMessage::Type::kRpc,
message_store_.GetReplyCallback());
receiver_messager_.SetHandler(SenderMessage::Type::kOffer,
message_store_.GetRequestCallback());
receiver_messager_.SetHandler(SenderMessage::Type::kGetStatus,
message_store_.GetRequestCallback());
receiver_messager_.SetHandler(SenderMessage::Type::kGetCapabilities,
message_store_.GetRequestCallback());
receiver_messager_.SetHandler(SenderMessage::Type::kRpc,
message_store_.GetRequestCallback());
}
protected:
FakeClock clock_;
FakeTaskRunner task_runner_;
SessionMessageStore message_store_;
MessagePipe pipe_;
ReceiverSessionMessager receiver_messager_;
SenderSessionMessager sender_messager_;
std::vector<Error> receiver_errors_;
std::vector<Error> sender_errors_;
};
TEST_F(SessionMessagerTest, RpcMessaging) {
ASSERT_TRUE(sender_messager_
.SendOutboundMessage(SenderMessage{
SenderMessage::Type::kRpc, 123, true /* valid */,
std::string("all your base are belong to us")})
.ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
EXPECT_EQ(SenderMessage::Type::kRpc, message_store_.sender_messages[0].type);
ASSERT_TRUE(message_store_.sender_messages[0].valid);
EXPECT_EQ("all your base are belong to us",
absl::get<std::string>(message_store_.sender_messages[0].body));
message_store_.sender_messages.clear();
ASSERT_TRUE(
receiver_messager_
.SendMessage(ReceiverMessage{ReceiverMessage::Type::kRpc, 123,
true /* valid */, std::string("nuh uh")})
.ok());
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
EXPECT_EQ(ReceiverMessage::Type::kRpc,
message_store_.receiver_messages[0].type);
EXPECT_TRUE(message_store_.receiver_messages[0].valid);
EXPECT_EQ("nuh uh",
absl::get<std::string>(message_store_.receiver_messages[0].body));
}
TEST_F(SessionMessagerTest, StatusMessaging) {
ASSERT_TRUE(sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kGetStatus,
3123, true /* valid */},
ReceiverMessage::Type::kStatusResponse,
message_store_.GetReplyCallback())
.ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
EXPECT_EQ(SenderMessage::Type::kGetStatus,
message_store_.sender_messages[0].type);
EXPECT_TRUE(message_store_.sender_messages[0].valid);
message_store_.sender_messages.clear();
ASSERT_TRUE(
receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kStatusResponse, 3123, true /* valid */,
ReceiverWifiStatus{-5.7, std::vector<int32_t>{1200, 1300, 1250}}})
.ok());
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
EXPECT_EQ(ReceiverMessage::Type::kStatusResponse,
message_store_.receiver_messages[0].type);
EXPECT_TRUE(message_store_.receiver_messages[0].valid);
const auto& status =
absl::get<ReceiverWifiStatus>(message_store_.receiver_messages[0].body);
EXPECT_DOUBLE_EQ(-5.7, status.wifi_snr);
EXPECT_THAT(status.wifi_speed, ElementsAre(1200, 1300, 1250));
}
TEST_F(SessionMessagerTest, CapabilitiesMessaging) {
ASSERT_TRUE(
sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kGetCapabilities,
1337, true /* valid */},
ReceiverMessage::Type::kCapabilitiesResponse,
message_store_.GetReplyCallback())
.ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
EXPECT_EQ(SenderMessage::Type::kGetCapabilities,
message_store_.sender_messages[0].type);
EXPECT_TRUE(message_store_.sender_messages[0].valid);
message_store_.sender_messages.clear();
ASSERT_TRUE(receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kCapabilitiesResponse, 1337,
true /* valid */, ReceiverCapability{47, {"ac3", "4k"}}})
.ok());
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
EXPECT_EQ(ReceiverMessage::Type::kCapabilitiesResponse,
message_store_.receiver_messages[0].type);
EXPECT_TRUE(message_store_.receiver_messages[0].valid);
const auto& capability =
absl::get<ReceiverCapability>(message_store_.receiver_messages[0].body);
EXPECT_EQ(47, capability.remoting_version);
EXPECT_THAT(capability.media_capabilities, ElementsAre("ac3", "4k"));
}
TEST_F(SessionMessagerTest, OfferAnswerMessaging) {
ASSERT_TRUE(sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kOffer, 42,
true /* valid */, kExampleOffer},
ReceiverMessage::Type::kAnswer,
message_store_.GetReplyCallback())
.ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
EXPECT_EQ(SenderMessage::Type::kOffer,
message_store_.sender_messages[0].type);
EXPECT_TRUE(message_store_.sender_messages[0].valid);
message_store_.sender_messages.clear();
EXPECT_TRUE(receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kAnswer, 41, true /* valid */,
Answer{1234, {0, 1}, {12344443, 12344445}}})
.ok());
// A stale answer (for offer 41) should get ignored:
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_TRUE(message_store_.receiver_messages.empty());
ASSERT_TRUE(receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kAnswer, 42, true /* valid */,
Answer{1234, {0, 1}, {12344443, 12344445}}})
.ok());
EXPECT_TRUE(message_store_.sender_messages.empty());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
EXPECT_EQ(ReceiverMessage::Type::kAnswer,
message_store_.receiver_messages[0].type);
EXPECT_TRUE(message_store_.receiver_messages[0].valid);
const auto& answer =
absl::get<Answer>(message_store_.receiver_messages[0].body);
EXPECT_EQ(1234, answer.udp_port);
EXPECT_THAT(answer.send_indexes, ElementsAre(0, 1));
EXPECT_THAT(answer.ssrcs, ElementsAre(12344443, 12344445));
}
TEST_F(SessionMessagerTest, OfferAndReceiverError) {
ASSERT_TRUE(sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kOffer, 42,
true /* valid */, kExampleOffer},
ReceiverMessage::Type::kAnswer,
message_store_.GetReplyCallback())
.ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
EXPECT_EQ(SenderMessage::Type::kOffer,
message_store_.sender_messages[0].type);
EXPECT_TRUE(message_store_.sender_messages[0].valid);
message_store_.sender_messages.clear();
EXPECT_TRUE(receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kAnswer, 42, false /* valid */,
ReceiverError{123, "Something real bad happened"}})
.ok());
EXPECT_TRUE(message_store_.sender_messages.empty());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
EXPECT_EQ(ReceiverMessage::Type::kAnswer,
message_store_.receiver_messages[0].type);
EXPECT_FALSE(message_store_.receiver_messages[0].valid);
const auto& error =
absl::get<ReceiverError>(message_store_.receiver_messages[0].body);
EXPECT_EQ(123, error.code);
EXPECT_EQ("Something real bad happened", error.description);
}
TEST_F(SessionMessagerTest, UnexpectedMessagesAreIgnored) {
EXPECT_FALSE(
receiver_messager_
.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kStatusResponse, 3123, true /* valid */,
ReceiverWifiStatus{-5.7, std::vector<int32_t>{1200, 1300, 1250}}})
.ok());
// The message gets dropped and thus won't be in the store.
EXPECT_TRUE(message_store_.sender_messages.empty());
EXPECT_TRUE(message_store_.receiver_messages.empty());
}
TEST_F(SessionMessagerTest, UnknownSenderMessageTypesDontGetSent) {
EXPECT_DEATH(sender_messager_
.SendOutboundMessage(SenderMessage{
SenderMessage::Type::kUnknown, 123, true /* valid */})
.ok(),
".*Trying to send an unknown message is a developer error.*");
}
TEST_F(SessionMessagerTest, UnknownReceiverMessageTypesDontGetSent) {
ASSERT_TRUE(sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kOffer, 42,
true /* valid */, kExampleOffer},
ReceiverMessage::Type::kAnswer,
message_store_.GetReplyCallback())
.ok());
EXPECT_DEATH(receiver_messager_
.SendMessage(ReceiverMessage{ReceiverMessage::Type::kUnknown,
3123, true /* valid */})
.ok(),
".*Trying to send an unknown message is a developer error.*");
}
TEST_F(SessionMessagerTest, ReceiverHandlesUnknownMessageType) {
pipe_.right()->ReceiveMessage(kCastWebrtcNamespace, R"({
"type": "GET_VIRTUAL_REALITY",
"seqNum": 31337
})");
ASSERT_TRUE(message_store_.errors.empty());
}
TEST_F(SessionMessagerTest, SenderHandlesUnknownMessageType) {
// The behavior on the sender side is a little more interesting: we
// test elsewhere that messages with the wrong sequence number are ignored,
// here if the type is unknown but the message contains a valid sequence
// number we just treat it as a bad response/same as a timeout.
ASSERT_TRUE(sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kOffer, 42,
true /* valid */, kExampleOffer},
ReceiverMessage::Type::kAnswer,
message_store_.GetReplyCallback())
.ok());
pipe_.left()->ReceiveMessage(kCastWebrtcNamespace, R"({
"type": "ANSWER_VERSION_2",
"seqNum": 42
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
ASSERT_EQ(ReceiverMessage::Type::kUnknown,
message_store_.receiver_messages[0].type);
ASSERT_EQ(false, message_store_.receiver_messages[0].valid);
}
TEST_F(SessionMessagerTest, SenderHandlesMessageMissingSequenceNumber) {
ASSERT_TRUE(
sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kGetCapabilities, 42,
true /* valid */},
ReceiverMessage::Type::kCapabilitiesResponse,
message_store_.GetReplyCallback())
.ok());
pipe_.left()->ReceiveMessage(kCastWebrtcNamespace, R"({
"capabilities": {
"keySystems": [],
"mediaCaps": ["video"]
},
"result": "ok",
"type": "CAPABILITIES_RESPONSE"
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_TRUE(message_store_.receiver_messages.empty());
}
TEST_F(SessionMessagerTest, ReceiverCannotSendFirst) {
const Error error = receiver_messager_.SendMessage(ReceiverMessage{
ReceiverMessage::Type::kStatusResponse, 3123, true /* valid */,
ReceiverWifiStatus{-5.7, std::vector<int32_t>{1200, 1300, 1250}}});
EXPECT_EQ(Error::Code::kInitializationFailure, error.code());
}
TEST_F(SessionMessagerTest, ErrorMessageLoggedIfTimeout) {
ASSERT_TRUE(sender_messager_
.SendRequest(SenderMessage{SenderMessage::Type::kGetStatus,
3123, true /* valid */},
ReceiverMessage::Type::kStatusResponse,
message_store_.GetReplyCallback())
.ok());
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_TRUE(message_store_.receiver_messages.empty());
clock_.Advance(std::chrono::seconds(10));
ASSERT_EQ(1u, message_store_.sender_messages.size());
ASSERT_EQ(1u, message_store_.receiver_messages.size());
EXPECT_EQ(3123, message_store_.receiver_messages[0].sequence_number);
EXPECT_EQ(ReceiverMessage::Type::kStatusResponse,
message_store_.receiver_messages[0].type);
EXPECT_FALSE(message_store_.receiver_messages[0].valid);
}
TEST_F(SessionMessagerTest, ReceiverRejectsMessageFromWrongSender) {
SimpleMessagePort port(kReceiverId);
ReceiverSessionMessager messager(&port, kReceiverId,
message_store_.GetErrorCallback());
messager.SetHandler(SenderMessage::Type::kGetStatus,
message_store_.GetRequestCallback());
// The first message should be accepted since we don't have a set sender_id
// yet.
port.ReceiveMessage("sender-31337", kCastWebrtcNamespace, R"({
"get_status": ["wifiSnr", "wifiSpeed"],
"seqNum": 820263769,
"type": "GET_STATUS"
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_EQ(1u, message_store_.sender_messages.size());
message_store_.sender_messages.clear();
// The second message should just be ignored.
port.ReceiveMessage("sender-42", kCastWebrtcNamespace, R"({
"get_status": ["wifiSnr"],
"seqNum": 1234,
"type": "GET_STATUS"
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_TRUE(message_store_.sender_messages.empty());
// But the third message should be accepted again since it's from the
// first sender.
port.ReceiveMessage("sender-31337", kCastWebrtcNamespace, R"({
"get_status": ["wifiSnr", "wifiSpeed"],
"seqNum": 820263769,
"type": "GET_STATUS"
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_EQ(1u, message_store_.sender_messages.size());
}
TEST_F(SessionMessagerTest, SenderRejectsMessageFromWrongSender) {
SimpleMessagePort port(kReceiverId);
SenderSessionMessager messager(&port, kSenderId, kReceiverId,
message_store_.GetErrorCallback(),
&task_runner_);
port.ReceiveMessage("receiver-31337", kCastWebrtcNamespace, R"({
"seqNum": 12345,
"sessionId": 735189,
"type": "RPC",
"result": "ok",
"rpc": "SGVsbG8gZnJvbSB0aGUgQ2FzdCBSZWNlaXZlciE="
})");
// The message should just be ignored.
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_TRUE(message_store_.receiver_messages.empty());
}
TEST_F(SessionMessagerTest, ReceiverRejectsMessagesWithoutHandler) {
SimpleMessagePort port(kReceiverId);
ReceiverSessionMessager messager(&port, kReceiverId,
message_store_.GetErrorCallback());
messager.SetHandler(SenderMessage::Type::kGetStatus,
message_store_.GetRequestCallback());
// The first message should be accepted since we don't have a set sender_id
// yet.
port.ReceiveMessage("sender-31337", kCastWebrtcNamespace, R"({
"get_status": ["wifiSnr", "wifiSpeed"],
"seqNum": 820263769,
"type": "GET_STATUS"
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_EQ(1u, message_store_.sender_messages.size());
message_store_.sender_messages.clear();
// The second message should be rejected since it doesn't have a handler.
port.ReceiveMessage("sender-31337", kCastWebrtcNamespace, R"({
"seqNum": 820263770,
"type": "GET_CAPABILITIES"
})");
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_TRUE(message_store_.sender_messages.empty());
}
TEST_F(SessionMessagerTest, SenderRejectsMessagesWithoutHandler) {
SimpleMessagePort port(kReceiverId);
SenderSessionMessager messager(&port, kSenderId, kReceiverId,
message_store_.GetErrorCallback(),
&task_runner_);
port.ReceiveMessage(kReceiverId, kCastWebrtcNamespace, R"({
"seqNum": 12345,
"sessionId": 735189,
"type": "RPC",
"result": "ok",
"rpc": "SGVsbG8gZnJvbSB0aGUgQ2FzdCBSZWNlaXZlciE="
})");
// The message should just be ignored.
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_TRUE(message_store_.receiver_messages.empty());
}
TEST_F(SessionMessagerTest, UnknownNamespaceMessagesGetDropped) {
pipe_.right()->ReceiveMessage("urn:x-cast:com.google.cast.virtualreality",
R"({
"seqNum": 12345,
"sessionId": 735190,
"type": "RPC",
"rpc": "SGVsbG8gZnJvbSB0aGUgQ2FzdCBSZWNlaXZlciE="
})");
pipe_.left()->ReceiveMessage("urn:x-cast:com.google.cast.virtualreality", R"({
"seqNum": 12345,
"sessionId": 735190,
"type": "RPC",
"result": "ok",
"rpc": "SGVsbG8gZnJvbSB0aGUgQ2FzdCBTZW5kZXIh="
})");
// The message should just be ignored.
ASSERT_TRUE(message_store_.errors.empty());
ASSERT_TRUE(message_store_.sender_messages.empty());
ASSERT_TRUE(message_store_.receiver_messages.empty());
}
} // namespace cast
} // namespace openscreen