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_availability_tracker.h"
6 
7 #include "base/test/simple_test_tick_clock.h"
8 #include "components/cast_channel/cast_message_util.h"
9 #include "components/media_router/common/providers/cast/cast_media_source.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 
13 using cast_channel::GetAppAvailabilityResult;
14 
15 namespace media_router {
16 
17 namespace {
18 
19 MATCHER_P(CastMediaSourcesEqual, expected, "") {
20   if (expected.size() != arg.size())
21     return false;
22   return std::equal(
23       expected.begin(), expected.end(), arg.begin(),
__anonfc3cb5ae0202(const CastMediaSource& source1, const CastMediaSource& source2) 24       [](const CastMediaSource& source1, const CastMediaSource& source2) {
25         return source1.source_id() == source2.source_id();
26       });
27 }
28 
29 }  // namespace
30 
31 class CastAppAvailabilityTrackerTest : public testing::Test {
32  public:
CastAppAvailabilityTrackerTest()33   CastAppAvailabilityTrackerTest() {}
34   ~CastAppAvailabilityTrackerTest() override = default;
35 
Now() const36   base::TimeTicks Now() const { return clock_.NowTicks(); }
37 
38  protected:
39   base::SimpleTestTickClock clock_;
40   CastAppAvailabilityTracker tracker_;
41 
42  private:
43   DISALLOW_COPY_AND_ASSIGN(CastAppAvailabilityTrackerTest);
44 };
45 
TEST_F(CastAppAvailabilityTrackerTest,RegisterSource)46 TEST_F(CastAppAvailabilityTrackerTest, RegisterSource) {
47   auto source1 = CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=1");
48   ASSERT_TRUE(source1);
49   auto source2 = CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=2");
50   ASSERT_TRUE(source2);
51 
52   base::flat_set<std::string> expected_app_ids = {"AAAAAAAA"};
53   EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(*source1));
54 
55   expected_app_ids.clear();
56   EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(*source1));
57   EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(*source2));
58 
59   tracker_.UnregisterSource(*source1);
60   tracker_.UnregisterSource(*source2);
61 
62   expected_app_ids = {"AAAAAAAA"};
63   EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(*source1));
64   EXPECT_EQ(expected_app_ids, tracker_.GetRegisteredApps());
65 }
66 
TEST_F(CastAppAvailabilityTrackerTest,RegisterSourceReturnsMultipleAppIds)67 TEST_F(CastAppAvailabilityTrackerTest, RegisterSourceReturnsMultipleAppIds) {
68   auto source1 = CastMediaSource::FromMediaSourceId(
69       "urn:x-org.chromium.media:source:tab:1");
70   ASSERT_TRUE(source1);
71 
72   // Mirorring app ids.
73   base::flat_set<std::string> expected_app_ids = {"0F5096E8", "85CDB22F"};
74   EXPECT_EQ(expected_app_ids, tracker_.RegisterSource(*source1));
75   EXPECT_EQ(expected_app_ids, tracker_.GetRegisteredApps());
76 }
77 
TEST_F(CastAppAvailabilityTrackerTest,MultipleAppIdsAlreadyTrackingOne)78 TEST_F(CastAppAvailabilityTrackerTest, MultipleAppIdsAlreadyTrackingOne) {
79   // One of the mirroring app IDs.
80   auto source1 =
81       CastMediaSource::FromMediaSourceId("cast:0F5096E8?clientId=123");
82   ASSERT_TRUE(source1);
83 
84   base::flat_set<std::string> new_app_ids = {"0F5096E8"};
85   base::flat_set<std::string> registered_app_ids = {"0F5096E8"};
86   EXPECT_EQ(new_app_ids, tracker_.RegisterSource(*source1));
87   EXPECT_EQ(registered_app_ids, tracker_.GetRegisteredApps());
88 
89   auto source2 = CastMediaSource::FromMediaSourceId(
90       "urn:x-org.chromium.media:source:tab:1");
91   ASSERT_TRUE(source2);
92 
93   new_app_ids = {"85CDB22F"};
94   registered_app_ids = {"0F5096E8", "85CDB22F"};
95 
96   EXPECT_EQ(new_app_ids, tracker_.RegisterSource(*source2));
97   EXPECT_EQ(registered_app_ids, tracker_.GetRegisteredApps());
98 }
99 
TEST_F(CastAppAvailabilityTrackerTest,UpdateAppAvailability)100 TEST_F(CastAppAvailabilityTrackerTest, UpdateAppAvailability) {
101   auto source1 = CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=1");
102   ASSERT_TRUE(source1);
103   auto source2 = CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=2");
104   ASSERT_TRUE(source2);
105   auto source3 = CastMediaSource::FromMediaSourceId("cast:BBBBBBBB?clientId=3");
106   ASSERT_TRUE(source3);
107 
108   tracker_.RegisterSource(*source3);
109 
110   // |source3| not affected.
111   EXPECT_THAT(
112       tracker_.UpdateAppAvailability(
113           "sinkId1", "AAAAAAAA", {GetAppAvailabilityResult::kAvailable, Now()}),
114       CastMediaSourcesEqual(std::vector<CastMediaSource>()));
115 
116   base::flat_set<MediaSink::Id> sinks_1 = {"sinkId1"};
117   base::flat_set<MediaSink::Id> sinks_1_2 = {"sinkId1", "sinkId2"};
118   std::vector<CastMediaSource> sources_1 = {*source1};
119   std::vector<CastMediaSource> sources_1_2 = {*source1, *source2};
120 
121   // Tracker returns available sinks even though sources aren't registered.
122   EXPECT_EQ(sinks_1, tracker_.GetAvailableSinks(*source1));
123   EXPECT_EQ(sinks_1, tracker_.GetAvailableSinks(*source2));
124   EXPECT_TRUE(tracker_.GetAvailableSinks(*source3).empty());
125 
126   tracker_.RegisterSource(*source1);
127   // Only |source1| is registered for this app.
128   EXPECT_THAT(
129       tracker_.UpdateAppAvailability(
130           "sinkId2", "AAAAAAAA", {GetAppAvailabilityResult::kAvailable, Now()}),
131       CastMediaSourcesEqual(sources_1));
132   EXPECT_EQ(sinks_1_2, tracker_.GetAvailableSinks(*source1));
133   EXPECT_EQ(sinks_1_2, tracker_.GetAvailableSinks(*source2));
134   EXPECT_TRUE(tracker_.GetAvailableSinks(*source3).empty());
135 
136   tracker_.RegisterSource(*source2);
137   EXPECT_THAT(tracker_.UpdateAppAvailability(
138                   "sinkId2", "AAAAAAAA",
139                   {GetAppAvailabilityResult::kUnavailable, Now()}),
140               CastMediaSourcesEqual(sources_1_2));
141   EXPECT_EQ(sinks_1, tracker_.GetAvailableSinks(*source1));
142   EXPECT_EQ(sinks_1, tracker_.GetAvailableSinks(*source2));
143   EXPECT_TRUE(tracker_.GetAvailableSinks(*source3).empty());
144 }
145 
TEST_F(CastAppAvailabilityTrackerTest,RemoveResultsForSink)146 TEST_F(CastAppAvailabilityTrackerTest, RemoveResultsForSink) {
147   auto source1 = CastMediaSource::FromMediaSourceId("cast:AAAAAAAA?clientId=1");
148   ASSERT_TRUE(source1);
149 
150   tracker_.UpdateAppAvailability("sinkId1", "AAAAAAAA",
151                                  {GetAppAvailabilityResult::kAvailable, Now()});
152   EXPECT_EQ(GetAppAvailabilityResult::kAvailable,
153             tracker_.GetAvailability("sinkId1", "AAAAAAAA").first);
154 
155   base::flat_set<MediaSink::Id> expected_sink_ids = {"sinkId1"};
156   EXPECT_EQ(expected_sink_ids, tracker_.GetAvailableSinks(*source1));
157 
158   // Unrelated sink ID.
159   tracker_.RemoveResultsForSink("sinkId2");
160   EXPECT_EQ(GetAppAvailabilityResult::kAvailable,
161             tracker_.GetAvailability("sinkId1", "AAAAAAAA").first);
162   EXPECT_EQ(expected_sink_ids, tracker_.GetAvailableSinks(*source1));
163 
164   expected_sink_ids.clear();
165   tracker_.RemoveResultsForSink("sinkId1");
166   EXPECT_EQ(GetAppAvailabilityResult::kUnknown,
167             tracker_.GetAvailability("sinkId1", "AAAAAAAA").first);
168   EXPECT_EQ(expected_sink_ids, tracker_.GetAvailableSinks(*source1));
169 }
170 
171 }  // namespace media_router
172