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