OLD | NEW |
| (Empty) |
1 // Copyright 2017 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/discovery/mdns/cast_media_sink_service.h" | |
6 #include "base/strings/stringprintf.h" | |
7 #include "base/test/mock_callback.h" | |
8 #include "base/timer/mock_timer.h" | |
9 #include "chrome/browser/media/router/discovery/mdns/mock_dns_sd_registry.h" | |
10 #include "chrome/browser/media/router/test_helper.h" | |
11 #include "chrome/test/base/testing_profile.h" | |
12 #include "components/cast_channel/cast_socket.h" | |
13 #include "components/cast_channel/cast_socket_service.h" | |
14 #include "components/cast_channel/cast_test_util.h" | |
15 #include "content/public/test/test_browser_thread_bundle.h" | |
16 #include "testing/gmock/include/gmock/gmock.h" | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 | |
19 using ::testing::_; | |
20 using ::testing::Return; | |
21 using ::testing::SaveArg; | |
22 | |
23 namespace { | |
24 | |
25 net::IPEndPoint CreateIPEndPoint(int num) { | |
26 net::IPAddress ip_address; | |
27 DCHECK(ip_address.AssignFromIPLiteral( | |
28 base::StringPrintf("192.168.0.10%d", num))); | |
29 return net::IPEndPoint(ip_address, 8009 + num); | |
30 } | |
31 | |
32 media_router::DnsSdService CreateDnsService(int num) { | |
33 net::IPEndPoint ip_endpoint = CreateIPEndPoint(num); | |
34 media_router::DnsSdService service; | |
35 service.service_name = | |
36 "_myDevice." + | |
37 std::string(media_router::CastMediaSinkService::kCastServiceType); | |
38 service.ip_address = ip_endpoint.address().ToString(); | |
39 service.service_host_port = ip_endpoint.ToString(); | |
40 service.service_data.push_back(base::StringPrintf("id=service %d", num)); | |
41 service.service_data.push_back( | |
42 base::StringPrintf("fn=friendly name %d", num)); | |
43 service.service_data.push_back(base::StringPrintf("md=model name %d", num)); | |
44 | |
45 return service; | |
46 } | |
47 | |
48 void VerifyMediaSinkInternal(const media_router::MediaSinkInternal& cast_sink, | |
49 const media_router::DnsSdService& service, | |
50 int channel_id, | |
51 bool audio_only) { | |
52 std::string id = base::StringPrintf("service %d", channel_id); | |
53 std::string name = base::StringPrintf("friendly name %d", channel_id); | |
54 std::string model_name = base::StringPrintf("model name %d", channel_id); | |
55 EXPECT_EQ(id, cast_sink.sink().id()); | |
56 EXPECT_EQ(name, cast_sink.sink().name()); | |
57 EXPECT_EQ(model_name, cast_sink.cast_data().model_name); | |
58 EXPECT_EQ(service.ip_address, cast_sink.cast_data().ip_address.ToString()); | |
59 | |
60 int capabilities = cast_channel::CastDeviceCapability::AUDIO_OUT; | |
61 if (!audio_only) | |
62 capabilities |= cast_channel::CastDeviceCapability::VIDEO_OUT; | |
63 EXPECT_EQ(capabilities, cast_sink.cast_data().capabilities); | |
64 EXPECT_EQ(channel_id, cast_sink.cast_data().cast_channel_id); | |
65 } | |
66 | |
67 } // namespace | |
68 | |
69 namespace media_router { | |
70 | |
71 class MockCastSocketService : public cast_channel::CastSocketService { | |
72 public: | |
73 MOCK_METHOD4(OpenSocket, | |
74 int(const net::IPEndPoint& ip_endpoint, | |
75 net::NetLog* net_log, | |
76 const cast_channel::CastSocket::OnOpenCallback& open_cb, | |
77 cast_channel::CastSocket::Observer* observer)); | |
78 MOCK_CONST_METHOD1(GetSocket, cast_channel::CastSocket*(int channel_id)); | |
79 | |
80 private: | |
81 ~MockCastSocketService() {} | |
82 }; | |
83 | |
84 class CastMediaSinkServiceTest : public ::testing::Test { | |
85 public: | |
86 CastMediaSinkServiceTest() | |
87 : mock_cast_socket_service_(new MockCastSocketService()), | |
88 media_sink_service_( | |
89 new CastMediaSinkService(mock_sink_discovered_cb_.Get(), | |
90 mock_cast_socket_service_.get())), | |
91 test_dns_sd_registry_(media_sink_service_.get()) {} | |
92 | |
93 void SetUp() override { | |
94 auto mock_timer = base::MakeUnique<base::MockTimer>( | |
95 true /*retain_user_task*/, false /*is_repeating*/); | |
96 mock_timer_ = mock_timer.get(); | |
97 media_sink_service_->SetTimerForTest(std::move(mock_timer)); | |
98 } | |
99 | |
100 protected: | |
101 const content::TestBrowserThreadBundle thread_bundle_; | |
102 TestingProfile profile_; | |
103 | |
104 base::MockCallback<MediaSinkService::OnSinksDiscoveredCallback> | |
105 mock_sink_discovered_cb_; | |
106 scoped_refptr<MockCastSocketService> mock_cast_socket_service_; | |
107 scoped_refptr<CastMediaSinkService> media_sink_service_; | |
108 MockDnsSdRegistry test_dns_sd_registry_; | |
109 base::MockTimer* mock_timer_; | |
110 | |
111 DISALLOW_COPY_AND_ASSIGN(CastMediaSinkServiceTest); | |
112 }; | |
113 | |
114 TEST_F(CastMediaSinkServiceTest, TestReStartAfterStop) { | |
115 EXPECT_CALL(test_dns_sd_registry_, AddObserver(media_sink_service_.get())) | |
116 .Times(2); | |
117 EXPECT_CALL(test_dns_sd_registry_, RegisterDnsSdListener(_)).Times(2); | |
118 EXPECT_FALSE(mock_timer_->IsRunning()); | |
119 media_sink_service_->SetDnsSdRegistryForTest(&test_dns_sd_registry_); | |
120 media_sink_service_->Start(); | |
121 EXPECT_TRUE(mock_timer_->IsRunning()); | |
122 | |
123 EXPECT_CALL(test_dns_sd_registry_, RemoveObserver(media_sink_service_.get())); | |
124 EXPECT_CALL(test_dns_sd_registry_, UnregisterDnsSdListener(_)); | |
125 media_sink_service_->Stop(); | |
126 | |
127 mock_timer_ = | |
128 new base::MockTimer(true /*retain_user_task*/, false /*is_repeating*/); | |
129 media_sink_service_->SetTimerForTest(base::WrapUnique(mock_timer_)); | |
130 media_sink_service_->SetDnsSdRegistryForTest(&test_dns_sd_registry_); | |
131 media_sink_service_->Start(); | |
132 EXPECT_TRUE(mock_timer_->IsRunning()); | |
133 } | |
134 | |
135 TEST_F(CastMediaSinkServiceTest, TestMultipleStartAndStop) { | |
136 EXPECT_CALL(test_dns_sd_registry_, AddObserver(media_sink_service_.get())); | |
137 EXPECT_CALL(test_dns_sd_registry_, RegisterDnsSdListener(_)); | |
138 media_sink_service_->SetDnsSdRegistryForTest(&test_dns_sd_registry_); | |
139 media_sink_service_->Start(); | |
140 media_sink_service_->Start(); | |
141 EXPECT_TRUE(mock_timer_->IsRunning()); | |
142 | |
143 EXPECT_CALL(test_dns_sd_registry_, RemoveObserver(media_sink_service_.get())); | |
144 EXPECT_CALL(test_dns_sd_registry_, UnregisterDnsSdListener(_)); | |
145 media_sink_service_->Stop(); | |
146 media_sink_service_->Stop(); | |
147 } | |
148 | |
149 TEST_F(CastMediaSinkServiceTest, TestOnChannelOpenedOnIOThread) { | |
150 DnsSdService service = CreateDnsService(1); | |
151 cast_channel::MockCastSocket socket; | |
152 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1)) | |
153 .WillOnce(Return(&socket)); | |
154 | |
155 media_sink_service_->current_services_.push_back(service); | |
156 media_sink_service_->OnChannelOpenedOnIOThread( | |
157 service, 1, cast_channel::ChannelError::NONE); | |
158 // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread. | |
159 base::RunLoop().RunUntilIdle(); | |
160 | |
161 // Verify sink content | |
162 EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size()); | |
163 for (const auto& sink_it : media_sink_service_->current_sinks_) | |
164 VerifyMediaSinkInternal(sink_it, service, 1, false); | |
165 } | |
166 | |
167 TEST_F(CastMediaSinkServiceTest, TestMultipleOnChannelOpenedOnIOThread) { | |
168 DnsSdService service1 = CreateDnsService(1); | |
169 DnsSdService service2 = CreateDnsService(2); | |
170 DnsSdService service3 = CreateDnsService(3); | |
171 | |
172 cast_channel::MockCastSocket socket2; | |
173 cast_channel::MockCastSocket socket3; | |
174 // Fail to open channel 1. | |
175 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1)) | |
176 .WillOnce(Return(nullptr)); | |
177 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(2)) | |
178 .WillOnce(Return(&socket2)); | |
179 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(3)) | |
180 .WillOnce(Return(&socket2)); | |
181 | |
182 // Current round of Dns discovery finds service1 and service 2. | |
183 media_sink_service_->current_services_.push_back(service1); | |
184 media_sink_service_->current_services_.push_back(service2); | |
185 media_sink_service_->OnChannelOpenedOnIOThread( | |
186 service1, 1, cast_channel::ChannelError::NONE); | |
187 media_sink_service_->OnChannelOpenedOnIOThread( | |
188 service2, 2, cast_channel::ChannelError::NONE); | |
189 media_sink_service_->OnChannelOpenedOnIOThread( | |
190 service3, 3, cast_channel::ChannelError::NONE); | |
191 // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread. | |
192 base::RunLoop().RunUntilIdle(); | |
193 | |
194 // Verify sink content | |
195 EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size()); | |
196 for (const auto& sink_it : media_sink_service_->current_sinks_) | |
197 VerifyMediaSinkInternal(sink_it, service2, 2, false); | |
198 } | |
199 | |
200 TEST_F(CastMediaSinkServiceTest, TestOnDnsSdEvent) { | |
201 DnsSdService service1 = CreateDnsService(1); | |
202 DnsSdService service2 = CreateDnsService(2); | |
203 net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); | |
204 net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); | |
205 | |
206 // Add dns services. | |
207 DnsSdRegistry::DnsSdServiceList service_list{service1, service2}; | |
208 | |
209 cast_channel::CastSocket::OnOpenCallback callback1; | |
210 cast_channel::CastSocket::OnOpenCallback callback2; | |
211 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _)) | |
212 .WillOnce(DoAll(SaveArg<2>(&callback1), Return(1))); | |
213 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)) | |
214 .WillOnce(DoAll(SaveArg<2>(&callback2), Return(2))); | |
215 | |
216 // Invoke CastSocketService::OpenSocket on the IO thread. | |
217 media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType, | |
218 service_list); | |
219 base::RunLoop().RunUntilIdle(); | |
220 | |
221 cast_channel::MockCastSocket socket1; | |
222 cast_channel::MockCastSocket socket2; | |
223 | |
224 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1)) | |
225 .WillOnce(Return(&socket1)); | |
226 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(2)) | |
227 .WillOnce(Return(&socket2)); | |
228 | |
229 callback1.Run(1, cast_channel::ChannelError::NONE); | |
230 callback2.Run(2, cast_channel::ChannelError::NONE); | |
231 | |
232 // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread. | |
233 base::RunLoop().RunUntilIdle(); | |
234 // Verify sink content | |
235 EXPECT_EQ(size_t(2), media_sink_service_->current_sinks_.size()); | |
236 } | |
237 | |
238 TEST_F(CastMediaSinkServiceTest, TestMultipleOnDnsSdEvent) { | |
239 DnsSdService service1 = CreateDnsService(1); | |
240 DnsSdService service2 = CreateDnsService(2); | |
241 DnsSdService service3 = CreateDnsService(3); | |
242 net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); | |
243 net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); | |
244 net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); | |
245 | |
246 // 1st round finds service 1 & 2. | |
247 DnsSdRegistry::DnsSdServiceList service_list1{service1, service2}; | |
248 media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType, | |
249 service_list1); | |
250 | |
251 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _)); | |
252 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)); | |
253 base::RunLoop().RunUntilIdle(); | |
254 | |
255 // Channel 2 opened. | |
256 media_sink_service_->OnChannelOpenedOnUIThread(service2, 2, false); | |
257 | |
258 // 2nd round finds service 2 & 3. | |
259 DnsSdRegistry::DnsSdServiceList service_list2{service2, service3}; | |
260 media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType, | |
261 service_list2); | |
262 | |
263 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)); | |
264 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint3, _, _, _)); | |
265 base::RunLoop().RunUntilIdle(); | |
266 | |
267 // Channel 1 and 3 opened. | |
268 media_sink_service_->OnChannelOpenedOnUIThread(service1, 1, false); | |
269 media_sink_service_->OnChannelOpenedOnUIThread(service3, 3, false); | |
270 | |
271 EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size()); | |
272 for (const auto& sink_it : media_sink_service_->current_sinks_) | |
273 VerifyMediaSinkInternal(sink_it, service3, 3, false); | |
274 } | |
275 | |
276 TEST_F(CastMediaSinkServiceTest, TestTimer) { | |
277 DnsSdService service1 = CreateDnsService(1); | |
278 DnsSdService service2 = CreateDnsService(2); | |
279 net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); | |
280 net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); | |
281 | |
282 EXPECT_FALSE(mock_timer_->IsRunning()); | |
283 // finds service 1 & 2. | |
284 DnsSdRegistry::DnsSdServiceList service_list1{service1, service2}; | |
285 media_sink_service_->OnDnsSdEvent(CastMediaSinkService::kCastServiceType, | |
286 service_list1); | |
287 | |
288 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _)); | |
289 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)); | |
290 base::RunLoop().RunUntilIdle(); | |
291 | |
292 // Channel 2 is opened. | |
293 media_sink_service_->OnChannelOpenedOnUIThread(service2, 2, false); | |
294 | |
295 std::vector<MediaSinkInternal> sinks; | |
296 EXPECT_CALL(mock_sink_discovered_cb_, Run(_)).WillOnce(SaveArg<0>(&sinks)); | |
297 | |
298 // Fire timer. | |
299 mock_timer_->Fire(); | |
300 EXPECT_EQ(size_t(1), sinks.size()); | |
301 VerifyMediaSinkInternal(sinks[0], service2, 2, false); | |
302 | |
303 EXPECT_FALSE(mock_timer_->IsRunning()); | |
304 // Channel 1 is opened and timer is restarted. | |
305 media_sink_service_->OnChannelOpenedOnUIThread(service1, 1, false); | |
306 EXPECT_TRUE(mock_timer_->IsRunning()); | |
307 } | |
308 | |
309 } // namespace media_router | |
OLD | NEW |