Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: content/renderer/presentation/presentation_dispatcher_unittest.cc

Issue 2597853002: Unit test for PresentationDispatcher (Closed)
Patch Set: Address Mark's comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698