Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / media / router / media_router_mojo_impl_unittest.cc
blobe24e60dd86104a7f8dcb1a5522717518f24b0224
1 // Copyright 2015 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.
5 #include <string>
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/run_loop.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chrome/browser/media/router/issue.h"
14 #include "chrome/browser/media/router/media_route.h"
15 #include "chrome/browser/media/router/media_router_mojo_test.h"
16 #include "chrome/browser/media/router/media_router_type_converters.h"
17 #include "chrome/browser/media/router/mock_media_router.h"
18 #include "chrome/browser/media/router/presentation_session_messages_observer.h"
19 #include "chrome/browser/media/router/test_helper.h"
20 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
21 #include "chrome/test/base/testing_browser_process.h"
22 #include "chrome/test/base/testing_profile.h"
23 #include "extensions/browser/extension_registry.h"
24 #include "extensions/browser/process_manager.h"
25 #include "extensions/browser/process_manager_factory.h"
26 #include "media/base/gmock_callback_support.h"
27 #include "mojo/message_pump/message_pump_mojo.h"
28 #include "testing/gmock/include/gmock/gmock.h"
29 #include "testing/gtest/include/gtest/gtest.h"
31 using testing::_;
32 using testing::Eq;
33 using testing::Invoke;
34 using testing::Mock;
35 using testing::Not;
36 using testing::Pointee;
37 using testing::Return;
38 using testing::ReturnRef;
39 using testing::SaveArg;
41 namespace media_router {
43 namespace {
45 const char kDescription[] = "description";
46 const char kError[] = "error";
47 const char kExtensionId[] = "extension1234";
48 const char kMessage[] = "message";
49 const char kSource[] = "source1";
50 const char kSource2[] = "source2";
51 const char kRouteId[] = "routeId";
52 const char kRouteId2[] = "routeId2";
53 const char kSinkId[] = "sink";
54 const char kSinkId2[] = "sink2";
55 const char kSinkName[] = "sinkName";
56 const char kPresentationId[] = "presentationId";
57 const char kOrigin[] = "http://origin/";
58 const int kTabId = 123;
59 const uint8 kBinaryMessage[] = {0x01, 0x02, 0x03, 0x04};
61 bool ArePresentationSessionMessagesEqual(
62 const content::PresentationSessionMessage* expected,
63 const content::PresentationSessionMessage* actual) {
64 if (expected->type != actual->type)
65 return false;
67 return expected->is_binary() ? *expected->data == *actual->data
68 : expected->message == actual->message;
71 interfaces::IssuePtr CreateMojoIssue(const std::string& title) {
72 interfaces::IssuePtr mojoIssue = interfaces::Issue::New();
73 mojoIssue->title = title;
74 mojoIssue->message = "msg";
75 mojoIssue->route_id = "";
76 mojoIssue->default_action =
77 interfaces::Issue::ActionType::ACTION_TYPE_DISMISS;
78 mojoIssue->secondary_actions =
79 mojo::Array<interfaces::Issue::ActionType>::New(0);
80 mojoIssue->severity = interfaces::Issue::Severity::SEVERITY_WARNING;
81 mojoIssue->is_blocking = false;
82 mojoIssue->help_url = "";
83 return mojoIssue.Pass();
86 } // namespace
88 class RouteResponseCallbackHandler {
89 public:
90 MOCK_METHOD3(Invoke,
91 void(const MediaRoute* route,
92 const std::string& presentation_id,
93 const std::string& error_text));
96 class SendMessageCallbackHandler {
97 public:
98 MOCK_METHOD1(Invoke, void(bool));
101 class ListenForMessagesCallbackHandler {
102 public:
103 ListenForMessagesCallbackHandler(
104 ScopedVector<content::PresentationSessionMessage> expected_messages,
105 bool pass_ownership)
106 : expected_messages_(expected_messages.Pass()),
107 pass_ownership_(pass_ownership) {}
108 void Invoke(const ScopedVector<content::PresentationSessionMessage>& messages,
109 bool pass_ownership) {
110 InvokeObserver();
111 EXPECT_EQ(pass_ownership_, pass_ownership);
112 EXPECT_EQ(messages.size(), expected_messages_.size());
113 for (size_t i = 0; i < expected_messages_.size(); ++i) {
114 EXPECT_TRUE(ArePresentationSessionMessagesEqual(expected_messages_[i],
115 messages[i]));
119 MOCK_METHOD0(InvokeObserver, void());
121 private:
122 ScopedVector<content::PresentationSessionMessage> expected_messages_;
123 bool pass_ownership_;
126 template <typename T>
127 void StoreAndRun(T* result, const base::Closure& closure, const T& result_val) {
128 *result = result_val;
129 closure.Run();
132 class MediaRouterMojoImplTest : public MediaRouterMojoTest {
133 public:
134 MediaRouterMojoImplTest() {}
135 ~MediaRouterMojoImplTest() override {}
138 // ProcessManager with a mocked method subset, for testing extension suspend
139 // handling.
140 class TestProcessManager : public extensions::ProcessManager {
141 public:
142 explicit TestProcessManager(content::BrowserContext* context)
143 : extensions::ProcessManager(
144 context,
145 context,
146 extensions::ExtensionRegistry::Get(context)) {}
147 ~TestProcessManager() override {}
149 static scoped_ptr<KeyedService> Create(content::BrowserContext* context) {
150 return make_scoped_ptr(new TestProcessManager(context));
153 MOCK_METHOD1(IsEventPageSuspended, bool(const std::string& ext_id));
155 MOCK_METHOD2(WakeEventPage,
156 bool(const std::string& extension_id,
157 const base::Callback<void(bool)>& callback));
159 private:
160 DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
163 // Mockable class for awaiting RegisterMediaRouteProvider callbacks.
164 class RegisterMediaRouteProviderHandler {
165 public:
166 MOCK_METHOD1(Invoke, void(const std::string& instance_id));
169 TEST_F(MediaRouterMojoImplTest, CreateRoute) {
170 MediaRoute expected_route(kRouteId, MediaSource(std::string(kSource)),
171 kSinkId, "", false, "", false);
172 interfaces::MediaRoutePtr route = interfaces::MediaRoute::New();
173 route->media_source = kSource;
174 route->media_sink_id = kSinkId;
175 route->media_route_id = kRouteId;
176 route->description = kDescription;
178 // Use a lambda function as an invocation target here to work around
179 // a limitation with GMock::Invoke that prevents it from using move-only types
180 // in runnable parameter lists.
181 EXPECT_CALL(mock_media_route_provider_,
182 CreateRoute(mojo::String(kSource), mojo::String(kSinkId), _,
183 mojo::String(kOrigin), kTabId, _))
184 .WillOnce(Invoke([&route](
185 const mojo::String& source, const mojo::String& sink,
186 const mojo::String& presentation_id, const mojo::String& origin,
187 int tab_id,
188 const interfaces::MediaRouteProvider::CreateRouteCallback& cb) {
189 cb.Run(route.Pass(), mojo::String());
190 }));
192 RouteResponseCallbackHandler handler;
193 EXPECT_CALL(handler, Invoke(Pointee(Equals(expected_route)), Not(""), ""));
194 std::vector<MediaRouteResponseCallback> route_response_callbacks;
195 route_response_callbacks.push_back(base::Bind(
196 &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler)));
197 router()->CreateRoute(kSource, kSinkId, GURL(kOrigin), kTabId,
198 route_response_callbacks);
199 ProcessEventLoop();
202 TEST_F(MediaRouterMojoImplTest, CreateRouteFails) {
203 EXPECT_CALL(mock_media_route_provider_,
204 CreateRoute(mojo::String(kSource), mojo::String(kSinkId), _,
205 mojo::String(kOrigin), kTabId, _))
206 .WillOnce(Invoke(
207 [](const mojo::String& source, const mojo::String& sink,
208 const mojo::String& presentation_id, const mojo::String& origin,
209 int tab_id,
210 const interfaces::MediaRouteProvider::CreateRouteCallback& cb) {
211 cb.Run(interfaces::MediaRoutePtr(), mojo::String(kError));
212 }));
214 RouteResponseCallbackHandler handler;
215 EXPECT_CALL(handler, Invoke(nullptr, "", kError));
216 std::vector<MediaRouteResponseCallback> route_response_callbacks;
217 route_response_callbacks.push_back(base::Bind(
218 &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler)));
219 router()->CreateRoute(kSource, kSinkId, GURL(kOrigin), kTabId,
220 route_response_callbacks);
221 ProcessEventLoop();
224 TEST_F(MediaRouterMojoImplTest, JoinRoute) {
225 MediaRoute expected_route(kRouteId, MediaSource(std::string(kSource)),
226 kSinkId, "", false, "", false);
227 interfaces::MediaRoutePtr route = interfaces::MediaRoute::New();
228 route->media_source = kSource;
229 route->media_sink_id = kSinkId;
230 route->media_route_id = kRouteId;
231 route->description = kDescription;
233 // Use a lambda function as an invocation target here to work around
234 // a limitation with GMock::Invoke that prevents it from using move-only types
235 // in runnable parameter lists.
236 EXPECT_CALL(mock_media_route_provider_,
237 JoinRoute(mojo::String(kSource), mojo::String(kPresentationId),
238 mojo::String(kOrigin), kTabId, _))
239 .WillOnce(Invoke([&route](
240 const mojo::String& source, const mojo::String& presentation_id,
241 const mojo::String& origin, int tab_id,
242 const interfaces::MediaRouteProvider::JoinRouteCallback& cb) {
243 cb.Run(route.Pass(), mojo::String());
244 }));
246 RouteResponseCallbackHandler handler;
247 EXPECT_CALL(handler, Invoke(Pointee(Equals(expected_route)), Not(""), ""));
248 std::vector<MediaRouteResponseCallback> route_response_callbacks;
249 route_response_callbacks.push_back(base::Bind(
250 &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler)));
251 router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), kTabId,
252 route_response_callbacks);
253 ProcessEventLoop();
256 TEST_F(MediaRouterMojoImplTest, JoinRouteFails) {
257 EXPECT_CALL(mock_media_route_provider_,
258 JoinRoute(mojo::String(kSource), mojo::String(kPresentationId),
259 mojo::String(kOrigin), kTabId, _))
260 .WillOnce(Invoke(
261 [](const mojo::String& source, const mojo::String& presentation_id,
262 const mojo::String& origin, int tab_id,
263 const interfaces::MediaRouteProvider::JoinRouteCallback& cb) {
264 cb.Run(interfaces::MediaRoutePtr(), mojo::String(kError));
265 }));
267 RouteResponseCallbackHandler handler;
268 EXPECT_CALL(handler, Invoke(nullptr, "", kError));
269 std::vector<MediaRouteResponseCallback> route_response_callbacks;
270 route_response_callbacks.push_back(base::Bind(
271 &RouteResponseCallbackHandler::Invoke, base::Unretained(&handler)));
272 router()->JoinRoute(kSource, kPresentationId, GURL(kOrigin), kTabId,
273 route_response_callbacks);
274 ProcessEventLoop();
277 TEST_F(MediaRouterMojoImplTest, CloseRoute) {
278 EXPECT_CALL(mock_media_route_provider_, CloseRoute(mojo::String(kRouteId)));
279 router()->CloseRoute(kRouteId);
280 ProcessEventLoop();
283 TEST_F(MediaRouterMojoImplTest, HandleIssue) {
284 MockIssuesObserver issue_observer1(router());
285 MockIssuesObserver issue_observer2(router());
286 interfaces::IssuePtr mojo_issue1 = CreateMojoIssue("title 1");
287 const Issue& expected_issue1 = mojo_issue1.To<Issue>();
289 const Issue* issue;
290 EXPECT_CALL(issue_observer1,
291 OnIssueUpdated(Pointee(EqualsIssue(expected_issue1))))
292 .WillOnce(SaveArg<0>(&issue));
293 EXPECT_CALL(issue_observer2,
294 OnIssueUpdated(Pointee(EqualsIssue(expected_issue1))));
295 media_router_proxy_->OnIssue(mojo_issue1.Pass());
296 ProcessEventLoop();
298 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer1));
299 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2));
301 EXPECT_CALL(issue_observer1, OnIssueUpdated(nullptr));
302 EXPECT_CALL(issue_observer2, OnIssueUpdated(nullptr));
304 router()->ClearIssue(issue->id());
306 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer1));
307 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2));
308 router()->UnregisterIssuesObserver(&issue_observer1);
309 interfaces::IssuePtr mojo_issue2 = CreateMojoIssue("title 2");
310 const Issue& expected_issue2 = mojo_issue2.To<Issue>();
312 EXPECT_CALL(issue_observer2,
313 OnIssueUpdated(Pointee(EqualsIssue(expected_issue2))));
314 router()->AddIssue(expected_issue2);
315 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2));
317 EXPECT_CALL(issue_observer2, OnIssueUpdated(nullptr));
318 router()->ClearIssue(issue->id());
319 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2));
321 EXPECT_CALL(issue_observer2,
322 OnIssueUpdated(Pointee(EqualsIssue(expected_issue2))));
323 media_router_proxy_->OnIssue(mojo_issue2.Pass());
324 ProcessEventLoop();
327 TEST_F(MediaRouterMojoImplTest, RegisterAndUnregisterMediaSinksObserver) {
328 MediaSource media_source(kSource);
330 MockMediaRouter mock_router;
331 EXPECT_CALL(mock_media_route_provider_,
332 StartObservingMediaSinks(mojo::String(kSource))).Times(2);
333 EXPECT_CALL(mock_media_route_provider_,
334 StartObservingMediaSinks(mojo::String(kSource2)));
336 MediaSinksObserver* captured_observer;
337 EXPECT_CALL(mock_router, RegisterMediaSinksObserver(_))
338 .Times(3)
339 .WillRepeatedly(SaveArg<0>(&captured_observer));
341 MockMediaSinksObserver sinks_observer(&mock_router, media_source);
342 EXPECT_EQ(&sinks_observer, captured_observer);
343 router()->RegisterMediaSinksObserver(&sinks_observer);
344 MockMediaSinksObserver extra_sinks_observer(&mock_router, media_source);
345 EXPECT_EQ(&extra_sinks_observer, captured_observer);
346 router()->RegisterMediaSinksObserver(&extra_sinks_observer);
347 MockMediaSinksObserver unrelated_sinks_observer(&mock_router,
348 MediaSource(kSource2));
349 EXPECT_EQ(&unrelated_sinks_observer, captured_observer);
350 router()->RegisterMediaSinksObserver(&unrelated_sinks_observer);
352 std::vector<MediaSink> expected_sinks;
353 expected_sinks.push_back(
354 MediaSink(kSinkId, kSinkName, MediaSink::IconType::CAST));
355 expected_sinks.push_back(
356 MediaSink(kSinkId2, kSinkName, MediaSink::IconType::CAST));
358 mojo::Array<interfaces::MediaSinkPtr> mojo_sinks(2);
359 mojo_sinks[0] = interfaces::MediaSink::New();
360 mojo_sinks[0]->sink_id = kSinkId;
361 mojo_sinks[0]->name = kSinkName;
362 mojo_sinks[0]->icon_type =
363 media_router::interfaces::MediaSink::IconType::ICON_TYPE_CAST;
364 mojo_sinks[1] = interfaces::MediaSink::New();
365 mojo_sinks[1]->sink_id = kSinkId2;
366 mojo_sinks[1]->name = kSinkName;
367 mojo_sinks[1]->icon_type =
368 media_router::interfaces::MediaSink::IconType::ICON_TYPE_CAST;
370 EXPECT_CALL(sinks_observer, OnSinksReceived(SequenceEquals(expected_sinks)));
371 EXPECT_CALL(extra_sinks_observer,
372 OnSinksReceived(SequenceEquals(expected_sinks)));
373 media_router_proxy_->OnSinksReceived(media_source.id(), mojo_sinks.Pass());
374 ProcessEventLoop();
376 EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&sinks_observer));
377 EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&extra_sinks_observer));
378 EXPECT_CALL(mock_router,
379 UnregisterMediaSinksObserver(&unrelated_sinks_observer));
380 EXPECT_CALL(mock_media_route_provider_,
381 StopObservingMediaSinks(mojo::String(kSource)));
382 EXPECT_CALL(mock_media_route_provider_,
383 StopObservingMediaSinks(mojo::String(kSource2)));
384 router()->UnregisterMediaSinksObserver(&sinks_observer);
385 router()->UnregisterMediaSinksObserver(&extra_sinks_observer);
386 router()->UnregisterMediaSinksObserver(&unrelated_sinks_observer);
387 ProcessEventLoop();
390 TEST_F(MediaRouterMojoImplTest, RegisterAndUnregisterMediaRoutesObserver) {
391 MockMediaRouter mock_router;
392 EXPECT_CALL(mock_media_route_provider_, StartObservingMediaRoutes()).Times(2);
394 MediaRoutesObserver* observer_captured;
395 EXPECT_CALL(mock_router, RegisterMediaRoutesObserver(_))
396 .Times(2)
397 .WillRepeatedly(SaveArg<0>(&observer_captured));
398 MockMediaRoutesObserver routes_observer(&mock_router);
399 EXPECT_EQ(observer_captured, &routes_observer);
400 MockMediaRoutesObserver extra_routes_observer(&mock_router);
401 EXPECT_EQ(observer_captured, &extra_routes_observer);
402 router()->RegisterMediaRoutesObserver(&routes_observer);
403 router()->RegisterMediaRoutesObserver(&extra_routes_observer);
405 std::vector<MediaRoute> expected_routes;
406 expected_routes.push_back(MediaRoute(kRouteId, MediaSource(kSource), kSinkId,
407 kDescription, false, "", false));
408 expected_routes.push_back(MediaRoute(kRouteId2, MediaSource(kSource), kSinkId,
409 kDescription, false, "", false));
411 mojo::Array<interfaces::MediaRoutePtr> mojo_routes(2);
412 mojo_routes[0] = interfaces::MediaRoute::New();
413 mojo_routes[0]->media_route_id = kRouteId;
414 mojo_routes[0]->media_source = kSource;
415 mojo_routes[0]->media_sink_id = kSinkId;
416 mojo_routes[0]->description = kDescription;
417 mojo_routes[0]->is_local = false;
418 mojo_routes[1] = interfaces::MediaRoute::New();
419 mojo_routes[1]->media_route_id = kRouteId2;
420 mojo_routes[1]->media_source = kSource;
421 mojo_routes[1]->media_sink_id = kSinkId;
422 mojo_routes[1]->description = kDescription;
423 mojo_routes[1]->is_local = false;
425 EXPECT_CALL(routes_observer,
426 OnRoutesUpdated(SequenceEquals(expected_routes)));
427 EXPECT_CALL(extra_routes_observer,
428 OnRoutesUpdated(SequenceEquals(expected_routes)));
429 media_router_proxy_->OnRoutesUpdated(mojo_routes.Pass());
430 ProcessEventLoop();
432 EXPECT_CALL(mock_router, UnregisterMediaRoutesObserver(&routes_observer));
433 EXPECT_CALL(mock_router,
434 UnregisterMediaRoutesObserver(&extra_routes_observer));
435 router()->UnregisterMediaRoutesObserver(&routes_observer);
436 router()->UnregisterMediaRoutesObserver(&extra_routes_observer);
437 EXPECT_CALL(mock_media_route_provider_, StopObservingMediaRoutes());
438 ProcessEventLoop();
441 TEST_F(MediaRouterMojoImplTest, SendRouteMessage) {
442 EXPECT_CALL(
443 mock_media_route_provider_,
444 SendRouteMessage(mojo::String(kRouteId), mojo::String(kMessage), _))
445 .WillOnce(Invoke([](
446 const MediaRoute::Id& route_id, const std::string& message,
447 const interfaces::MediaRouteProvider::SendRouteMessageCallback& cb) {
448 cb.Run(true);
449 }));
451 SendMessageCallbackHandler handler;
452 EXPECT_CALL(handler, Invoke(true));
453 router()->SendRouteMessage(kRouteId, kMessage,
454 base::Bind(&SendMessageCallbackHandler::Invoke,
455 base::Unretained(&handler)));
456 ProcessEventLoop();
459 TEST_F(MediaRouterMojoImplTest, SendRouteBinaryMessage) {
460 scoped_ptr<std::vector<uint8>> expected_binary_data(new std::vector<uint8>(
461 kBinaryMessage, kBinaryMessage + arraysize(kBinaryMessage)));
463 EXPECT_CALL(mock_media_route_provider_,
464 SendRouteBinaryMessageInternal(mojo::String(kRouteId), _, _))
465 .WillOnce(Invoke([](
466 const MediaRoute::Id& route_id, const std::vector<uint8>& data,
467 const interfaces::MediaRouteProvider::SendRouteMessageCallback& cb) {
468 EXPECT_EQ(
469 0, memcmp(kBinaryMessage, &(data[0]), arraysize(kBinaryMessage)));
470 cb.Run(true);
471 }));
473 SendMessageCallbackHandler handler;
474 EXPECT_CALL(handler, Invoke(true));
475 router()->SendRouteBinaryMessage(
476 kRouteId, expected_binary_data.Pass(),
477 base::Bind(&SendMessageCallbackHandler::Invoke,
478 base::Unretained(&handler)));
479 ProcessEventLoop();
482 TEST_F(MediaRouterMojoImplTest, PresentationSessionMessagesSingleObserver) {
483 mojo::Array<interfaces::RouteMessagePtr> mojo_messages(2);
484 mojo_messages[0] = interfaces::RouteMessage::New();
485 mojo_messages[0]->type = interfaces::RouteMessage::Type::TYPE_TEXT;
486 mojo_messages[0]->message = "text";
487 mojo_messages[1] = interfaces::RouteMessage::New();
488 mojo_messages[1]->type = interfaces::RouteMessage::Type::TYPE_BINARY;
489 mojo_messages[1]->data.push_back(1);
491 ScopedVector<content::PresentationSessionMessage> expected_messages;
492 scoped_ptr<content::PresentationSessionMessage> message;
493 message.reset(new content::PresentationSessionMessage(
494 content::PresentationMessageType::TEXT));
495 message->message = "text";
496 expected_messages.push_back(message.Pass());
498 message.reset(new content::PresentationSessionMessage(
499 content::PresentationMessageType::ARRAY_BUFFER));
500 message->data.reset(new std::vector<uint8_t>(1, 1));
501 expected_messages.push_back(message.Pass());
503 MediaRoute::Id expected_route_id("foo");
504 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback;
505 EXPECT_CALL(mock_media_route_provider_,
506 ListenForRouteMessages(Eq(expected_route_id), _))
507 .WillOnce(SaveArg<1>(&mojo_callback));
509 // |pass_ownership| param is "true" here because there is only one observer.
510 ListenForMessagesCallbackHandler handler(expected_messages.Pass(), true);
512 EXPECT_CALL(handler, InvokeObserver());
513 // Creating PresentationSessionMessagesObserver will register itself to the
514 // MediaRouter, which in turn will start listening for route messages.
515 scoped_ptr<PresentationSessionMessagesObserver> observer(
516 new PresentationSessionMessagesObserver(
517 base::Bind(&ListenForMessagesCallbackHandler::Invoke,
518 base::Unretained(&handler)),
519 expected_route_id, router()));
520 ProcessEventLoop();
522 // Simulate messages by invoking the saved mojo callback.
523 // We expect one more ListenForRouteMessages call since |observer| was
524 // still registered when the first set of messages arrived.
525 mojo_callback.Run(mojo_messages.Pass(), false);
526 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback
527 mojo_callback_2;
528 EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(_, _))
529 .WillOnce(SaveArg<1>(&mojo_callback_2));
530 ProcessEventLoop();
532 // Stop listening for messages. In particular, MediaRouterMojoImpl will not
533 // call ListenForRouteMessages again when it sees there are no more observers.
534 mojo::Array<interfaces::RouteMessagePtr> mojo_messages_2(1);
535 mojo_messages_2[0] = interfaces::RouteMessage::New();
536 mojo_messages_2[0]->type = interfaces::RouteMessage::Type::TYPE_TEXT;
537 mojo_messages_2[0]->message = "foo";
538 observer.reset();
539 mojo_callback_2.Run(mojo_messages_2.Pass(), false);
540 EXPECT_CALL(mock_media_route_provider_, StopListeningForRouteMessages(_));
541 ProcessEventLoop();
544 TEST_F(MediaRouterMojoImplTest, PresentationSessionMessagesMultipleObservers) {
545 mojo::Array<interfaces::RouteMessagePtr> mojo_messages(2);
546 mojo_messages[0] = interfaces::RouteMessage::New();
547 mojo_messages[0]->type = interfaces::RouteMessage::Type::TYPE_TEXT;
548 mojo_messages[0]->message = "text";
549 mojo_messages[1] = interfaces::RouteMessage::New();
550 mojo_messages[1]->type = interfaces::RouteMessage::Type::TYPE_BINARY;
551 mojo_messages[1]->data.push_back(1);
553 ScopedVector<content::PresentationSessionMessage> expected_messages;
554 scoped_ptr<content::PresentationSessionMessage> message;
555 message.reset(new content::PresentationSessionMessage(
556 content::PresentationMessageType::TEXT));
557 message->message = "text";
558 expected_messages.push_back(message.Pass());
560 message.reset(new content::PresentationSessionMessage(
561 content::PresentationMessageType::ARRAY_BUFFER));
562 message->data.reset(new std::vector<uint8_t>(1, 1));
563 expected_messages.push_back(message.Pass());
565 MediaRoute::Id expected_route_id("foo");
566 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback;
567 EXPECT_CALL(mock_media_route_provider_,
568 ListenForRouteMessages(Eq(expected_route_id), _))
569 .WillOnce(SaveArg<1>(&mojo_callback));
571 // |pass_ownership| param is "false" here because there are more than one
572 // observers.
573 ListenForMessagesCallbackHandler handler(expected_messages.Pass(), false);
575 EXPECT_CALL(handler, InvokeObserver()).Times(2);
576 // Creating PresentationSessionMessagesObserver will register itself to the
577 // MediaRouter, which in turn will start listening for route messages.
578 scoped_ptr<PresentationSessionMessagesObserver> observer1(
579 new PresentationSessionMessagesObserver(
580 base::Bind(&ListenForMessagesCallbackHandler::Invoke,
581 base::Unretained(&handler)),
582 expected_route_id, router()));
583 scoped_ptr<PresentationSessionMessagesObserver> observer2(
584 new PresentationSessionMessagesObserver(
585 base::Bind(&ListenForMessagesCallbackHandler::Invoke,
586 base::Unretained(&handler)),
587 expected_route_id, router()));
588 ProcessEventLoop();
590 // Simulate messages by invoking the saved mojo callback.
591 // We expect one more ListenForRouteMessages call since |observer| was
592 // still registered when the first set of messages arrived.
593 mojo_callback.Run(mojo_messages.Pass(), false);
594 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback
595 mojo_callback_2;
596 EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(_, _))
597 .WillOnce(SaveArg<1>(&mojo_callback_2));
598 ProcessEventLoop();
600 // Stop listening for messages. In particular, MediaRouterMojoImpl will not
601 // call ListenForRouteMessages again when it sees there are no more observers.
602 mojo::Array<interfaces::RouteMessagePtr> mojo_messages_2(1);
603 mojo_messages_2[0] = interfaces::RouteMessage::New();
604 mojo_messages_2[0]->type = interfaces::RouteMessage::Type::TYPE_TEXT;
605 mojo_messages_2[0]->message = "foo";
606 observer1.reset();
607 observer2.reset();
608 mojo_callback_2.Run(mojo_messages_2.Pass(), false);
609 EXPECT_CALL(mock_media_route_provider_, StopListeningForRouteMessages(_));
610 ProcessEventLoop();
613 TEST_F(MediaRouterMojoImplTest, PresentationSessionMessagesError) {
614 MediaRoute::Id expected_route_id("foo");
615 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback;
616 EXPECT_CALL(mock_media_route_provider_,
617 ListenForRouteMessages(Eq(expected_route_id), _))
618 .WillOnce(SaveArg<1>(&mojo_callback));
620 ListenForMessagesCallbackHandler handler(
621 ScopedVector<content::PresentationSessionMessage>(), true);
623 // Creating PresentationSessionMessagesObserver will register itself to the
624 // MediaRouter, which in turn will start listening for route messages.
625 scoped_ptr<PresentationSessionMessagesObserver> observer1(
626 new PresentationSessionMessagesObserver(
627 base::Bind(&ListenForMessagesCallbackHandler::Invoke,
628 base::Unretained(&handler)),
629 expected_route_id, router()));
630 ProcessEventLoop();
632 mojo_callback.Run(mojo::Array<interfaces::RouteMessagePtr>(0), true);
633 ProcessEventLoop();
636 TEST_F(MediaRouterMojoImplTest, QueuedWhileAsleep) {
637 EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
638 .Times(2)
639 .WillRepeatedly(Return(true));
640 EXPECT_CALL(mock_event_page_tracker_, WakeEventPage(extension_id(), _))
641 .Times(2)
642 .WillRepeatedly(Return(true));
643 router()->CloseRoute(kRouteId);
644 router()->CloseRoute(kRouteId2);
645 ProcessEventLoop();
646 EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
647 .Times(1)
648 .WillRepeatedly(Return(false));
649 EXPECT_CALL(mock_media_route_provider_, CloseRoute(mojo::String(kRouteId)));
650 EXPECT_CALL(mock_media_route_provider_, CloseRoute(mojo::String(kRouteId2)));
651 ConnectProviderManagerService();
652 ProcessEventLoop();
655 class MediaRouterMojoExtensionTest : public ::testing::Test {
656 public:
657 MediaRouterMojoExtensionTest()
658 : process_manager_(nullptr),
659 message_loop_(mojo::common::MessagePumpMojo::Create())
662 ~MediaRouterMojoExtensionTest() override {}
664 protected:
665 void SetUp() override {
666 profile_.reset(new TestingProfile);
667 // Set up a mock ProcessManager instance.
668 extensions::ProcessManagerFactory::GetInstance()->SetTestingFactory(
669 profile_.get(), &TestProcessManager::Create);
670 process_manager_ = static_cast<TestProcessManager*>(
671 extensions::ProcessManager::Get(profile_.get()));
672 DCHECK(process_manager_);
674 // Create MR and its proxy, so that it can be accessed through Mojo.
675 media_router_.reset(new MediaRouterMojoImpl(process_manager_));
676 ProcessEventLoop();
679 void TearDown() override {
680 profile_.reset();
681 // Explicitly delete the TestingBrowserProcess before |message_loop_|.
682 // This allows it to do cleanup before |message_loop_| goes away.
683 TestingBrowserProcess::DeleteInstance();
686 // Constructs bindings so that |media_router_| delegates calls to
687 // |mojo_media_router_|, which are then handled by
688 // |mock_media_route_provider_service_|.
689 void BindMediaRouteProvider() {
690 binding_.reset(new mojo::Binding<interfaces::MediaRouteProvider>(
691 &mock_media_route_provider_,
692 mojo::GetProxy(&media_route_provider_proxy_)));
693 media_router_->BindToMojoRequest(mojo::GetProxy(&media_router_proxy_),
694 kExtensionId);
697 void ResetMediaRouteProvider() {
698 binding_.reset();
699 media_router_->BindToMojoRequest(mojo::GetProxy(&media_router_proxy_),
700 kExtensionId);
703 void RegisterMediaRouteProvider() {
704 media_router_proxy_->RegisterMediaRouteProvider(
705 media_route_provider_proxy_.Pass(),
706 base::Bind(&RegisterMediaRouteProviderHandler::Invoke,
707 base::Unretained(&provide_handler_)));
710 void ProcessEventLoop() {
711 message_loop_.RunUntilIdle();
714 protected:
715 scoped_ptr<MediaRouterMojoImpl> media_router_;
716 RegisterMediaRouteProviderHandler provide_handler_;
717 TestProcessManager* process_manager_;
718 testing::StrictMock<MockMediaRouteProvider> mock_media_route_provider_;
719 interfaces::MediaRouterPtr media_router_proxy_;
721 private:
722 scoped_ptr<TestingProfile> profile_;
723 base::MessageLoop message_loop_;
724 interfaces::MediaRouteProviderPtr media_route_provider_proxy_;
725 scoped_ptr<mojo::Binding<interfaces::MediaRouteProvider>> binding_;
727 DISALLOW_COPY_AND_ASSIGN(MediaRouterMojoExtensionTest);
730 TEST_F(MediaRouterMojoExtensionTest, DeferredBindingAndSuspension) {
731 // CloseRoute is called before *any* extension has connected.
732 // It should be queued.
733 media_router_->CloseRoute(kRouteId);
735 BindMediaRouteProvider();
737 // |mojo_media_router| signals its readiness to the MR by registering
738 // itself via RegisterMediaRouteProvider().
739 // Now that the |media_router| and |mojo_media_router| are fully initialized,
740 // the queued CloseRoute() call should be executed.
741 EXPECT_CALL(provide_handler_, Invoke(testing::Not("")));
742 EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId))
743 .WillOnce(Return(false));
744 EXPECT_CALL(mock_media_route_provider_, CloseRoute(mojo::String(kRouteId)));
745 RegisterMediaRouteProvider();
746 ProcessEventLoop();
748 // Extension is suspended and re-awoken.
749 ResetMediaRouteProvider();
750 EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId))
751 .WillOnce(Return(true));
752 EXPECT_CALL(*process_manager_, WakeEventPage(kExtensionId, _))
753 .WillOnce(testing::DoAll(media::RunCallback<1>(true), Return(true)));
754 media_router_->CloseRoute(kRouteId2);
755 ProcessEventLoop();
757 // RegisterMediaRouteProvider() is called.
758 // The queued CloseRoute(kRouteId2) call should be executed.
759 EXPECT_CALL(provide_handler_, Invoke(testing::Not("")));
760 EXPECT_CALL(*process_manager_, IsEventPageSuspended(kExtensionId))
761 .WillOnce(Return(false));
762 EXPECT_CALL(mock_media_route_provider_, CloseRoute(mojo::String(kRouteId2)));
763 BindMediaRouteProvider();
764 RegisterMediaRouteProvider();
765 ProcessEventLoop();
768 } // namespace media_router