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 const char SERVICE_TYPE[] = "_googlecast._tcp.local"; | |
mark a. foltz
2017/06/28 22:43:13
This duplicates the definition in cast_media_sink_
zhaobin
2017/07/05 18:01:37
Done.
| |
26 | |
27 net::IPEndPoint CreateIPEndPoint(int num) { | |
28 net::IPAddress ip_address; | |
29 DCHECK(ip_address.AssignFromIPLiteral( | |
30 base::StringPrintf("192.168.0.10%d", num))); | |
31 return net::IPEndPoint(ip_address, 8009 + num); | |
32 } | |
33 | |
34 media_router::DnsSdService CreateDnsService(int num) { | |
35 net::IPEndPoint ip_endpoint = CreateIPEndPoint(num); | |
36 media_router::DnsSdService service; | |
37 service.service_name = "_myDevice." + std::string(SERVICE_TYPE); | |
mark a. foltz
2017/06/28 22:43:13
I thing std::string is optional here.
zhaobin
2017/07/05 18:01:37
Compile error if removed...cannot add 'const char*
| |
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 EXPECT_TRUE(cast_channel::CastDeviceCapability::AUDIO_OUT & | |
60 cast_sink.cast_data().capabilities); | |
61 EXPECT_EQ(!audio_only, cast_channel::CastDeviceCapability::VIDEO_OUT & | |
62 cast_sink.cast_data().capabilities); | |
63 EXPECT_EQ(channel_id, cast_sink.cast_data().cast_channel_id); | |
64 } | |
65 | |
66 } // namespace | |
67 | |
68 namespace media_router { | |
69 | |
70 class MockCastSocketService : public cast_channel::CastSocketService { | |
71 public: | |
72 MOCK_METHOD4(OpenSocket, | |
73 int(const net::IPEndPoint& ip_endpoint, | |
74 net::NetLog* net_log, | |
75 const cast_channel::CastSocket::OnOpenCallback& open_cb, | |
76 cast_channel::CastSocket::Observer* observer)); | |
77 MOCK_CONST_METHOD1(GetSocket, cast_channel::CastSocket*(int channel_id)); | |
78 | |
79 private: | |
80 ~MockCastSocketService() {} | |
81 }; | |
82 | |
83 class CastMediaSinkServiceTest : public ::testing::Test { | |
84 public: | |
85 CastMediaSinkServiceTest() | |
86 : mock_cast_socket_service_(new MockCastSocketService()), | |
87 media_sink_service_( | |
88 new CastMediaSinkService(mock_sink_discovered_cb_.Get(), | |
89 mock_cast_socket_service_.get())), | |
90 test_dns_sd_registry_(media_sink_service_.get()) {} | |
91 | |
92 void SetUp() override { | |
93 media_sink_service_->SetDnsSdRegistryForTest(&test_dns_sd_registry_); | |
94 mock_timer_ = | |
95 new base::MockTimer(true /*retain_user_task*/, false /*is_repeating*/); | |
96 media_sink_service_->SetTimerForTest(base::WrapUnique(mock_timer_)); | |
97 } | |
98 | |
99 protected: | |
100 const content::TestBrowserThreadBundle thread_bundle_; | |
101 TestingProfile profile_; | |
102 | |
103 base::MockCallback<MediaSinkService::OnSinksDiscoveredCallback> | |
104 mock_sink_discovered_cb_; | |
105 scoped_refptr<MockCastSocketService> mock_cast_socket_service_; | |
106 scoped_refptr<CastMediaSinkService> media_sink_service_; | |
107 MockDnsSdRegistry test_dns_sd_registry_; | |
108 base::MockTimer* mock_timer_; | |
mark a. foltz
2017/06/28 22:43:13
Consider declaring this as std::unique_ptr and usi
zhaobin
2017/07/05 18:01:37
Ownership of |mock_timer_| is passed into MediaSin
| |
109 | |
110 DISALLOW_COPY_AND_ASSIGN(CastMediaSinkServiceTest); | |
111 }; | |
112 | |
113 TEST_F(CastMediaSinkServiceTest, TestReStartAfterStop) { | |
114 EXPECT_CALL(test_dns_sd_registry_, AddObserver(media_sink_service_.get())) | |
115 .Times(2); | |
116 EXPECT_CALL(test_dns_sd_registry_, RegisterDnsSdListener(_)).Times(2); | |
117 EXPECT_FALSE(mock_timer_->IsRunning()); | |
118 media_sink_service_->Start(); | |
119 EXPECT_TRUE(mock_timer_->IsRunning()); | |
120 | |
121 EXPECT_CALL(test_dns_sd_registry_, RemoveObserver(media_sink_service_.get())); | |
122 EXPECT_CALL(test_dns_sd_registry_, UnregisterDnsSdListener(_)); | |
123 media_sink_service_->Stop(); | |
124 | |
125 mock_timer_ = | |
126 new base::MockTimer(true /*retain_user_task*/, false /*is_repeating*/); | |
127 media_sink_service_->SetTimerForTest(base::WrapUnique(mock_timer_)); | |
128 media_sink_service_->Start(); | |
129 EXPECT_TRUE(mock_timer_->IsRunning()); | |
130 } | |
131 | |
132 TEST_F(CastMediaSinkServiceTest, TestMultipleStartAndStop) { | |
133 EXPECT_CALL(test_dns_sd_registry_, AddObserver(media_sink_service_.get())); | |
134 EXPECT_CALL(test_dns_sd_registry_, RegisterDnsSdListener(_)); | |
135 media_sink_service_->Start(); | |
136 media_sink_service_->Start(); | |
137 EXPECT_TRUE(mock_timer_->IsRunning()); | |
138 | |
139 EXPECT_CALL(test_dns_sd_registry_, RemoveObserver(media_sink_service_.get())); | |
140 EXPECT_CALL(test_dns_sd_registry_, UnregisterDnsSdListener(_)); | |
141 media_sink_service_->Stop(); | |
142 media_sink_service_->Stop(); | |
143 } | |
144 | |
145 TEST_F(CastMediaSinkServiceTest, TestOnChannelOpenedOnIOThread) { | |
146 DnsSdService service = CreateDnsService(1); | |
147 cast_channel::MockCastSocket socket; | |
148 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1)) | |
149 .WillOnce(Return(&socket)); | |
150 | |
151 media_sink_service_->current_services_.push_back(service); | |
152 media_sink_service_->OnChannelOpenedOnIOThread( | |
153 service, 1, cast_channel::ChannelError::NONE); | |
154 // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread. | |
155 base::RunLoop().RunUntilIdle(); | |
156 | |
157 // Verify sink content | |
158 EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size()); | |
159 for (const auto& sink_it : media_sink_service_->current_sinks_) | |
160 VerifyMediaSinkInternal(sink_it, service, 1, false); | |
161 } | |
162 | |
163 TEST_F(CastMediaSinkServiceTest, TestMultipleOnChannelOpenedOnIOThread) { | |
164 DnsSdService service1 = CreateDnsService(1); | |
165 DnsSdService service2 = CreateDnsService(2); | |
166 DnsSdService service3 = CreateDnsService(3); | |
167 | |
168 cast_channel::MockCastSocket socket2; | |
169 cast_channel::MockCastSocket socket3; | |
170 // Fail to open channel 1. | |
171 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1)) | |
172 .WillOnce(Return(nullptr)); | |
173 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(2)) | |
174 .WillOnce(Return(&socket2)); | |
175 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(3)) | |
176 .WillOnce(Return(&socket2)); | |
177 | |
178 // Current round of Dns discovery finds service1 and service 2. | |
179 media_sink_service_->current_services_.push_back(service1); | |
180 media_sink_service_->current_services_.push_back(service2); | |
181 media_sink_service_->OnChannelOpenedOnIOThread( | |
182 service1, 1, cast_channel::ChannelError::NONE); | |
183 media_sink_service_->OnChannelOpenedOnIOThread( | |
184 service2, 2, cast_channel::ChannelError::NONE); | |
185 media_sink_service_->OnChannelOpenedOnIOThread( | |
186 service3, 3, cast_channel::ChannelError::NONE); | |
187 // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread. | |
188 base::RunLoop().RunUntilIdle(); | |
189 | |
190 // Verify sink content | |
191 EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size()); | |
192 for (const auto& sink_it : media_sink_service_->current_sinks_) | |
193 VerifyMediaSinkInternal(sink_it, service2, 2, false); | |
194 } | |
195 | |
196 TEST_F(CastMediaSinkServiceTest, TestOnDnsSdEvent) { | |
197 DnsSdService service1 = CreateDnsService(1); | |
198 DnsSdService service2 = CreateDnsService(2); | |
199 net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); | |
200 net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); | |
201 | |
202 // Add dns services. | |
203 DnsSdRegistry::DnsSdServiceList service_list{service1, service2}; | |
204 | |
205 cast_channel::CastSocket::OnOpenCallback callback1; | |
206 cast_channel::CastSocket::OnOpenCallback callback2; | |
207 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _)) | |
208 .WillOnce(DoAll(SaveArg<2>(&callback1), Return(1))); | |
209 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)) | |
210 .WillOnce(DoAll(SaveArg<2>(&callback2), Return(2))); | |
211 | |
212 // Invoke CastSocketService::OpenSocket on the IO thread. | |
213 media_sink_service_->OnDnsSdEvent(SERVICE_TYPE, service_list); | |
214 base::RunLoop().RunUntilIdle(); | |
215 | |
216 cast_channel::MockCastSocket socket1; | |
217 cast_channel::MockCastSocket socket2; | |
218 | |
219 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(1)) | |
220 .WillOnce(Return(&socket1)); | |
221 EXPECT_CALL(*mock_cast_socket_service_, GetSocket(2)) | |
222 .WillOnce(Return(&socket2)); | |
223 | |
224 callback1.Run(1, cast_channel::ChannelError::NONE); | |
225 callback2.Run(2, cast_channel::ChannelError::NONE); | |
226 | |
227 // Invoke CastMediaSinkService::OnChannelOpenedOnUIThread on the UI thread. | |
228 base::RunLoop().RunUntilIdle(); | |
229 // Verify sink content | |
230 EXPECT_EQ(size_t(2), media_sink_service_->current_sinks_.size()); | |
231 } | |
232 | |
233 TEST_F(CastMediaSinkServiceTest, TestMultipleOnDnsSdEvent) { | |
234 DnsSdService service1 = CreateDnsService(1); | |
235 DnsSdService service2 = CreateDnsService(2); | |
236 DnsSdService service3 = CreateDnsService(3); | |
237 net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); | |
238 net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); | |
239 net::IPEndPoint ip_endpoint3 = CreateIPEndPoint(3); | |
240 | |
241 // 1st round finds service 1 & 2. | |
242 DnsSdRegistry::DnsSdServiceList service_list1{service1, service2}; | |
243 media_sink_service_->OnDnsSdEvent(SERVICE_TYPE, service_list1); | |
244 | |
245 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _)); | |
246 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)); | |
247 base::RunLoop().RunUntilIdle(); | |
248 | |
249 // Channel 2 opened. | |
250 media_sink_service_->OnChannelOpenedOnUIThread(service2, 2, false); | |
251 | |
252 // 2nd round finds service 2 & 3. | |
253 DnsSdRegistry::DnsSdServiceList service_list2{service2, service3}; | |
254 media_sink_service_->OnDnsSdEvent(SERVICE_TYPE, service_list2); | |
255 | |
256 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)); | |
257 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint3, _, _, _)); | |
258 base::RunLoop().RunUntilIdle(); | |
259 | |
260 // Channel 1 and 3 opened. | |
261 media_sink_service_->OnChannelOpenedOnUIThread(service1, 1, false); | |
262 media_sink_service_->OnChannelOpenedOnUIThread(service3, 3, false); | |
263 | |
264 EXPECT_EQ(size_t(1), media_sink_service_->current_sinks_.size()); | |
265 for (const auto& sink_it : media_sink_service_->current_sinks_) | |
266 VerifyMediaSinkInternal(sink_it, service3, 3, false); | |
267 } | |
268 | |
269 TEST_F(CastMediaSinkServiceTest, TestTimer) { | |
270 DnsSdService service1 = CreateDnsService(1); | |
271 DnsSdService service2 = CreateDnsService(2); | |
272 net::IPEndPoint ip_endpoint1 = CreateIPEndPoint(1); | |
273 net::IPEndPoint ip_endpoint2 = CreateIPEndPoint(2); | |
274 | |
275 EXPECT_FALSE(mock_timer_->IsRunning()); | |
276 // finds service 1 & 2. | |
277 DnsSdRegistry::DnsSdServiceList service_list1{service1, service2}; | |
278 media_sink_service_->OnDnsSdEvent(SERVICE_TYPE, service_list1); | |
279 | |
280 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint1, _, _, _)); | |
281 EXPECT_CALL(*mock_cast_socket_service_, OpenSocket(ip_endpoint2, _, _, _)); | |
282 base::RunLoop().RunUntilIdle(); | |
283 | |
284 // Channel 2 is opened. | |
285 media_sink_service_->OnChannelOpenedOnUIThread(service2, 2, false); | |
286 | |
287 std::vector<MediaSinkInternal> sinks; | |
288 EXPECT_CALL(mock_sink_discovered_cb_, Run(_)).WillOnce(SaveArg<0>(&sinks)); | |
289 | |
290 // Fire timer. | |
291 mock_timer_->Fire(); | |
292 EXPECT_EQ(size_t(1), sinks.size()); | |
293 VerifyMediaSinkInternal(sinks[0], service2, 2, false); | |
294 | |
295 EXPECT_FALSE(mock_timer_->IsRunning()); | |
296 // Channel 1 is opened and timer is restarted. | |
297 media_sink_service_->OnChannelOpenedOnUIThread(service1, 1, false); | |
298 EXPECT_TRUE(mock_timer_->IsRunning()); | |
299 } | |
300 | |
301 } // namespace media_router | |
OLD | NEW |