blob: 7ee439ff903d1eed4845a0e01a2c41856a54d2b8 [file] [log] [blame]
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "osp/public/presentation/presentation_controller.h"
#include <string>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "osp/impl/presentation/presentation_utils.h"
#include "osp/impl/presentation/testing/mock_connection_delegate.h"
#include "osp/impl/presentation/url_availability_requester.h"
#include "osp/impl/quic/testing/quic_test_support.h"
#include "osp/public/message_demuxer.h"
#include "osp/public/network_service_manager.h"
#include "osp/public/service_listener.h"
#include "osp/public/testing/message_demuxer_test_support.h"
#include "platform/test/fake_clock.h"
#include "platform/test/fake_task_runner.h"
namespace openscreen::osp {
using ::testing::_;
using ::testing::NiceMock;
namespace {
constexpr char kTestUrl1[] = "https://example.foo";
constexpr char kTestUrl2[] = "https://example.bar";
class MockServiceListenerDelegate final : public ServiceListener::Delegate {
public:
~MockServiceListenerDelegate() override = default;
ServiceListener* listener() { return listener_; }
MOCK_METHOD(void,
StartListener,
(const ServiceListener::Config& config),
(override));
MOCK_METHOD(void,
StartAndSuspendListener,
(const ServiceListener::Config& config),
(override));
MOCK_METHOD(void, StopListener, (), (override));
MOCK_METHOD(void, SuspendListener, (), (override));
MOCK_METHOD(void, ResumeListener, (), (override));
MOCK_METHOD(void, SearchNow, (ServiceListener::State from), (override));
MOCK_METHOD(void, RunTasksListener, ());
};
class MockReceiverObserver final : public ReceiverObserver {
public:
~MockReceiverObserver() override = default;
MOCK_METHOD(void,
OnRequestFailed,
(const std::string& presentation_url,
const std::string& instance_name),
(override));
MOCK_METHOD(void,
OnReceiverAvailable,
(const std::string& presentation_url,
const std::string& instance_name),
(override));
MOCK_METHOD(void,
OnReceiverUnavailable,
(const std::string& presentation_url,
const std::string& instance_name),
(override));
};
class MockRequestDelegate final : public RequestDelegate {
public:
MockRequestDelegate() = default;
~MockRequestDelegate() override = default;
void OnConnection(std::unique_ptr<Connection> connection) override {
OnConnectionMock(connection);
}
MOCK_METHOD(void,
OnConnectionMock,
(std::unique_ptr<Connection> & connection));
MOCK_METHOD(void, OnError, (const Error& error), (override));
};
} // namespace
class ControllerTest : public ::testing::Test {
public:
ControllerTest()
: fake_clock_(Clock::time_point(std::chrono::milliseconds(11111))),
task_runner_(fake_clock_),
quic_bridge_(task_runner_, FakeClock::now) {
receiver_info1 = {quic_bridge_.kInstanceName, quic_bridge_.kFingerprint,
quic_bridge_.kAuthToken, 1,
quic_bridge_.kReceiverEndpoint, {}};
}
protected:
void SetUp() override {
auto mock_listener_delegate =
std::make_unique<MockServiceListenerDelegate>();
mock_listener_delegate_ = mock_listener_delegate.get();
auto service_listener =
std::make_unique<ServiceListener>(std::move(mock_listener_delegate));
service_listener->AddObserver(*quic_bridge_.GetQuicClient());
quic_bridge_.CreateNetworkServiceManager(std::move(service_listener),
nullptr);
controller_ = std::make_unique<Controller>(FakeClock::now);
ON_CALL(quic_bridge_.mock_server_observer(), OnIncomingConnectionMock(_))
.WillByDefault([this](std::unique_ptr<ProtocolConnection>& connection) {
controller_instance_id_ = connection->GetInstanceID();
server_connections_.push_back(std::move(connection));
});
ON_CALL(quic_bridge_.mock_client_observer(), OnIncomingConnectionMock(_))
.WillByDefault([this](std::unique_ptr<ProtocolConnection>& connection) {
client_connections_.push_back(std::move(connection));
});
availability_watch_ =
quic_bridge_.GetReceiverDemuxer().SetDefaultMessageTypeWatch(
msgs::Type::kPresentationUrlAvailabilityRequest, &mock_callback_);
controller_->BuildConnection(quic_bridge_.kInstanceName);
quic_bridge_.RunTasksUntilIdle();
}
void TearDown() override {
availability_watch_.Reset();
controller_.reset();
}
void ExpectAvailabilityRequest(
msgs::PresentationUrlAvailabilityRequest& request) {
msgs::CborResult decode_result = -1;
msgs::Type msg_type;
EXPECT_CALL(mock_callback_, OnStreamMessage(_, _, _, _, _, _))
.WillOnce([&request, &msg_type, &decode_result](
uint64_t instance_id, uint64_t cid,
msgs::Type message_type, const uint8_t* buffer,
size_t buffer_size, Clock::time_point now) {
msg_type = message_type;
decode_result = msgs::DecodePresentationUrlAvailabilityRequest(
buffer, buffer_size, request);
return decode_result;
});
quic_bridge_.RunTasksUntilIdle();
ASSERT_EQ(msg_type, msgs::Type::kPresentationUrlAvailabilityRequest);
ASSERT_GT(decode_result, 0);
}
void SendAvailabilityResponse(
const msgs::PresentationUrlAvailabilityResponse& response) {
std::unique_ptr<ProtocolConnection> controller_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(controller_connection);
ASSERT_EQ(Error::Code::kNone,
controller_connection
->WriteMessage(
response, msgs::EncodePresentationUrlAvailabilityResponse)
.code());
}
void SendStartResponse(const msgs::PresentationStartResponse& response) {
std::unique_ptr<ProtocolConnection> protocol_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(protocol_connection);
ASSERT_EQ(
Error::Code::kNone,
protocol_connection
->WriteMessage(response, msgs::EncodePresentationStartResponse)
.code());
}
void SendAvailabilityEvent(
const msgs::PresentationUrlAvailabilityEvent& event) {
std::unique_ptr<ProtocolConnection> controller_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(controller_connection);
ASSERT_EQ(
Error::Code::kNone,
controller_connection
->WriteMessage(event, msgs::EncodePresentationUrlAvailabilityEvent)
.code());
}
void SendTerminationResponse(
const msgs::PresentationTerminationResponse& response) {
std::unique_ptr<ProtocolConnection> protocol_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(protocol_connection);
ASSERT_EQ(Error::Code::kNone,
protocol_connection
->WriteMessage(response,
msgs::EncodePresentationTerminationResponse)
.code());
}
void SendTerminationEvent(const msgs::PresentationTerminationEvent& event) {
std::unique_ptr<ProtocolConnection> protocol_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(protocol_connection);
ASSERT_EQ(
Error::Code::kNone,
protocol_connection
->WriteMessage(event, msgs::EncodePresentationTerminationEvent)
.code());
}
void ExpectCloseEvent(MockMessageCallback* mock_callback,
Connection* connection) {
msgs::CborResult decode_result = -1;
msgs::Type msg_type;
msgs::PresentationConnectionCloseEvent event;
EXPECT_CALL(*mock_callback, OnStreamMessage(_, _, _, _, _, _))
.WillOnce([&event, &msg_type, &decode_result](
uint64_t instance_id, uint64_t cid,
msgs::Type message_type, const uint8_t* buffer,
size_t buffer_size, Clock::time_point now) {
msg_type = message_type;
decode_result = msgs::DecodePresentationConnectionCloseEvent(
buffer, buffer_size, event);
return decode_result;
});
connection->Close(Connection::CloseReason::kClosed);
EXPECT_EQ(connection->state(), Connection::State::kClosed);
quic_bridge_.RunTasksUntilIdle();
ASSERT_EQ(msg_type, msgs::Type::kPresentationConnectionCloseEvent);
ASSERT_GT(decode_result, 0);
}
void SendCloseEvent(msgs::PresentationConnectionCloseEvent& event) {
std::unique_ptr<ProtocolConnection> protocol_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(protocol_connection);
ASSERT_EQ(
Error::Code::kNone,
protocol_connection
->WriteMessage(event, msgs::EncodePresentationConnectionCloseEvent)
.code());
}
void SendOpenResponse(
const msgs::PresentationConnectionOpenResponse& response) {
std::unique_ptr<ProtocolConnection> protocol_connection =
CreateServerProtocolConnection(controller_instance_id_);
ASSERT_TRUE(protocol_connection);
ASSERT_EQ(Error::Code::kNone,
protocol_connection
->WriteMessage(response,
msgs::EncodePresentationConnectionOpenResponse)
.code());
}
void StartPresentation(MockMessageCallback* mock_callback,
MockConnectionDelegate* mock_connection_delegate,
std::unique_ptr<Connection>* connection) {
MessageDemuxer::MessageWatch start_presentation_watch =
quic_bridge_.GetReceiverDemuxer().SetDefaultMessageTypeWatch(
msgs::Type::kPresentationStartRequest, mock_callback);
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
quic_bridge_.RunTasksUntilIdle();
MockRequestDelegate mock_request_delegate;
msgs::PresentationStartRequest request;
msgs::Type msg_type;
EXPECT_CALL(*mock_callback, OnStreamMessage(_, _, _, _, _, _))
.WillOnce([&request, &msg_type](
uint64_t instance_id, uint64_t cid,
msgs::Type message_type, const uint8_t* buffer,
size_t buffer_size, Clock::time_point now) {
msg_type = message_type;
const msgs::CborResult result = msgs::DecodePresentationStartRequest(
buffer, buffer_size, request);
return result;
});
Controller::ConnectRequest connect_request = controller_->StartPresentation(
"https://example.com/receiver.html", receiver_info1.instance_name,
&mock_request_delegate, mock_connection_delegate);
ASSERT_TRUE(connect_request);
quic_bridge_.RunTasksUntilIdle();
ASSERT_EQ(msgs::Type::kPresentationStartRequest, msg_type);
msgs::PresentationStartResponse response = {
.request_id = request.request_id,
.result = msgs::PresentationStartResponse_result::kSuccess,
.connection_id = 1};
SendStartResponse(response);
EXPECT_CALL(mock_request_delegate, OnConnectionMock(_))
.WillOnce([connection](std::unique_ptr<Connection>& c) {
*connection = std::move(c);
});
EXPECT_CALL(*mock_connection_delegate, OnConnected());
quic_bridge_.RunTasksUntilIdle();
ASSERT_TRUE(*connection);
}
FakeClock fake_clock_;
FakeTaskRunner task_runner_;
MessageDemuxer::MessageWatch availability_watch_;
MockMessageCallback mock_callback_;
FakeQuicBridge quic_bridge_;
MockServiceListenerDelegate* mock_listener_delegate_;
std::unique_ptr<Controller> controller_;
ServiceInfo receiver_info1;
MockReceiverObserver mock_receiver_observer_;
uint64_t controller_instance_id_ = 0;
std::vector<std::unique_ptr<ProtocolConnection>> server_connections_;
std::vector<std::unique_ptr<ProtocolConnection>> client_connections_;
};
TEST_F(ControllerTest, ReceiverWatchMoves) {
std::vector<std::string> urls = {"one fish", "two fish", "red fish",
"gnu fish"};
MockReceiverObserver mock_observer;
Controller::ReceiverWatch watch1(controller_.get(), urls, &mock_observer);
EXPECT_TRUE(watch1);
Controller::ReceiverWatch watch2;
EXPECT_FALSE(watch2);
watch2 = std::move(watch1);
EXPECT_FALSE(watch1);
EXPECT_TRUE(watch2);
Controller::ReceiverWatch watch3(std::move(watch2));
EXPECT_FALSE(watch2);
EXPECT_TRUE(watch3);
}
TEST_F(ControllerTest, ConnectRequestMoves) {
std::string instance_name = "instance-name1";
uint64_t request_id = 7;
Controller::ConnectRequest request1(controller_.get(), instance_name, false,
request_id);
EXPECT_TRUE(request1);
Controller::ConnectRequest request2;
EXPECT_FALSE(request2);
request2 = std::move(request1);
EXPECT_FALSE(request1);
EXPECT_TRUE(request2);
Controller::ConnectRequest request3(std::move(request2));
EXPECT_FALSE(request2);
EXPECT_TRUE(request3);
}
TEST_F(ControllerTest, ReceiverAvailable) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _));
quic_bridge_.RunTasksUntilIdle();
// `quic_bridge_.RunTasksUntilIdle()` is not used here to test availability is
// cached.
MockReceiverObserver mock_receiver_observer2;
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(_, _));
Controller::ReceiverWatch watch2 =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer2);
}
TEST_F(ControllerTest, ReceiverUnavailable) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _));
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, AvailabilityCacheIsTransient) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _));
quic_bridge_.RunTasksUntilIdle();
controller_->availability_requester()->RemoveObserverUrls(
{kTestUrl1}, &mock_receiver_observer_);
MockReceiverObserver mock_receiver_observer2;
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(_, _)).Times(0);
Controller::ReceiverWatch watch2 =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer2);
}
TEST_F(ControllerTest, AvailabilityPartiallyCachedAnswer) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _));
quic_bridge_.RunTasksUntilIdle();
MockReceiverObserver mock_receiver_observer2;
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(kTestUrl1, _))
.Times(0);
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(kTestUrl1, _));
Controller::ReceiverWatch watch2 = controller_->RegisterReceiverWatch(
{kTestUrl1, kTestUrl2}, &mock_receiver_observer2);
ExpectAvailabilityRequest(request);
quic_bridge_.RunTasksUntilIdle();
msgs::PresentationUrlAvailabilityResponse response2 = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response2);
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(kTestUrl2, _))
.Times(0);
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(kTestUrl2, _));
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, RemoveObserver) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
uint64_t url1_watch_id = request.watch_id;
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _));
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
quic_bridge_.RunTasksUntilIdle();
MockReceiverObserver mock_receiver_observer2;
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(kTestUrl1, _));
Controller::ReceiverWatch watch2 = controller_->RegisterReceiverWatch(
{kTestUrl1, kTestUrl2}, &mock_receiver_observer2);
ExpectAvailabilityRequest(request);
quic_bridge_.RunTasksUntilIdle();
controller_->availability_requester()->RemoveObserver(
&mock_receiver_observer_);
msgs::PresentationUrlAvailabilityResponse response2 = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response2);
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(kTestUrl2, _));
quic_bridge_.RunTasksUntilIdle();
msgs::PresentationUrlAvailabilityEvent event1 = {
.watch_id = url1_watch_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityEvent(event1);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(kTestUrl1, _));
quic_bridge_.RunTasksUntilIdle();
controller_->availability_requester()->RemoveObserver(
&mock_receiver_observer2);
msgs::PresentationUrlAvailabilityEvent event2 = {
.watch_id = url1_watch_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable}};
SendAvailabilityEvent(event2);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(_, _)).Times(0);
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, EventUpdate) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch = controller_->RegisterReceiverWatch(
{kTestUrl1, kTestUrl2}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable,
msgs::UrlAvailability::kAvailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(kTestUrl1, _));
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(kTestUrl2, _));
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
quic_bridge_.RunTasksUntilIdle();
msgs::PresentationUrlAvailabilityEvent event = {
.watch_id = request.watch_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable,
msgs::UrlAvailability::kUnavailable}};
SendAvailabilityEvent(event);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(kTestUrl2, _));
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, RefreshWatches) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _));
quic_bridge_.RunTasksUntilIdle();
fake_clock_.Advance(std::chrono::seconds(60));
controller_->availability_requester()->RefreshWatches();
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response2 = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable}};
SendAvailabilityResponse(response2);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _));
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, RemoveAvailabilityObserverInSteps) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
controller_->availability_requester()->RemoveObserverUrls(
{kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _)).Times(0);
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, ReceiverWatchCancel) {
mock_listener_delegate_->listener()->OnReceiverUpdated({receiver_info1});
Controller::ReceiverWatch watch =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer_);
msgs::PresentationUrlAvailabilityRequest request;
ExpectAvailabilityRequest(request);
msgs::PresentationUrlAvailabilityResponse response = {
.request_id = request.request_id,
.url_availabilities = {msgs::UrlAvailability::kAvailable}};
SendAvailabilityResponse(response);
EXPECT_CALL(mock_receiver_observer_, OnReceiverAvailable(_, _));
quic_bridge_.RunTasksUntilIdle();
MockReceiverObserver mock_receiver_observer2;
EXPECT_CALL(mock_receiver_observer2, OnReceiverAvailable(_, _));
Controller::ReceiverWatch watch2 =
controller_->RegisterReceiverWatch({kTestUrl1}, &mock_receiver_observer2);
watch.Reset();
msgs::PresentationUrlAvailabilityEvent event = {
.watch_id = request.watch_id,
.url_availabilities = {msgs::UrlAvailability::kUnavailable}};
EXPECT_CALL(mock_receiver_observer2, OnReceiverUnavailable(_, _));
EXPECT_CALL(mock_receiver_observer_, OnReceiverUnavailable(_, _)).Times(0);
SendAvailabilityEvent(event);
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, StartPresentation) {
MockMessageCallback mock_callback;
NiceMock<MockConnectionDelegate> mock_connection_delegate;
std::unique_ptr<Connection> connection;
StartPresentation(&mock_callback, &mock_connection_delegate, &connection);
}
TEST_F(ControllerTest, TerminatePresentationFromController) {
MockMessageCallback mock_callback;
MockConnectionDelegate mock_connection_delegate;
std::unique_ptr<Connection> connection;
StartPresentation(&mock_callback, &mock_connection_delegate, &connection);
MessageDemuxer::MessageWatch terminate_presentation_watch =
quic_bridge_.GetReceiverDemuxer().SetDefaultMessageTypeWatch(
msgs::Type::kPresentationTerminationRequest, &mock_callback);
msgs::PresentationTerminationRequest termination_request;
msgs::Type msg_type;
EXPECT_CALL(mock_callback, OnStreamMessage(_, _, _, _, _, _))
.WillOnce([&termination_request, &msg_type](
uint64_t instance_id, uint64_t cid, msgs::Type message_type,
const uint8_t* buffer, size_t buffer_size,
Clock::time_point now) {
msg_type = message_type;
const msgs::CborResult result =
msgs::DecodePresentationTerminationRequest(buffer, buffer_size,
termination_request);
return result;
});
connection->Terminate(TerminationSource::kController,
TerminationReason::kApplicationTerminated);
quic_bridge_.RunTasksUntilIdle();
ASSERT_EQ(msgs::Type::kPresentationTerminationRequest, msg_type);
msgs::PresentationTerminationResponse termination_response = {
.request_id = termination_request.request_id,
.result = msgs::PresentationTerminationResponse_result::kSuccess};
SendTerminationResponse(termination_response);
// TODO(btolsch): Check OnTerminated of other connections when reconnect
// lands.
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, TerminatePresentationFromReceiver) {
MockMessageCallback mock_callback;
MockConnectionDelegate mock_connection_delegate;
std::unique_ptr<Connection> connection;
StartPresentation(&mock_callback, &mock_connection_delegate, &connection);
msgs::PresentationTerminationEvent termination_event = {
.presentation_id = connection->presentation_info().id,
.source = msgs::PresentationTerminationSource::kReceiver,
.reason = msgs::PresentationTerminationReason::kApplicationRequest};
SendTerminationEvent(termination_event);
EXPECT_CALL(mock_connection_delegate, OnTerminated());
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, CloseConnection) {
MockMessageCallback mock_callback;
MockConnectionDelegate mock_connection_delegate;
std::unique_ptr<Connection> connection;
StartPresentation(&mock_callback, &mock_connection_delegate, &connection);
MessageDemuxer::MessageWatch close_event_watch =
quic_bridge_.GetReceiverDemuxer().SetDefaultMessageTypeWatch(
msgs::Type::kPresentationConnectionCloseEvent, &mock_callback);
ExpectCloseEvent(&mock_callback, connection.get());
}
TEST_F(ControllerTest, CloseConnectionFromPeer) {
MockMessageCallback mock_callback;
MockConnectionDelegate mock_connection_delegate;
std::unique_ptr<Connection> connection;
StartPresentation(&mock_callback, &mock_connection_delegate, &connection);
msgs::PresentationConnectionCloseEvent close_event = {
.connection_id = connection->connection_id(),
.reason =
msgs::PresentationConnectionCloseEvent_reason::kCloseMethodCalled,
.connection_count = 1,
.has_error_message = false};
SendCloseEvent(close_event);
EXPECT_CALL(mock_connection_delegate, OnClosedByRemote());
quic_bridge_.RunTasksUntilIdle();
}
TEST_F(ControllerTest, Reconnect) {
MockMessageCallback mock_callback;
NiceMock<MockConnectionDelegate> mock_connection_delegate;
std::unique_ptr<Connection> connection;
StartPresentation(&mock_callback, &mock_connection_delegate, &connection);
MessageDemuxer::MessageWatch close_event_watch =
quic_bridge_.GetReceiverDemuxer().SetDefaultMessageTypeWatch(
msgs::Type::kPresentationConnectionCloseEvent, &mock_callback);
ExpectCloseEvent(&mock_callback, connection.get());
quic_bridge_.RunTasksUntilIdle();
MessageDemuxer::MessageWatch connection_open_watch =
quic_bridge_.GetReceiverDemuxer().SetDefaultMessageTypeWatch(
msgs::Type::kPresentationConnectionOpenRequest, &mock_callback);
msgs::PresentationConnectionOpenRequest open_request;
MockRequestDelegate reconnect_delegate;
Controller::ConnectRequest reconnect_request =
controller_->ReconnectConnection(std::move(connection),
&reconnect_delegate);
ASSERT_TRUE(reconnect_request);
msgs::CborResult decode_result = -1;
msgs::Type msg_type;
EXPECT_CALL(mock_callback, OnStreamMessage(_, _, _, _, _, _))
.WillOnce([&open_request, &msg_type, &decode_result](
uint64_t instance_id, uint64_t cid, msgs::Type message_type,
const uint8_t* buffer, size_t buffer_size,
Clock::time_point now) {
msg_type = message_type;
decode_result = msgs::DecodePresentationConnectionOpenRequest(
buffer, buffer_size, open_request);
return decode_result;
});
quic_bridge_.RunTasksUntilIdle();
ASSERT_FALSE(connection);
ASSERT_EQ(msg_type, msgs::Type::kPresentationConnectionOpenRequest);
ASSERT_GT(decode_result, 0);
msgs::PresentationConnectionOpenResponse open_response = {
.request_id = open_request.request_id,
.result = msgs::PresentationConnectionOpenResponse_result::kSuccess,
.connection_id = 17,
.connection_count = 1ULL};
SendOpenResponse(open_response);
EXPECT_CALL(reconnect_delegate, OnConnectionMock(_))
.WillOnce([&connection](std::unique_ptr<Connection>& c) {
connection = std::move(c);
});
EXPECT_CALL(mock_connection_delegate, OnConnected());
quic_bridge_.RunTasksUntilIdle();
ASSERT_TRUE(connection);
EXPECT_EQ(connection->state(), Connection::State::kConnected);
}
} // namespace openscreen::osp