OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
mark a. foltz
2017/01/03 18:39:20
2017 :)
takumif
2017/01/03 23:29:51
Done. :)
| |
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 <memory> | |
6 #include <utility> | |
7 | |
8 #include "base/run_loop.h" | |
9 #include "content/public/test/test_browser_thread_bundle.h" | |
10 #include "content/renderer/presentation/presentation_dispatcher.h" | |
11 #include "testing/gmock/include/gmock/gmock.h" | |
12 #include "third_party/WebKit/public/platform/modules/presentation/WebPresentatio nAvailabilityObserver.h" | |
13 #include "third_party/WebKit/public/platform/modules/presentation/WebPresentatio nError.h" | |
14 #include "third_party/WebKit/public/platform/modules/presentation/WebPresentatio nSessionInfo.h" | |
15 #include "third_party/WebKit/public/web/WebArrayBuffer.h" | |
16 | |
17 using ::testing::_; | |
18 using ::testing::Invoke; | |
19 using blink::WebArrayBuffer; | |
20 using blink::WebPresentationAvailabilityCallbacks; | |
21 using blink::WebPresentationAvailabilityObserver; | |
22 using blink::WebPresentationConnectionCallback; | |
23 using blink::WebPresentationError; | |
24 using blink::WebPresentationSessionInfo; | |
25 using blink::WebString; | |
26 using blink::WebURL; | |
27 using blink::WebVector; | |
28 using blink::mojom::PresentationError; | |
29 using blink::mojom::PresentationErrorPtr; | |
30 using blink::mojom::PresentationErrorType; | |
31 using blink::mojom::PresentationService; | |
32 using blink::mojom::PresentationServiceClientPtr; | |
33 using blink::mojom::PresentationSessionInfo; | |
34 using blink::mojom::PresentationSessionInfoPtr; | |
35 using blink::mojom::ConnectionMessage; | |
36 using blink::mojom::ConnectionMessagePtr; | |
37 | |
38 // TODO(crbug.com/576808): Add test cases for the following: | |
39 // - State changes | |
40 // - Messages received | |
41 // - Discarding queued messages when the frame navigates | |
42 // - Screen availability not supported | |
43 // - Default presentation starting | |
44 | |
45 namespace content { | |
46 | |
47 class MockPresentationAvailabilityObserver | |
48 : public WebPresentationAvailabilityObserver { | |
49 public: | |
50 explicit MockPresentationAvailabilityObserver(WebURL url) : url_(url) {} | |
51 ~MockPresentationAvailabilityObserver() override {} | |
52 | |
53 MOCK_METHOD1(availabilityChanged, void(bool is_available)); | |
54 const WebURL url() const override { return url_; } | |
55 | |
56 private: | |
57 const WebURL url_; | |
58 }; | |
59 | |
60 class MockPresentationService : public PresentationService { | |
61 public: | |
62 void SetClient(PresentationServiceClientPtr client) override {} | |
63 MOCK_METHOD1(SetDefaultPresentationUrls, | |
64 void(const std::vector<GURL>& presentation_urls)); | |
65 MOCK_METHOD1(ListenForScreenAvailability, void(const GURL& availability_url)); | |
66 MOCK_METHOD1(StopListeningForScreenAvailability, | |
67 void(const GURL& availability_url)); | |
68 MOCK_METHOD2(StartSession, | |
69 void(const std::vector<GURL>& presentation_urls, | |
70 const StartSessionCallback& callback)); | |
71 MOCK_METHOD3(JoinSession, | |
72 void(const std::vector<GURL>& presentation_urls, | |
73 const base::Optional<std::string>& presentation_id, | |
74 const JoinSessionCallback& callback)); | |
75 | |
76 // *Internal method is to work around lack of support for move-only types in | |
77 // GMock. | |
78 void SendConnectionMessage( | |
79 PresentationSessionInfoPtr session_info, | |
80 ConnectionMessagePtr message_request, | |
81 const SendConnectionMessageCallback& callback) override { | |
82 SendConnectionMessageInternal(session_info.get(), message_request.get(), | |
83 callback); | |
84 } | |
85 MOCK_METHOD3(SendConnectionMessageInternal, | |
86 void(PresentationSessionInfo* session_info, | |
87 ConnectionMessage* message_request, | |
88 const SendConnectionMessageCallback& callback)); | |
89 | |
90 MOCK_METHOD2(CloseConnection, | |
91 void(const GURL& presentation_url, | |
92 const std::string& presentation_id)); | |
93 MOCK_METHOD2(Terminate, | |
94 void(const GURL& presentation_url, | |
95 const std::string& presentation_id)); | |
96 | |
97 // *Internal method is to work around lack of support for move-only types in | |
98 // GMock. | |
99 void ListenForConnectionMessages( | |
100 PresentationSessionInfoPtr session_info) override { | |
101 ListenForConnectionMessagesInternal(session_info.get()); | |
102 } | |
103 MOCK_METHOD1(ListenForConnectionMessagesInternal, | |
104 void(PresentationSessionInfo* session_info)); | |
105 }; | |
106 | |
107 class TestWebPresentationConnectionCallback | |
108 : public WebPresentationConnectionCallback { | |
109 public: | |
110 TestWebPresentationConnectionCallback(WebURL url, | |
111 WebString id, | |
112 bool* callback_called) | |
113 : url_(url), id_(id), callback_called_(callback_called) {} | |
114 ~TestWebPresentationConnectionCallback() override {} | |
115 | |
116 void onSuccess(const WebPresentationSessionInfo& info) override { | |
117 *callback_called_ = true; | |
mark a. foltz
2017/01/03 18:39:20
It seems like the only time you would instantiate
takumif
2017/01/03 23:29:50
Done.
| |
118 EXPECT_EQ(info.url, url_); | |
119 EXPECT_EQ(info.id, id_); | |
120 } | |
121 | |
122 private: | |
123 const WebURL url_; | |
124 const WebString id_; | |
125 bool* const callback_called_; | |
126 }; | |
127 | |
128 class TestWebPresentationConnectionErrorCallback | |
129 : public WebPresentationConnectionCallback { | |
130 public: | |
131 TestWebPresentationConnectionErrorCallback( | |
132 WebPresentationError::ErrorType error_type, | |
133 WebString message, | |
134 bool* callback_called) | |
135 : error_type_(error_type), | |
136 message_(message), | |
137 callback_called_(callback_called) {} | |
138 ~TestWebPresentationConnectionErrorCallback() override {} | |
139 | |
140 void onError(const WebPresentationError& error) override { | |
141 *callback_called_ = true; | |
mark a. foltz
2017/01/03 18:39:20
See comment above about making this a private memb
takumif
2017/01/03 23:29:50
Done.
| |
142 EXPECT_EQ(error.errorType, error_type_); | |
143 EXPECT_EQ(error.message, message_); | |
144 } | |
145 | |
146 private: | |
147 const WebPresentationError::ErrorType error_type_; | |
148 const WebString message_; | |
149 bool* const callback_called_; | |
150 }; | |
151 | |
152 class TestPresentationDispatcher : public PresentationDispatcher { | |
153 public: | |
154 explicit TestPresentationDispatcher( | |
155 MockPresentationService* presentation_service) | |
156 : PresentationDispatcher(nullptr), | |
157 mock_presentation_service_(presentation_service) {} | |
158 ~TestPresentationDispatcher() override {} | |
159 | |
160 private: | |
161 void ConnectToPresentationServiceIfNeeded() override { | |
162 if (!mock_binding_) { | |
163 mock_binding_ = base::MakeUnique<mojo::Binding<PresentationService>>( | |
164 mock_presentation_service_, | |
165 mojo::MakeRequest(&presentation_service_)); | |
166 } | |
167 } | |
168 | |
169 MockPresentationService* mock_presentation_service_; | |
170 std::unique_ptr<mojo::Binding<PresentationService>> mock_binding_; | |
171 }; | |
172 | |
173 class PresentationDispatcherTest : public ::testing::Test { | |
174 public: | |
175 PresentationDispatcherTest() | |
176 : gurl1_(GURL("https://www.example.com/1.html")), | |
177 gurl2_(GURL("https://www.example.com/2.html")), | |
178 gurls_({gurl1_, gurl2_}), | |
179 url1_(WebURL(gurl1_)), | |
180 url2_(WebURL(gurl2_)), | |
181 urls_(WebVector<WebURL>(gurls_)), | |
182 presentation_id_(WebString::fromUTF8("test-id")), | |
183 array_buffer_(WebArrayBuffer::create(4, 1)), | |
184 observer_(url1_) {} | |
185 ~PresentationDispatcherTest() override {} | |
186 | |
187 void SetUp() override { | |
188 presentation_service_ = base::MakeUnique<MockPresentationService>(); | |
mark a. foltz
2017/01/03 18:39:20
I don't see a reason why these can't be instantiat
takumif
2017/01/03 23:29:50
Done.
| |
189 dispatcher_ = | |
190 base::MakeUnique<TestPresentationDispatcher>(presentation_service()); | |
191 | |
192 // Set some test data. | |
193 *(static_cast<uint8_t*>(array_buffer_.data())) = 42; | |
194 } | |
195 | |
196 void TearDown() override { | |
197 dispatcher_.reset(); | |
198 presentation_service_.reset(); | |
199 } | |
200 | |
201 PresentationDispatcher* dispatcher() { return dispatcher_.get(); } | |
mark a. foltz
2017/01/03 18:39:20
It's common to declare objects used in test cases
takumif
2017/01/03 23:29:50
Done.
| |
202 MockPresentationService* presentation_service() { | |
203 return presentation_service_.get(); | |
204 } | |
205 | |
206 protected: | |
207 const GURL gurl1_; | |
208 const GURL gurl2_; | |
209 const std::vector<GURL> gurls_; | |
210 const WebURL url1_; | |
211 const WebURL url2_; | |
212 const WebVector<WebURL> urls_; | |
213 const WebString presentation_id_; | |
214 const WebArrayBuffer array_buffer_; | |
215 MockPresentationAvailabilityObserver observer_; | |
216 | |
217 private: | |
218 content::TestBrowserThreadBundle thread_bundle_; | |
219 std::unique_ptr<PresentationDispatcher> dispatcher_; | |
220 std::unique_ptr<MockPresentationService> presentation_service_; | |
221 }; | |
222 | |
223 TEST_F(PresentationDispatcherTest, TestStartSession) { | |
224 bool callback_called = false; | |
225 base::RunLoop run_loop; | |
226 | |
227 EXPECT_CALL(*presentation_service(), StartSession(gurls_, _)) | |
228 .WillOnce(Invoke([&]( | |
229 const std::vector<GURL>& presentation_urls, | |
230 const PresentationService::StartSessionCallback& callback) { | |
231 PresentationSessionInfoPtr session_info(PresentationSessionInfo::New()); | |
232 session_info->url = gurl1_; | |
233 session_info->id = presentation_id_.utf8(); | |
234 callback.Run(std::move(session_info), PresentationErrorPtr()); | |
235 })); | |
236 dispatcher()->startSession( | |
237 urls_, base::MakeUnique<TestWebPresentationConnectionCallback>( | |
238 url1_, presentation_id_, &callback_called)); | |
239 run_loop.RunUntilIdle(); | |
240 EXPECT_TRUE(callback_called); | |
241 } | |
242 | |
243 TEST_F(PresentationDispatcherTest, TestStartSessionError) { | |
244 WebString error_message = WebString::fromUTF8("Test error message"); | |
245 bool callback_called = false; | |
246 base::RunLoop run_loop; | |
247 | |
248 EXPECT_CALL(*presentation_service(), StartSession(gurls_, _)) | |
249 .WillOnce(Invoke( | |
250 [&](const std::vector<GURL>& presentation_urls, | |
mark a. foltz
2017/01/03 18:39:20
I slightly prefer explicit captures to default cap
takumif
2017/01/03 23:29:50
Done. Although I can capture |this| but not indivi
| |
251 const PresentationService::StartSessionCallback& callback) { | |
252 PresentationErrorPtr error(PresentationError::New()); | |
253 error->error_type = PresentationErrorType::NO_AVAILABLE_SCREENS; | |
254 error->message = error_message.utf8(); | |
255 callback.Run(PresentationSessionInfoPtr(), std::move(error)); | |
256 })); | |
257 dispatcher()->startSession( | |
258 urls_, base::MakeUnique<TestWebPresentationConnectionErrorCallback>( | |
259 WebPresentationError::ErrorTypeNoAvailableScreens, | |
260 error_message, &callback_called)); | |
261 run_loop.RunUntilIdle(); | |
262 EXPECT_TRUE(callback_called); | |
263 } | |
264 | |
265 TEST_F(PresentationDispatcherTest, TestJoinSessionError) { | |
266 WebString error_message = WebString::fromUTF8("Test error message"); | |
267 bool callback_called = false; | |
268 base::RunLoop run_loop; | |
269 | |
270 EXPECT_CALL(*presentation_service(), JoinSession(gurls_, _, _)) | |
271 .WillOnce( | |
272 Invoke([&](const std::vector<GURL>& presentation_urls, | |
273 const base::Optional<std::string>& presentation_id, | |
274 const PresentationService::JoinSessionCallback& callback) { | |
275 EXPECT_TRUE(presentation_id.has_value()); | |
276 EXPECT_EQ(presentation_id_.utf8(), presentation_id.value()); | |
277 PresentationErrorPtr error(PresentationError::New()); | |
278 error->error_type = PresentationErrorType::NO_AVAILABLE_SCREENS; | |
279 error->message = error_message.utf8(); | |
280 callback.Run(PresentationSessionInfoPtr(), std::move(error)); | |
281 })); | |
282 dispatcher()->joinSession( | |
283 urls_, presentation_id_, | |
284 base::MakeUnique<TestWebPresentationConnectionErrorCallback>( | |
285 WebPresentationError::ErrorTypeNoAvailableScreens, error_message, | |
286 &callback_called)); | |
287 run_loop.RunUntilIdle(); | |
288 EXPECT_TRUE(callback_called); | |
289 } | |
290 | |
291 TEST_F(PresentationDispatcherTest, TestJoinSession) { | |
292 bool callback_called = false; | |
293 base::RunLoop run_loop; | |
294 | |
295 EXPECT_CALL(*presentation_service(), JoinSession(gurls_, _, _)) | |
296 .WillOnce(Invoke([&]( | |
297 const std::vector<GURL>& presentation_urls, | |
298 const base::Optional<std::string>& presentation_id, | |
299 const PresentationService::JoinSessionCallback& callback) { | |
300 EXPECT_TRUE(presentation_id.has_value()); | |
301 EXPECT_EQ(presentation_id_.utf8(), presentation_id.value()); | |
302 PresentationSessionInfoPtr session_info(PresentationSessionInfo::New()); | |
303 session_info->url = gurl1_; | |
304 session_info->id = presentation_id_.utf8(); | |
305 callback.Run(std::move(session_info), PresentationErrorPtr()); | |
306 })); | |
307 dispatcher()->joinSession( | |
308 urls_, presentation_id_, | |
309 base::MakeUnique<TestWebPresentationConnectionCallback>( | |
310 url1_, presentation_id_, &callback_called)); | |
311 run_loop.RunUntilIdle(); | |
312 EXPECT_TRUE(callback_called); | |
313 } | |
314 | |
315 TEST_F(PresentationDispatcherTest, TestSendString) { | |
316 WebString message = WebString::fromUTF8("test message"); | |
317 base::RunLoop run_loop; | |
318 EXPECT_CALL(*presentation_service(), SendConnectionMessageInternal(_, _, _)) | |
319 .WillOnce(Invoke([&]( | |
320 PresentationSessionInfo* session_info, | |
321 ConnectionMessage* message_request, | |
322 const PresentationService::SendConnectionMessageCallback& callback) { | |
323 EXPECT_EQ(gurl1_, session_info->url); | |
324 EXPECT_EQ(presentation_id_.utf8(), session_info->id); | |
325 EXPECT_TRUE(message_request->message.has_value()); | |
326 EXPECT_EQ(message.utf8(), message_request->message.value()); | |
327 callback.Run(true); | |
328 })); | |
329 dispatcher()->sendString(url1_, presentation_id_, message); | |
330 run_loop.RunUntilIdle(); | |
331 } | |
332 | |
333 TEST_F(PresentationDispatcherTest, TestSendArrayBuffer) { | |
334 base::RunLoop run_loop; | |
335 EXPECT_CALL(*presentation_service(), SendConnectionMessageInternal(_, _, _)) | |
336 .WillOnce(Invoke([&]( | |
337 PresentationSessionInfo* session_info, | |
338 ConnectionMessage* message_request, | |
339 const PresentationService::SendConnectionMessageCallback& callback) { | |
340 EXPECT_EQ(gurl1_, session_info->url); | |
341 EXPECT_EQ(presentation_id_.utf8(), session_info->id); | |
342 std::vector<uint8_t> data( | |
343 static_cast<const uint8_t*>(array_buffer_.data()), | |
mark a. foltz
2017/01/03 18:39:20
Consider computing this pointer in the test base c
takumif
2017/01/03 23:29:50
Done.
| |
344 static_cast<const uint8_t*>(array_buffer_.data()) + | |
345 array_buffer_.byteLength()); | |
346 EXPECT_TRUE(message_request->data.has_value()); | |
347 EXPECT_EQ(data, message_request->data.value()); | |
348 callback.Run(true); | |
349 })); | |
350 dispatcher()->sendArrayBuffer( | |
351 url1_, presentation_id_, | |
352 static_cast<const uint8_t*>(array_buffer_.data()), | |
353 array_buffer_.byteLength()); | |
354 run_loop.RunUntilIdle(); | |
355 } | |
356 | |
357 TEST_F(PresentationDispatcherTest, TestSendBlobData) { | |
358 base::RunLoop run_loop; | |
359 EXPECT_CALL(*presentation_service(), SendConnectionMessageInternal(_, _, _)) | |
360 .WillOnce(Invoke([&]( | |
361 PresentationSessionInfo* session_info, | |
362 ConnectionMessage* message_request, | |
363 const PresentationService::SendConnectionMessageCallback& callback) { | |
364 EXPECT_EQ(gurl1_, session_info->url); | |
365 EXPECT_EQ(presentation_id_.utf8(), session_info->id); | |
366 std::vector<uint8_t> data( | |
367 static_cast<const uint8_t*>(array_buffer_.data()), | |
368 static_cast<const uint8_t*>(array_buffer_.data()) + | |
369 array_buffer_.byteLength()); | |
370 EXPECT_TRUE(message_request->data.has_value()); | |
371 EXPECT_EQ(data, message_request->data.value()); | |
372 callback.Run(true); | |
373 })); | |
374 dispatcher()->sendBlobData(url1_, presentation_id_, | |
375 static_cast<const uint8_t*>(array_buffer_.data()), | |
376 array_buffer_.byteLength()); | |
377 run_loop.RunUntilIdle(); | |
378 } | |
379 | |
380 TEST_F(PresentationDispatcherTest, TestCloseSession) { | |
381 base::RunLoop run_loop; | |
382 EXPECT_CALL(*presentation_service(), | |
383 CloseConnection(gurl1_, presentation_id_.utf8())); | |
384 dispatcher()->closeSession(url1_, presentation_id_); | |
385 run_loop.RunUntilIdle(); | |
386 } | |
387 | |
388 TEST_F(PresentationDispatcherTest, TestTerminateSession) { | |
389 base::RunLoop run_loop; | |
390 EXPECT_CALL(*presentation_service(), | |
391 Terminate(gurl1_, presentation_id_.utf8())); | |
392 dispatcher()->terminateSession(url1_, presentation_id_); | |
393 run_loop.RunUntilIdle(); | |
394 } | |
395 | |
396 TEST_F(PresentationDispatcherTest, TestListenForScreenAvailability) { | |
397 base::RunLoop run_loop1; | |
398 EXPECT_CALL(*presentation_service(), ListenForScreenAvailability(gurl1_)); | |
399 dispatcher()->getAvailability( | |
400 url1_, base::MakeUnique<WebPresentationAvailabilityCallbacks>()); | |
401 dispatcher()->OnScreenAvailabilityUpdated(url1_, true); | |
402 run_loop1.RunUntilIdle(); | |
403 | |
404 base::RunLoop run_loop2; | |
405 EXPECT_CALL(*presentation_service(), ListenForScreenAvailability(gurl1_)); | |
406 dispatcher()->startListening(&observer_); | |
407 run_loop2.RunUntilIdle(); | |
408 | |
409 base::RunLoop run_loop3; | |
410 EXPECT_CALL(observer_, availabilityChanged(false)); | |
411 dispatcher()->OnScreenAvailabilityUpdated(url1_, false); | |
412 EXPECT_CALL(observer_, availabilityChanged(true)); | |
413 dispatcher()->OnScreenAvailabilityUpdated(url1_, true); | |
414 EXPECT_CALL(*presentation_service(), | |
415 StopListeningForScreenAvailability(gurl1_)); | |
416 dispatcher()->stopListening(&observer_); | |
417 run_loop3.RunUntilIdle(); | |
418 | |
419 // After stopListening(), |observer_| should no longer be notified. | |
420 base::RunLoop run_loop4; | |
421 EXPECT_CALL(observer_, availabilityChanged(false)).Times(0); | |
422 dispatcher()->OnScreenAvailabilityUpdated(url1_, false); | |
423 run_loop4.RunUntilIdle(); | |
424 } | |
425 | |
426 TEST_F(PresentationDispatcherTest, TestSetDefaultPresentationUrls) { | |
427 base::RunLoop run_loop; | |
428 EXPECT_CALL(*presentation_service(), SetDefaultPresentationUrls(gurls_)); | |
429 dispatcher()->setDefaultPresentationUrls(urls_); | |
430 run_loop.RunUntilIdle(); | |
431 } | |
432 | |
433 } // namespace content | |
OLD | NEW |