1 // Copyright 2018 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 "chrome/browser/media/router/providers/cast/cast_app_discovery_service.h"
6
7 #include "base/bind.h"
8 #include "base/test/simple_test_tick_clock.h"
9 #include "base/test/task_environment.h"
10 #include "base/test/test_simple_task_runner.h"
11 #include "chrome/browser/media/router/test/provider_test_helpers.h"
12 #include "components/cast_channel/cast_test_util.h"
13 #include "components/media_router/common/discovery/media_sink_service_base.h"
14 #include "components/media_router/common/providers/cast/cast_media_source.h"
15 #include "components/media_router/common/test/test_helper.h"
16 #include "content/public/test/browser_task_environment.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using cast_channel::GetAppAvailabilityResult;
21 using testing::_;
22 using testing::Invoke;
23
24 namespace media_router {
25
26 class CastAppDiscoveryServiceTest : public testing::Test {
27 public:
CastAppDiscoveryServiceTest()28 CastAppDiscoveryServiceTest()
29 : task_runner_(base::MakeRefCounted<base::TestSimpleTaskRunner>()),
30 socket_service_(task_runner_),
31 message_handler_(&socket_service_),
32 app_discovery_service_(
33 std::make_unique<CastAppDiscoveryServiceImpl>(&message_handler_,
34 &socket_service_,
35 &media_sink_service_,
36 &clock_)),
37 source_a_1_(
38 *CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=1")),
39 source_a_2_(
40 *CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=2")),
41 source_b_1_(
42 *CastMediaSource::FromMediaSourceId("cast:BBBBBBBB?clientId=1")) {
43 ON_CALL(socket_service_, GetSocket(_))
44 .WillByDefault(testing::Return(&socket_));
45 task_runner_->RunPendingTasks();
46 }
47
~CastAppDiscoveryServiceTest()48 ~CastAppDiscoveryServiceTest() override { task_runner_->RunPendingTasks(); }
49
50 MOCK_METHOD2(OnSinkQueryUpdated,
51 void(const MediaSource::Id&,
52 const std::vector<MediaSinkInternal>&));
53
AddOrUpdateSink(const MediaSinkInternal & sink)54 void AddOrUpdateSink(const MediaSinkInternal& sink) {
55 media_sink_service_.AddOrUpdateSink(sink);
56 }
57
RemoveSink(const MediaSinkInternal & sink)58 void RemoveSink(const MediaSinkInternal& sink) {
59 media_sink_service_.RemoveSink(sink);
60 }
61
StartObservingMediaSinksInitially(const CastMediaSource & source)62 CastAppDiscoveryService::Subscription StartObservingMediaSinksInitially(
63 const CastMediaSource& source) {
64 auto subscription = app_discovery_service_->StartObservingMediaSinks(
65 source,
66 base::BindRepeating(&CastAppDiscoveryServiceTest::OnSinkQueryUpdated,
67 base::Unretained(this)));
68 task_runner_->RunPendingTasks();
69 return subscription;
70 }
71
72 protected:
73 content::BrowserTaskEnvironment task_environment_;
74 scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
75 base::SimpleTestTickClock clock_;
76 testing::NiceMock<cast_channel::MockCastSocketService> socket_service_;
77 cast_channel::MockCastSocket socket_;
78 cast_channel::MockCastMessageHandler message_handler_;
79 TestMediaSinkService media_sink_service_;
80 std::unique_ptr<CastAppDiscoveryService> app_discovery_service_;
81 CastMediaSource source_a_1_;
82 CastMediaSource source_a_2_;
83 CastMediaSource source_b_1_;
84
85 private:
86 DISALLOW_COPY_AND_ASSIGN(CastAppDiscoveryServiceTest);
87 };
88
TEST_F(CastAppDiscoveryServiceTest,StartObservingMediaSinks)89 TEST_F(CastAppDiscoveryServiceTest, StartObservingMediaSinks) {
90 auto subscription1 = StartObservingMediaSinksInitially(source_a_1_);
91
92 // Adding a sink after app registered causes app availability request to be
93 // sent.
94 MediaSinkInternal sink1 = CreateCastSink(1);
95 cast_channel::GetAppAvailabilityCallback cb;
96 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
97 .WillOnce([&cb](cast_channel::CastSocket*, const std::string&,
98 cast_channel::GetAppAvailabilityCallback callback) {
99 cb = std::move(callback);
100 });
101
102 AddOrUpdateSink(sink1);
103
104 // Same app ID should not trigger another request.
105 EXPECT_CALL(message_handler_, RequestAppAvailability(_, _, _)).Times(0);
106 auto subscription2 = app_discovery_service_->StartObservingMediaSinks(
107 source_a_2_,
108 base::BindRepeating(&CastAppDiscoveryServiceTest::OnSinkQueryUpdated,
109 base::Unretained(this)));
110
111 std::vector<MediaSinkInternal> sinks_1 = {sink1};
112 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
113 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_2_.source_id(), sinks_1));
114 std::move(cb).Run("AAAAAAAA", GetAppAvailabilityResult::kAvailable);
115
116 // No more updates for |source_a_1_|.
117 subscription1.reset();
118 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), _)).Times(0);
119 EXPECT_CALL(*this,
120 OnSinkQueryUpdated(source_a_2_.source_id(), testing::IsEmpty()));
121 RemoveSink(sink1);
122 }
123
TEST_F(CastAppDiscoveryServiceTest,ReAddSinkQueryUsesCachedValue)124 TEST_F(CastAppDiscoveryServiceTest, ReAddSinkQueryUsesCachedValue) {
125 auto subscription1 = StartObservingMediaSinksInitially(source_a_1_);
126
127 // Adding a sink after app registered causes app availability request to be
128 // sent.
129 MediaSinkInternal sink1 = CreateCastSink(1);
130 cast_channel::GetAppAvailabilityCallback cb;
131 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
132 .WillOnce([&cb](cast_channel::CastSocket*, const std::string&,
133 cast_channel::GetAppAvailabilityCallback callback) {
134 cb = std::move(callback);
135 });
136
137 AddOrUpdateSink(sink1);
138
139 std::vector<MediaSinkInternal> sinks_1 = {sink1};
140 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
141 std::move(cb).Run("AAAAAAAA", GetAppAvailabilityResult::kAvailable);
142
143 subscription1.reset();
144
145 // Request not re-sent; cached kAvailable value is used.
146 EXPECT_CALL(message_handler_, RequestAppAvailability(_, _, _)).Times(0);
147 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
148 subscription1 = StartObservingMediaSinksInitially(source_a_1_);
149 }
150
TEST_F(CastAppDiscoveryServiceTest,SinkQueryUpdatedOnSinkUpdate)151 TEST_F(CastAppDiscoveryServiceTest, SinkQueryUpdatedOnSinkUpdate) {
152 auto subscription1 = StartObservingMediaSinksInitially(source_a_1_);
153
154 // Adding a sink after app registered causes app availability request to be
155 // sent.
156 MediaSinkInternal sink1 = CreateCastSink(1);
157 cast_channel::GetAppAvailabilityCallback cb;
158 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
159 .WillOnce([&cb](cast_channel::CastSocket*, const std::string&,
160 cast_channel::GetAppAvailabilityCallback callback) {
161 cb = std::move(callback);
162 });
163
164 AddOrUpdateSink(sink1);
165
166 // Query now includes |sink1|.
167 std::vector<MediaSinkInternal> sinks_1 = {sink1};
168 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
169 std::move(cb).Run("AAAAAAAA", GetAppAvailabilityResult::kAvailable);
170
171 // Updating |sink1| causes |source_a_1_| query to be updated.
172 sink1.sink().set_name("Updated name");
173 sinks_1 = {sink1};
174 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
175 AddOrUpdateSink(sink1);
176 }
177
TEST_F(CastAppDiscoveryServiceTest,Refresh)178 TEST_F(CastAppDiscoveryServiceTest, Refresh) {
179 auto subscription1 = StartObservingMediaSinksInitially(source_a_1_);
180 auto subscription2 = StartObservingMediaSinksInitially(source_b_1_);
181
182 MediaSinkInternal sink1 = CreateCastSink(1);
183 EXPECT_CALL(*this, OnSinkQueryUpdated(_, _));
184 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
185 .WillOnce([](cast_channel::CastSocket*, const std::string& app_id,
186 cast_channel::GetAppAvailabilityCallback callback) {
187 std::move(callback).Run(app_id, GetAppAvailabilityResult::kAvailable);
188 });
189 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "BBBBBBBB", _))
190 .WillOnce([](cast_channel::CastSocket*, const std::string& app_id,
191 cast_channel::GetAppAvailabilityCallback callback) {
192 std::move(callback).Run(app_id, GetAppAvailabilityResult::kUnknown);
193 });
194 AddOrUpdateSink(sink1);
195
196 MediaSinkInternal sink2 = CreateCastSink(2);
197 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
198 .WillOnce([](cast_channel::CastSocket*, const std::string& app_id,
199 cast_channel::GetAppAvailabilityCallback callback) {
200 std::move(callback).Run(app_id, GetAppAvailabilityResult::kUnavailable);
201 });
202 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "BBBBBBBB", _));
203 AddOrUpdateSink(sink2);
204
205 clock_.Advance(base::TimeDelta::FromSeconds(30));
206
207 // Request app availability for app B for both sinks.
208 // App A on |sink2| is not requested due to timing threshold.
209 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
210 .Times(0);
211 EXPECT_CALL(*this, OnSinkQueryUpdated(_, _)).Times(2);
212 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "BBBBBBBB", _))
213 .Times(2)
214 .WillRepeatedly([](cast_channel::CastSocket*, const std::string& app_id,
215 cast_channel::GetAppAvailabilityCallback callback) {
216 std::move(callback).Run(app_id, GetAppAvailabilityResult::kAvailable);
217 });
218 app_discovery_service_->Refresh();
219
220 clock_.Advance(base::TimeDelta::FromSeconds(31));
221
222 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _));
223 app_discovery_service_->Refresh();
224 }
225
TEST_F(CastAppDiscoveryServiceTest,StartObservingMediaSinksAfterSinkAdded)226 TEST_F(CastAppDiscoveryServiceTest, StartObservingMediaSinksAfterSinkAdded) {
227 // No registered apps.
228 MediaSinkInternal sink1 = CreateCastSink(1);
229 EXPECT_CALL(message_handler_, RequestAppAvailability(_, _, _)).Times(0);
230 AddOrUpdateSink(sink1);
231
232 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _));
233 auto subscription1 = app_discovery_service_->StartObservingMediaSinks(
234 source_a_1_,
235 base::BindRepeating(&CastAppDiscoveryServiceTest::OnSinkQueryUpdated,
236 base::Unretained(this)));
237
238 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "BBBBBBBB", _));
239 auto subscription2 = app_discovery_service_->StartObservingMediaSinks(
240 source_b_1_,
241 base::BindRepeating(&CastAppDiscoveryServiceTest::OnSinkQueryUpdated,
242 base::Unretained(this)));
243
244 // Adding new sink causes availability requests for 2 apps to be sent to the
245 // new sink.
246 MediaSinkInternal sink2 = CreateCastSink(2);
247 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _));
248 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "BBBBBBBB", _));
249 AddOrUpdateSink(sink2);
250 }
251
TEST_F(CastAppDiscoveryServiceTest,StartObservingMediaSinksCachedValue)252 TEST_F(CastAppDiscoveryServiceTest, StartObservingMediaSinksCachedValue) {
253 auto subscription1 = StartObservingMediaSinksInitially(source_a_1_);
254
255 // Adding a sink after app registered causes app availability request to be
256 // sent.
257 MediaSinkInternal sink1 = CreateCastSink(1);
258 cast_channel::GetAppAvailabilityCallback cb;
259 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
260 .WillOnce([&cb](cast_channel::CastSocket*, const std::string&,
261 cast_channel::GetAppAvailabilityCallback callback) {
262 cb = std::move(callback);
263 });
264 AddOrUpdateSink(sink1);
265
266 std::vector<MediaSinkInternal> sinks_1 = {sink1};
267 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
268 std::move(cb).Run("AAAAAAAA", GetAppAvailabilityResult::kAvailable);
269
270 // Same app ID should not trigger another request, but it should return
271 // cached value.
272 EXPECT_CALL(message_handler_, RequestAppAvailability(_, _, _)).Times(0);
273 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_2_.source_id(), sinks_1));
274 auto subscription2 = app_discovery_service_->StartObservingMediaSinks(
275 source_a_2_,
276 base::BindRepeating(&CastAppDiscoveryServiceTest::OnSinkQueryUpdated,
277 base::Unretained(this)));
278
279 // Same source as |source_a_1_|. The callback will be invoked.
280 auto source3 = CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=1");
281 ASSERT_TRUE(source3);
282 EXPECT_CALL(message_handler_, RequestAppAvailability(_, _, _)).Times(0);
283 EXPECT_CALL(*this, OnSinkQueryUpdated(source_a_1_.source_id(), sinks_1));
284 auto subscription3 = app_discovery_service_->StartObservingMediaSinks(
285 *source3,
286 base::BindRepeating(&CastAppDiscoveryServiceTest::OnSinkQueryUpdated,
287 base::Unretained(this)));
288 }
289
TEST_F(CastAppDiscoveryServiceTest,AvailabilityUnknownOrUnavailable)290 TEST_F(CastAppDiscoveryServiceTest, AvailabilityUnknownOrUnavailable) {
291 auto subscription1 = StartObservingMediaSinksInitially(source_a_1_);
292
293 // Adding a sink after app registered causes app availability request to be
294 // sent.
295 MediaSinkInternal sink1 = CreateCastSink(1);
296 EXPECT_CALL(*this, OnSinkQueryUpdated(_, _)).Times(0);
297 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
298 .WillOnce([](cast_channel::CastSocket*, const std::string&,
299 cast_channel::GetAppAvailabilityCallback callback) {
300 std::move(callback).Run("AAAAAAAA", GetAppAvailabilityResult::kUnknown);
301 });
302 AddOrUpdateSink(sink1);
303
304 // Sink updated and unknown app availability will cause request to be sent
305 // again.
306 EXPECT_CALL(*this, OnSinkQueryUpdated(_, _)).Times(0);
307 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
308 .WillOnce([](cast_channel::CastSocket*, const std::string&,
309 cast_channel::GetAppAvailabilityCallback callback) {
310 std::move(callback).Run("AAAAAAAA",
311 GetAppAvailabilityResult::kUnavailable);
312 });
313 AddOrUpdateSink(sink1);
314
315 // Known availability -- no request sent.
316 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _))
317 .Times(0);
318 AddOrUpdateSink(sink1);
319
320 // Removing the sink will also remove previous availability information.
321 // Next time sink is added, request will be sent.
322 EXPECT_CALL(*this, OnSinkQueryUpdated(_, _)).Times(0);
323 RemoveSink(sink1);
324
325 EXPECT_CALL(message_handler_, RequestAppAvailability(_, "AAAAAAAA", _));
326 AddOrUpdateSink(sink1);
327 }
328
329 } // namespace media_router
330