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.
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"
33 using testing::Invoke
;
36 using testing::Pointee
;
37 using testing::Return
;
38 using testing::ReturnRef
;
39 using testing::SaveArg
;
41 namespace media_router
{
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
)
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();
88 class RouteResponseCallbackHandler
{
91 void(const MediaRoute
* route
,
92 const std::string
& presentation_id
,
93 const std::string
& error_text
));
96 class SendMessageCallbackHandler
{
98 MOCK_METHOD1(Invoke
, void(bool));
101 class ListenForMessagesCallbackHandler
{
103 ListenForMessagesCallbackHandler(
104 ScopedVector
<content::PresentationSessionMessage
> expected_messages
,
106 : expected_messages_(expected_messages
.Pass()),
107 pass_ownership_(pass_ownership
) {}
108 void Invoke(const ScopedVector
<content::PresentationSessionMessage
>& messages
,
109 bool pass_ownership
) {
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
],
119 MOCK_METHOD0(InvokeObserver
, void());
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
;
132 class MediaRouterMojoImplTest
: public MediaRouterMojoTest
{
134 MediaRouterMojoImplTest() {}
135 ~MediaRouterMojoImplTest() override
{}
138 // ProcessManager with a mocked method subset, for testing extension suspend
140 class TestProcessManager
: public extensions::ProcessManager
{
142 explicit TestProcessManager(content::BrowserContext
* context
)
143 : extensions::ProcessManager(
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
));
160 DISALLOW_COPY_AND_ASSIGN(TestProcessManager
);
163 // Mockable class for awaiting RegisterMediaRouteProvider callbacks.
164 class RegisterMediaRouteProviderHandler
{
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
,
188 const interfaces::MediaRouteProvider::CreateRouteCallback
& cb
) {
189 cb
.Run(route
.Pass(), mojo::String());
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
);
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
, _
))
207 [](const mojo::String
& source
, const mojo::String
& sink
,
208 const mojo::String
& presentation_id
, const mojo::String
& origin
,
210 const interfaces::MediaRouteProvider::CreateRouteCallback
& cb
) {
211 cb
.Run(interfaces::MediaRoutePtr(), mojo::String(kError
));
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
);
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());
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
);
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
, _
))
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
));
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
);
277 TEST_F(MediaRouterMojoImplTest
, CloseRoute
) {
278 EXPECT_CALL(mock_media_route_provider_
, CloseRoute(mojo::String(kRouteId
)));
279 router()->CloseRoute(kRouteId
);
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
>();
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());
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());
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(_
))
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());
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
);
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(_
))
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());
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());
441 TEST_F(MediaRouterMojoImplTest
, SendRouteMessage
) {
443 mock_media_route_provider_
,
444 SendRouteMessage(mojo::String(kRouteId
), mojo::String(kMessage
), _
))
446 const MediaRoute::Id
& route_id
, const std::string
& message
,
447 const interfaces::MediaRouteProvider::SendRouteMessageCallback
& cb
) {
451 SendMessageCallbackHandler handler
;
452 EXPECT_CALL(handler
, Invoke(true));
453 router()->SendRouteMessage(kRouteId
, kMessage
,
454 base::Bind(&SendMessageCallbackHandler::Invoke
,
455 base::Unretained(&handler
)));
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
), _
, _
))
466 const MediaRoute::Id
& route_id
, const std::vector
<uint8
>& data
,
467 const interfaces::MediaRouteProvider::SendRouteMessageCallback
& cb
) {
469 0, memcmp(kBinaryMessage
, &(data
[0]), arraysize(kBinaryMessage
)));
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
)));
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()));
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
528 EXPECT_CALL(mock_media_route_provider_
, ListenForRouteMessages(_
, _
))
529 .WillOnce(SaveArg
<1>(&mojo_callback_2
));
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";
539 mojo_callback_2
.Run(mojo_messages_2
.Pass(), false);
540 EXPECT_CALL(mock_media_route_provider_
, StopListeningForRouteMessages(_
));
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
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()));
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
596 EXPECT_CALL(mock_media_route_provider_
, ListenForRouteMessages(_
, _
))
597 .WillOnce(SaveArg
<1>(&mojo_callback_2
));
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";
608 mojo_callback_2
.Run(mojo_messages_2
.Pass(), false);
609 EXPECT_CALL(mock_media_route_provider_
, StopListeningForRouteMessages(_
));
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()));
632 mojo_callback
.Run(mojo::Array
<interfaces::RouteMessagePtr
>(0), true);
636 TEST_F(MediaRouterMojoImplTest
, QueuedWhileAsleep
) {
637 EXPECT_CALL(mock_event_page_tracker_
, IsEventPageSuspended(extension_id()))
639 .WillRepeatedly(Return(true));
640 EXPECT_CALL(mock_event_page_tracker_
, WakeEventPage(extension_id(), _
))
642 .WillRepeatedly(Return(true));
643 router()->CloseRoute(kRouteId
);
644 router()->CloseRoute(kRouteId2
);
646 EXPECT_CALL(mock_event_page_tracker_
, IsEventPageSuspended(extension_id()))
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();
655 class MediaRouterMojoExtensionTest
: public ::testing::Test
{
657 MediaRouterMojoExtensionTest()
658 : process_manager_(nullptr),
659 message_loop_(mojo::common::MessagePumpMojo::Create())
662 ~MediaRouterMojoExtensionTest() override
{}
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_
));
679 void TearDown() override
{
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_
),
697 void ResetMediaRouteProvider() {
699 media_router_
->BindToMojoRequest(mojo::GetProxy(&media_router_proxy_
),
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();
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_
;
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();
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
);
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();
768 } // namespace media_router