blob: 8a7a5738075c8acb8e0882ed159b6abebbdfd0ae [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 "fuchsia/cast_streaming/cast_message_port_impl.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "components/cast/message_port/test_message_port_receiver.h"
#include "fuchsia/cast_streaming/message_serialization.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cast_streaming {
namespace {
const char kSenderId[] = "senderId";
} // namespace
class CastMessagePortImplTest : public testing::Test,
public openscreen::cast::MessagePort::Client {
public:
CastMessagePortImplTest() = default;
~CastMessagePortImplTest() override = default;
CastMessagePortImplTest(const CastMessagePortImplTest&) = delete;
CastMessagePortImplTest& operator=(const CastMessagePortImplTest&) = delete;
void SetUp() override {
std::unique_ptr<cast_api_bindings::MessagePort> receiver;
cast_api_bindings::MessagePort::CreatePair(&sender_message_port_,
&receiver);
sender_message_port_->SetReceiver(&sender_message_port_receiver_);
receiver_message_port_ = std::make_unique<CastMessagePortImpl>(
std::move(receiver),
base::BindOnce(&CastMessagePortImplTest::OnCastChannelClosed,
base::Unretained(this)));
receiver_message_port_->SetClient(this, kSenderId);
}
protected:
struct CastMessage {
std::string sender_id;
std::string message_namespace;
std::string message;
};
void RunUntilMessageCountIsAtLeast(size_t message_count) {
while (receiver_messages_.size() < message_count) {
base::RunLoop run_loop;
receiver_message_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
}
void RunUntilError() {
base::RunLoop run_loop;
error_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
void RunUntilCastChannelClosed() {
base::RunLoop run_loop;
cast_channel_closed_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
void OnCastChannelClosed() {
if (cast_channel_closed_closure_) {
std::move(cast_channel_closed_closure_).Run();
} else {
ADD_FAILURE() << "Cast Streaming Session MessagePort disconnected";
}
}
// openscreen::cast::MessagePort::Client implementation.
void OnMessage(const std::string& source_sender_id,
const std::string& message_namespace,
const std::string& message) override {
receiver_messages_.push_back(
{source_sender_id, message_namespace, message});
if (receiver_message_closure_) {
std::move(receiver_message_closure_).Run();
}
}
void OnError(openscreen::Error error) override {
latest_error_ = error;
if (error_closure_) {
std::move(error_closure_).Run();
}
}
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::SingleThreadTaskEnvironment::MainThreadType::IO};
openscreen::Error latest_error_ = openscreen::Error::None();
std::vector<CastMessage> receiver_messages_;
base::OnceClosure receiver_message_closure_;
base::OnceClosure error_closure_;
base::OnceClosure cast_channel_closed_closure_;
std::unique_ptr<CastMessagePortImpl> receiver_message_port_;
std::unique_ptr<cast_api_bindings::MessagePort> sender_message_port_;
cast_api_bindings::TestMessagePortReceiver sender_message_port_receiver_;
};
// Tests basic connection between the sender and receiver message port is
// working.
TEST_F(CastMessagePortImplTest, BasicConnection) {
std::string sender_id;
std::string message_namespace;
std::string message;
const std::string test_message = "testMessage";
// Check the initial connect message is properly sent.
sender_message_port_receiver_.RunUntilMessageCountEqual(1u);
ASSERT_EQ(sender_message_port_receiver_.buffer().size(), 1u);
ASSERT_TRUE(
DeserializeCastMessage(sender_message_port_receiver_.buffer().at(0).first,
&sender_id, &message_namespace, &message));
EXPECT_EQ(sender_id, kValueSystemSenderId);
EXPECT_EQ(message_namespace, kSystemNamespace);
EXPECT_EQ(message, kInitialConnectMessage);
// Check the the connection from the sender to the receiver is working.
sender_message_port_->PostMessage(
SerializeCastMessage(kSenderId, kMirroringNamespace, test_message));
RunUntilMessageCountIsAtLeast(1u);
ASSERT_EQ(receiver_messages_.size(), 1u);
EXPECT_EQ(receiver_messages_.at(0).sender_id, kSenderId);
EXPECT_EQ(receiver_messages_.at(0).message_namespace, kMirroringNamespace);
EXPECT_EQ(receiver_messages_.at(0).message, test_message);
// Check the connection from the receiver to the sender is working.
receiver_message_port_->PostMessage(kSenderId, kMirroringNamespace,
test_message);
sender_message_port_receiver_.RunUntilMessageCountEqual(2u);
ASSERT_EQ(sender_message_port_receiver_.buffer().size(), 2u);
ASSERT_TRUE(
DeserializeCastMessage(sender_message_port_receiver_.buffer().at(1).first,
&sender_id, &message_namespace, &message));
EXPECT_EQ(sender_id, kSenderId);
EXPECT_EQ(message_namespace, kMirroringNamespace);
EXPECT_EQ(message, test_message);
}
// Tests the "not supported" message is properly received for the inject
// message.
TEST_F(CastMessagePortImplTest, InjectMessage) {
const int kRequestId = 42;
base::Value inject_value(base::Value::Type::DICTIONARY);
inject_value.SetKey(kKeyType, base::Value(kValueWrapped));
inject_value.SetKey(kKeyRequestId, base::Value(kRequestId));
std::string inject_message;
ASSERT_TRUE(base::JSONWriter::Write(inject_value, &inject_message));
sender_message_port_->PostMessage(
SerializeCastMessage(kSenderId, kInjectNamespace, inject_message));
sender_message_port_receiver_.RunUntilMessageCountEqual(2u);
ASSERT_EQ(sender_message_port_receiver_.buffer().size(), 2u);
std::string sender_id;
std::string message_namespace;
std::string message;
ASSERT_TRUE(
DeserializeCastMessage(sender_message_port_receiver_.buffer().at(1).first,
&sender_id, &message_namespace, &message));
EXPECT_EQ(sender_id, kSenderId);
EXPECT_EQ(message_namespace, kInjectNamespace);
base::Optional<base::Value> return_value = base::JSONReader::Read(message);
ASSERT_TRUE(return_value);
ASSERT_TRUE(return_value->is_dict());
const std::string* type_value = return_value->FindStringKey(kKeyType);
ASSERT_TRUE(type_value);
EXPECT_EQ(*type_value, kValueError);
base::Optional<int> request_id_value =
return_value->FindIntKey(kKeyRequestId);
ASSERT_TRUE(request_id_value);
EXPECT_EQ(request_id_value.value(), kRequestId);
const std::string* data_value = return_value->FindStringKey(kKeyData);
ASSERT_TRUE(data_value);
EXPECT_EQ(*data_value, kValueInjectNotSupportedError);
const std::string* code_value = return_value->FindStringKey(kKeyCode);
ASSERT_TRUE(code_value);
EXPECT_EQ(*code_value, kValueWrappedError);
}
// Tests sending a bad message properly reports an error to Open Screen without
// crashing.
TEST_F(CastMessagePortImplTest, BadMessage) {
const std::string kBadMessage = "42";
sender_message_port_->PostMessage(kBadMessage);
RunUntilError();
EXPECT_EQ(latest_error_,
openscreen::Error(openscreen::Error::Code::kCastV2InvalidMessage));
}
// Tests closing the sender-end of the Cast Channel properly runs the closure.
TEST_F(CastMessagePortImplTest, CastChannelClosed) {
sender_message_port_.reset();
RunUntilCastChannelClosed();
}
} // namespace cast_streaming