1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "osp/public/presentation/presentation_receiver.h"
6
7 #include <memory>
8
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11 #include "osp/impl/presentation/testing/mock_connection_delegate.h"
12 #include "osp/impl/quic/quic_client.h"
13 #include "osp/impl/quic/quic_server.h"
14 #include "osp/impl/quic/testing/fake_quic_connection_factory.h"
15 #include "osp/impl/quic/testing/quic_test_support.h"
16 #include "osp/public/network_service_manager.h"
17 #include "osp/public/protocol_connection_server.h"
18 #include "osp/public/testing/message_demuxer_test_support.h"
19 #include "platform/test/fake_clock.h"
20 #include "platform/test/fake_task_runner.h"
21
22 namespace openscreen {
23 namespace osp {
24
25 namespace {
26
27 using ::testing::_;
28 using ::testing::Invoke;
29 using ::testing::NiceMock;
30
31 class MockConnectRequest final
32 : public ProtocolConnectionClient::ConnectionRequestCallback {
33 public:
34 ~MockConnectRequest() override = default;
35
36 MOCK_METHOD2(OnConnectionOpened,
37 void(uint64_t request_id,
38 std::unique_ptr<ProtocolConnection> connection));
39 MOCK_METHOD1(OnConnectionFailed, void(uint64_t request_id));
40 };
41
42 class MockReceiverDelegate final : public ReceiverDelegate {
43 public:
44 ~MockReceiverDelegate() override = default;
45
46 MOCK_METHOD3(
47 OnUrlAvailabilityRequest,
48 std::vector<msgs::UrlAvailability>(uint64_t watch_id,
49 uint64_t watch_duration,
50 std::vector<std::string> urls));
51 MOCK_METHOD3(StartPresentation,
52 bool(const Connection::PresentationInfo& info,
53 uint64_t source_id,
54 const std::vector<msgs::HttpHeader>& http_headers));
55 MOCK_METHOD3(ConnectToPresentation,
56 bool(uint64_t request_id,
57 const std::string& id,
58 uint64_t source_id));
59 MOCK_METHOD2(TerminatePresentation,
60 void(const std::string& id, TerminationReason reason));
61 };
62
63 class PresentationReceiverTest : public ::testing::Test {
64 public:
PresentationReceiverTest()65 PresentationReceiverTest() {
66 fake_clock_ = std::make_unique<FakeClock>(
67 Clock::time_point(std::chrono::milliseconds(1298424)));
68 task_runner_ = std::make_unique<FakeTaskRunner>(fake_clock_.get());
69 quic_bridge_ =
70 std::make_unique<FakeQuicBridge>(task_runner_.get(), FakeClock::now);
71 }
72
73 protected:
MakeClientStream()74 std::unique_ptr<ProtocolConnection> MakeClientStream() {
75 MockConnectRequest mock_connect_request;
76 NetworkServiceManager::Get()->GetProtocolConnectionClient()->Connect(
77 quic_bridge_->kReceiverEndpoint, &mock_connect_request);
78 std::unique_ptr<ProtocolConnection> stream;
79 EXPECT_CALL(mock_connect_request, OnConnectionOpened(_, _))
80 .WillOnce([&stream](uint64_t request_id,
81 std::unique_ptr<ProtocolConnection> connection) {
82 stream = std::move(connection);
83 });
84 quic_bridge_->RunTasksUntilIdle();
85 return stream;
86 }
87
SetUp()88 void SetUp() override {
89 NetworkServiceManager::Create(nullptr, nullptr,
90 std::move(quic_bridge_->quic_client),
91 std::move(quic_bridge_->quic_server));
92 Receiver::Get()->Init();
93 Receiver::Get()->SetReceiverDelegate(&mock_receiver_delegate_);
94 }
95
TearDown()96 void TearDown() override {
97 Receiver::Get()->SetReceiverDelegate(nullptr);
98 Receiver::Get()->Deinit();
99 NetworkServiceManager::Dispose();
100 }
101
102 std::unique_ptr<FakeClock> fake_clock_;
103 std::unique_ptr<FakeTaskRunner> task_runner_;
104 const std::string url1_{"https://www.example.com/receiver.html"};
105 std::unique_ptr<FakeQuicBridge> quic_bridge_;
106 MockReceiverDelegate mock_receiver_delegate_;
107 };
108
109 } // namespace
110
111 // TODO(btolsch): Availability CL includes watch duration, so when that lands,
112 // also test proper updating here.
TEST_F(PresentationReceiverTest,QueryAvailability)113 TEST_F(PresentationReceiverTest, QueryAvailability) {
114 MockMessageCallback mock_callback;
115 MessageDemuxer::MessageWatch availability_watch =
116 quic_bridge_->controller_demuxer->SetDefaultMessageTypeWatch(
117 msgs::Type::kPresentationUrlAvailabilityResponse, &mock_callback);
118
119 std::unique_ptr<ProtocolConnection> stream = MakeClientStream();
120 ASSERT_TRUE(stream);
121
122 msgs::PresentationUrlAvailabilityRequest request{/* .request_id = */ 0,
123 /* .urls = */ {url1_},
124 /* .watch_duration = */ 0,
125 /* .watch_id = */ 0};
126 msgs::CborEncodeBuffer buffer;
127 ASSERT_TRUE(msgs::EncodePresentationUrlAvailabilityRequest(request, &buffer));
128 stream->Write(buffer.data(), buffer.size());
129
130 EXPECT_CALL(mock_receiver_delegate_, OnUrlAvailabilityRequest(_, _, _))
131 .WillOnce(Invoke([this](uint64_t watch_id, uint64_t watch_duration,
132 std::vector<std::string> urls) {
133 EXPECT_EQ(std::vector<std::string>{url1_}, urls);
134
135 return std::vector<msgs::UrlAvailability>{
136 msgs::UrlAvailability::kAvailable};
137 }));
138
139 msgs::PresentationUrlAvailabilityResponse response;
140 EXPECT_CALL(mock_callback, OnStreamMessage(_, _, _, _, _, _))
141 .WillOnce(
142 Invoke([&response](uint64_t endpoint_id, uint64_t cid,
143 msgs::Type message_type, const uint8_t* buffer,
144 size_t buffer_size, Clock::time_point now) {
145 ssize_t result = msgs::DecodePresentationUrlAvailabilityResponse(
146 buffer, buffer_size, &response);
147 return result;
148 }));
149 quic_bridge_->RunTasksUntilIdle();
150 EXPECT_EQ(request.request_id, response.request_id);
151 EXPECT_EQ(
152 (std::vector<msgs::UrlAvailability>{msgs::UrlAvailability::kAvailable}),
153 response.url_availabilities);
154 }
155
TEST_F(PresentationReceiverTest,StartPresentation)156 TEST_F(PresentationReceiverTest, StartPresentation) {
157 MockMessageCallback mock_callback;
158 MessageDemuxer::MessageWatch initiation_watch =
159 quic_bridge_->controller_demuxer->SetDefaultMessageTypeWatch(
160 msgs::Type::kPresentationStartResponse, &mock_callback);
161
162 std::unique_ptr<ProtocolConnection> stream = MakeClientStream();
163 ASSERT_TRUE(stream);
164
165 const std::string presentation_id = "KMvyNqTCvvSv7v5X";
166 msgs::PresentationStartRequest request;
167 request.request_id = 0;
168 request.presentation_id = presentation_id;
169 request.url = url1_;
170 request.headers = {msgs::HttpHeader{"Accept-Language", "de"}};
171 msgs::CborEncodeBuffer buffer;
172 ASSERT_TRUE(msgs::EncodePresentationStartRequest(request, &buffer));
173 stream->Write(buffer.data(), buffer.size());
174 Connection::PresentationInfo info;
175 EXPECT_CALL(mock_receiver_delegate_, StartPresentation(_, _, request.headers))
176 .WillOnce(::testing::DoAll(::testing::SaveArg<0>(&info),
177 ::testing::Return(true)));
178 quic_bridge_->RunTasksUntilIdle();
179 EXPECT_EQ(presentation_id, info.id);
180 EXPECT_EQ(url1_, info.url);
181
182 NiceMock<MockConnectionDelegate> null_connection_delegate;
183 Connection connection(Connection::PresentationInfo{presentation_id, url1_},
184 &null_connection_delegate, Receiver::Get());
185 Receiver::Get()->OnPresentationStarted(presentation_id, &connection,
186 ResponseResult::kSuccess);
187 msgs::PresentationStartResponse response;
188 EXPECT_CALL(mock_callback, OnStreamMessage(_, _, _, _, _, _))
189 .WillOnce(
190 Invoke([&response](uint64_t endpoint_id, uint64_t cid,
191 msgs::Type message_type, const uint8_t* buffer,
192 size_t buffer_size, Clock::time_point now) {
193 ssize_t result = msgs::DecodePresentationStartResponse(
194 buffer, buffer_size, &response);
195 return result;
196 }));
197 quic_bridge_->RunTasksUntilIdle();
198 EXPECT_EQ(msgs::Result::kSuccess, response.result);
199 EXPECT_EQ(connection.connection_id(), response.connection_id);
200 }
201
202 // TODO(btolsch): Connect and reconnect.
203 // TODO(btolsch): Terminate request and event.
204
205 } // namespace osp
206 } // namespace openscreen
207