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 "chrome/browser/media/router/issue.h"
13 #include "chrome/browser/media/router/media_route.h"
14 #include "chrome/browser/media/router/media_router_mojo_test.h"
15 #include "chrome/browser/media/router/media_router_type_converters.h"
16 #include "chrome/browser/media/router/mock_media_router.h"
17 #include "chrome/browser/media/router/presentation_session_messages_observer.h"
18 #include "chrome/browser/media/router/test_helper.h"
19 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
20 #include "chrome/test/base/testing_profile.h"
21 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/process_manager.h"
23 #include "extensions/browser/process_manager_factory.h"
24 #include "media/base/gmock_callback_support.h"
25 #include "testing/gmock/include/gmock/gmock.h"
26 #include "testing/gtest/include/gtest/gtest.h"
30 using testing::Invoke
;
33 using testing::Pointee
;
34 using testing::Return
;
35 using testing::ReturnRef
;
36 using testing::SaveArg
;
38 namespace media_router
{
42 const char kDescription
[] = "description";
43 const char kError
[] = "error";
44 const char kExtensionId
[] = "extension1234";
45 const char kMessage
[] = "message";
46 const char kSource
[] = "source1";
47 const char kSource2
[] = "source2";
48 const char kRouteId
[] = "routeId";
49 const char kRouteId2
[] = "routeId2";
50 const char kSink
[] = "sink";
51 const char kSink2
[] = "sink2";
52 const char kSinkName
[] = "sinkName";
53 const char kPresentationId
[] = "presentationId";
54 const char kOrigin
[] = "http://origin/";
55 const int kTabId
= 123;
56 const uint8 kBinaryMessage
[] = {0x01, 0x02, 0x03, 0x04};
58 bool ArePresentationSessionMessagesEqual(
59 const content::PresentationSessionMessage
* expected
,
60 const content::PresentationSessionMessage
* actual
) {
61 if (expected
->type
!= actual
->type
)
64 return expected
->is_binary() ? *expected
->data
== *actual
->data
65 : expected
->message
== actual
->message
;
68 interfaces::IssuePtr
CreateMojoIssue(const std::string
& title
) {
69 interfaces::IssuePtr mojoIssue
= interfaces::Issue::New();
70 mojoIssue
->title
= title
;
71 mojoIssue
->message
= "msg";
72 mojoIssue
->route_id
= "";
73 mojoIssue
->default_action
=
74 interfaces::Issue::ActionType::ACTION_TYPE_DISMISS
;
75 mojoIssue
->secondary_actions
=
76 mojo::Array
<interfaces::Issue::ActionType
>::New(0);
77 mojoIssue
->severity
= interfaces::Issue::Severity::SEVERITY_WARNING
;
78 mojoIssue
->is_blocking
= false;
79 mojoIssue
->help_url
= "";
80 return mojoIssue
.Pass();
85 class RouteResponseCallbackHandler
{
88 void(const MediaRoute
* route
,
89 const std::string
& presentation_id
,
90 const std::string
& error_text
));
93 class SendMessageCallbackHandler
{
95 MOCK_METHOD1(Invoke
, void(bool));
98 class ListenForMessagesCallbackHandler
{
100 ListenForMessagesCallbackHandler(
101 ScopedVector
<content::PresentationSessionMessage
> expected_messages
,
103 : expected_messages_(expected_messages
.Pass()),
104 pass_ownership_(pass_ownership
) {}
105 void Invoke(const ScopedVector
<content::PresentationSessionMessage
>& messages
,
106 bool pass_ownership
) {
108 EXPECT_EQ(pass_ownership_
, pass_ownership
);
109 EXPECT_EQ(messages
.size(), expected_messages_
.size());
110 for (size_t i
= 0; i
< expected_messages_
.size(); ++i
) {
111 EXPECT_TRUE(ArePresentationSessionMessagesEqual(expected_messages_
[i
],
116 MOCK_METHOD0(InvokeObserver
, void());
119 ScopedVector
<content::PresentationSessionMessage
> expected_messages_
;
120 bool pass_ownership_
;
123 template <typename T
>
124 void StoreAndRun(T
* result
, const base::Closure
& closure
, const T
& result_val
) {
125 *result
= result_val
;
129 class MediaRouterMojoImplTest
: public MediaRouterMojoTest
{
131 MediaRouterMojoImplTest() {}
132 ~MediaRouterMojoImplTest() override
{}
135 // ProcessManager with a mocked method subset, for testing extension suspend
137 class TestProcessManager
: public extensions::ProcessManager
{
139 explicit TestProcessManager(content::BrowserContext
* context
)
140 : extensions::ProcessManager(
143 extensions::ExtensionRegistry::Get(context
)) {}
144 ~TestProcessManager() override
{}
146 static scoped_ptr
<KeyedService
> Create(content::BrowserContext
* context
) {
147 return make_scoped_ptr(new TestProcessManager(context
));
150 MOCK_METHOD1(IsEventPageSuspended
, bool(const std::string
& ext_id
));
152 MOCK_METHOD2(WakeEventPage
,
153 bool(const std::string
& extension_id
,
154 const base::Callback
<void(bool)>& callback
));
157 DISALLOW_COPY_AND_ASSIGN(TestProcessManager
);
160 // Mockable class for awaiting RegisterMediaRouteProvider callbacks.
161 class RegisterMediaRouteProviderHandler
{
163 MOCK_METHOD1(Invoke
, void(const std::string
& instance_id
));
166 TEST_F(MediaRouterMojoImplTest
, CreateRoute
) {
167 MediaRoute
expected_route(kRouteId
, MediaSource(std::string(kSource
)),
168 MediaSink(kSink
, kSinkName
), "", false, "");
169 interfaces::MediaRoutePtr route
= interfaces::MediaRoute::New();
170 route
->media_source
= kSource
;
171 route
->media_sink
= interfaces::MediaSink::New();
172 route
->media_sink
->sink_id
= kSink
;
173 route
->media_sink
->name
= kSinkName
;
174 route
->media_route_id
= kRouteId
;
175 route
->description
= kDescription
;
177 // Use a lambda function as an invocation target here to work around
178 // a limitation with GMock::Invoke that prevents it from using move-only types
179 // in runnable parameter lists.
180 EXPECT_CALL(mock_media_route_provider_
,
181 CreateRoute(mojo::String(kSource
), mojo::String(kSink
), _
,
182 mojo::String(kOrigin
), kTabId
, _
))
183 .WillOnce(Invoke([&route
](
184 const mojo::String
& source
, const mojo::String
& sink
,
185 const mojo::String
& presentation_id
, const mojo::String
& origin
,
187 const interfaces::MediaRouteProvider::CreateRouteCallback
& cb
) {
188 cb
.Run(route
.Pass(), mojo::String());
191 RouteResponseCallbackHandler handler
;
192 EXPECT_CALL(handler
, Invoke(Pointee(Equals(expected_route
)), Not(""), ""));
193 std::vector
<MediaRouteResponseCallback
> route_response_callbacks
;
194 route_response_callbacks
.push_back(base::Bind(
195 &RouteResponseCallbackHandler::Invoke
, base::Unretained(&handler
)));
196 router()->CreateRoute(kSource
, kSink
, GURL(kOrigin
), kTabId
,
197 route_response_callbacks
);
201 TEST_F(MediaRouterMojoImplTest
, CreateRouteFails
) {
202 EXPECT_CALL(mock_media_route_provider_
,
203 CreateRoute(mojo::String(kSource
), mojo::String(kSink
), _
,
204 mojo::String(kOrigin
), kTabId
, _
))
206 [](const mojo::String
& source
, const mojo::String
& sink
,
207 const mojo::String
& presentation_id
, const mojo::String
& origin
,
209 const interfaces::MediaRouteProvider::CreateRouteCallback
& cb
) {
210 cb
.Run(interfaces::MediaRoutePtr(), mojo::String(kError
));
213 RouteResponseCallbackHandler handler
;
214 EXPECT_CALL(handler
, Invoke(nullptr, "", kError
));
215 std::vector
<MediaRouteResponseCallback
> route_response_callbacks
;
216 route_response_callbacks
.push_back(base::Bind(
217 &RouteResponseCallbackHandler::Invoke
, base::Unretained(&handler
)));
218 router()->CreateRoute(kSource
, kSink
, GURL(kOrigin
), kTabId
,
219 route_response_callbacks
);
223 TEST_F(MediaRouterMojoImplTest
, JoinRoute
) {
224 MediaRoute
expected_route(kRouteId
, MediaSource(std::string(kSource
)),
225 MediaSink(kSink
, kSinkName
), "", false, "");
226 interfaces::MediaRoutePtr route
= interfaces::MediaRoute::New();
227 route
->media_source
= kSource
;
228 route
->media_sink
= interfaces::MediaSink::New();
229 route
->media_sink
->sink_id
= kSink
;
230 route
->media_sink
->name
= kSinkName
;
231 route
->media_route_id
= kRouteId
;
232 route
->description
= kDescription
;
234 // Use a lambda function as an invocation target here to work around
235 // a limitation with GMock::Invoke that prevents it from using move-only types
236 // in runnable parameter lists.
237 EXPECT_CALL(mock_media_route_provider_
,
238 JoinRoute(mojo::String(kSource
), mojo::String(kPresentationId
),
239 mojo::String(kOrigin
), kTabId
, _
))
240 .WillOnce(Invoke([&route
](
241 const mojo::String
& source
, const mojo::String
& presentation_id
,
242 const mojo::String
& origin
, int tab_id
,
243 const interfaces::MediaRouteProvider::JoinRouteCallback
& cb
) {
244 cb
.Run(route
.Pass(), mojo::String());
247 RouteResponseCallbackHandler handler
;
248 EXPECT_CALL(handler
, Invoke(Pointee(Equals(expected_route
)), Not(""), ""));
249 std::vector
<MediaRouteResponseCallback
> route_response_callbacks
;
250 route_response_callbacks
.push_back(base::Bind(
251 &RouteResponseCallbackHandler::Invoke
, base::Unretained(&handler
)));
252 router()->JoinRoute(kSource
, kPresentationId
, GURL(kOrigin
), kTabId
,
253 route_response_callbacks
);
257 TEST_F(MediaRouterMojoImplTest
, JoinRouteFails
) {
258 EXPECT_CALL(mock_media_route_provider_
,
259 JoinRoute(mojo::String(kSource
), mojo::String(kPresentationId
),
260 mojo::String(kOrigin
), kTabId
, _
))
262 [](const mojo::String
& source
, const mojo::String
& presentation_id
,
263 const mojo::String
& origin
, int tab_id
,
264 const interfaces::MediaRouteProvider::JoinRouteCallback
& cb
) {
265 cb
.Run(interfaces::MediaRoutePtr(), mojo::String(kError
));
268 RouteResponseCallbackHandler handler
;
269 EXPECT_CALL(handler
, Invoke(nullptr, "", kError
));
270 std::vector
<MediaRouteResponseCallback
> route_response_callbacks
;
271 route_response_callbacks
.push_back(base::Bind(
272 &RouteResponseCallbackHandler::Invoke
, base::Unretained(&handler
)));
273 router()->JoinRoute(kSource
, kPresentationId
, GURL(kOrigin
), kTabId
,
274 route_response_callbacks
);
278 TEST_F(MediaRouterMojoImplTest
, CloseRoute
) {
279 EXPECT_CALL(mock_media_route_provider_
, CloseRoute(mojo::String(kRouteId
)));
280 router()->CloseRoute(kRouteId
);
284 TEST_F(MediaRouterMojoImplTest
, HandleIssue
) {
285 MockIssuesObserver
issue_observer1(router());
286 MockIssuesObserver
issue_observer2(router());
287 interfaces::IssuePtr mojo_issue1
= CreateMojoIssue("title 1");
288 const Issue
& expected_issue1
= mojo_issue1
.To
<Issue
>();
291 EXPECT_CALL(issue_observer1
,
292 OnIssueUpdated(Pointee(EqualsIssue(expected_issue1
))))
293 .WillOnce(SaveArg
<0>(&issue
));
294 EXPECT_CALL(issue_observer2
,
295 OnIssueUpdated(Pointee(EqualsIssue(expected_issue1
))));
296 media_router_proxy_
->OnIssue(mojo_issue1
.Pass());
299 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer1
));
300 EXPECT_TRUE(Mock::VerifyAndClearExpectations(&issue_observer2
));
302 router()->ClearIssue(issue
->id());
303 router()->UnregisterIssuesObserver(&issue_observer1
);
304 interfaces::IssuePtr mojo_issue2
= CreateMojoIssue("title 2");
305 const Issue
& expected_issue2
= mojo_issue2
.To
<Issue
>();
307 EXPECT_CALL(issue_observer2
,
308 OnIssueUpdated(Pointee(EqualsIssue(expected_issue2
))));
309 media_router_proxy_
->OnIssue(mojo_issue2
.Pass());
313 TEST_F(MediaRouterMojoImplTest
, RegisterAndUnregisterMediaSinksObserver
) {
314 MediaSource
media_source(kSource
);
316 MockMediaRouter mock_router
;
317 EXPECT_CALL(mock_media_route_provider_
,
318 StartObservingMediaSinks(mojo::String(kSource
))).Times(2);
319 EXPECT_CALL(mock_media_route_provider_
,
320 StartObservingMediaSinks(mojo::String(kSource2
)));
322 MediaSinksObserver
* captured_observer
;
323 EXPECT_CALL(mock_router
, RegisterMediaSinksObserver(_
))
325 .WillRepeatedly(SaveArg
<0>(&captured_observer
));
327 MockMediaSinksObserver
sinks_observer(&mock_router
, media_source
);
328 EXPECT_EQ(&sinks_observer
, captured_observer
);
329 router()->RegisterMediaSinksObserver(&sinks_observer
);
330 MockMediaSinksObserver
extra_sinks_observer(&mock_router
, media_source
);
331 EXPECT_EQ(&extra_sinks_observer
, captured_observer
);
332 router()->RegisterMediaSinksObserver(&extra_sinks_observer
);
333 MockMediaSinksObserver
unrelated_sinks_observer(&mock_router
,
334 MediaSource(kSource2
));
335 EXPECT_EQ(&unrelated_sinks_observer
, captured_observer
);
336 router()->RegisterMediaSinksObserver(&unrelated_sinks_observer
);
338 std::vector
<MediaSink
> expected_sinks
;
339 expected_sinks
.push_back(MediaSink(kSink
, kSinkName
));
340 expected_sinks
.push_back(MediaSink(kSink2
, kSinkName
));
342 mojo::Array
<interfaces::MediaSinkPtr
> mojo_sinks(2);
343 mojo_sinks
[0] = interfaces::MediaSink::New();
344 mojo_sinks
[0]->sink_id
= kSink
;
345 mojo_sinks
[0]->name
= kSink
;
346 mojo_sinks
[1] = interfaces::MediaSink::New();
347 mojo_sinks
[1]->sink_id
= kSink2
;
348 mojo_sinks
[1]->name
= kSink2
;
350 EXPECT_CALL(sinks_observer
, OnSinksReceived(SequenceEquals(expected_sinks
)));
351 EXPECT_CALL(extra_sinks_observer
,
352 OnSinksReceived(SequenceEquals(expected_sinks
)));
353 media_router_proxy_
->OnSinksReceived(media_source
.id(), mojo_sinks
.Pass());
356 EXPECT_CALL(mock_router
, UnregisterMediaSinksObserver(&sinks_observer
));
357 EXPECT_CALL(mock_router
, UnregisterMediaSinksObserver(&extra_sinks_observer
));
358 EXPECT_CALL(mock_router
,
359 UnregisterMediaSinksObserver(&unrelated_sinks_observer
));
360 EXPECT_CALL(mock_media_route_provider_
,
361 StopObservingMediaSinks(mojo::String(kSource
)));
362 EXPECT_CALL(mock_media_route_provider_
,
363 StopObservingMediaSinks(mojo::String(kSource2
)));
364 router()->UnregisterMediaSinksObserver(&sinks_observer
);
365 router()->UnregisterMediaSinksObserver(&extra_sinks_observer
);
366 router()->UnregisterMediaSinksObserver(&unrelated_sinks_observer
);
370 TEST_F(MediaRouterMojoImplTest
, RegisterAndUnregisterMediaRoutesObserver
) {
371 MockMediaRouter mock_router
;
372 EXPECT_CALL(mock_media_route_provider_
, StartObservingMediaRoutes()).Times(2);
374 MediaRoutesObserver
* observer_captured
;
375 EXPECT_CALL(mock_router
, RegisterMediaRoutesObserver(_
))
377 .WillRepeatedly(SaveArg
<0>(&observer_captured
));
378 MockMediaRoutesObserver
routes_observer(&mock_router
);
379 EXPECT_EQ(observer_captured
, &routes_observer
);
380 MockMediaRoutesObserver
extra_routes_observer(&mock_router
);
381 EXPECT_EQ(observer_captured
, &extra_routes_observer
);
382 router()->RegisterMediaRoutesObserver(&routes_observer
);
383 router()->RegisterMediaRoutesObserver(&extra_routes_observer
);
385 std::vector
<MediaRoute
> expected_routes
;
386 expected_routes
.push_back(MediaRoute(kRouteId
, MediaSource(kSource
),
387 MediaSink(kSink
, kSink
), kDescription
,
389 expected_routes
.push_back(MediaRoute(kRouteId2
, MediaSource(kSource
),
390 MediaSink(kSink
, kSink
), kDescription
,
393 mojo::Array
<interfaces::MediaRoutePtr
> mojo_routes(2);
394 mojo_routes
[0] = interfaces::MediaRoute::New();
395 mojo_routes
[0]->media_route_id
= kRouteId
;
396 mojo_routes
[0]->media_source
= kSource
;
397 mojo_routes
[0]->media_sink
= interfaces::MediaSink::New();
398 mojo_routes
[0]->media_sink
->sink_id
= kSink
;
399 mojo_routes
[0]->media_sink
->name
= kSink
;
400 mojo_routes
[0]->description
= kDescription
;
401 mojo_routes
[0]->is_local
= false;
402 mojo_routes
[1] = interfaces::MediaRoute::New();
403 mojo_routes
[1]->media_route_id
= kRouteId2
;
404 mojo_routes
[1]->media_source
= kSource
;
405 mojo_routes
[1]->media_sink
= interfaces::MediaSink::New();
406 mojo_routes
[1]->media_sink
->sink_id
= kSink
;
407 mojo_routes
[1]->media_sink
->name
= kSink
;
408 mojo_routes
[1]->description
= kDescription
;
409 mojo_routes
[1]->is_local
= false;
411 EXPECT_CALL(routes_observer
,
412 OnRoutesUpdated(SequenceEquals(expected_routes
)));
413 EXPECT_CALL(extra_routes_observer
,
414 OnRoutesUpdated(SequenceEquals(expected_routes
)));
415 media_router_proxy_
->OnRoutesUpdated(mojo_routes
.Pass());
418 EXPECT_CALL(mock_router
, UnregisterMediaRoutesObserver(&routes_observer
));
419 EXPECT_CALL(mock_router
,
420 UnregisterMediaRoutesObserver(&extra_routes_observer
));
421 router()->UnregisterMediaRoutesObserver(&routes_observer
);
422 router()->UnregisterMediaRoutesObserver(&extra_routes_observer
);
423 EXPECT_CALL(mock_media_route_provider_
, StopObservingMediaRoutes());
427 TEST_F(MediaRouterMojoImplTest
, SendRouteMessage
) {
429 mock_media_route_provider_
,
430 SendRouteMessage(mojo::String(kRouteId
), mojo::String(kMessage
), _
))
432 const MediaRoute::Id
& route_id
, const std::string
& message
,
433 const interfaces::MediaRouteProvider::SendRouteMessageCallback
& cb
) {
437 SendMessageCallbackHandler handler
;
438 EXPECT_CALL(handler
, Invoke(true));
439 router()->SendRouteMessage(kRouteId
, kMessage
,
440 base::Bind(&SendMessageCallbackHandler::Invoke
,
441 base::Unretained(&handler
)));
445 TEST_F(MediaRouterMojoImplTest
, SendRouteBinaryMessage
) {
446 scoped_ptr
<std::vector
<uint8
>> expected_binary_data(new std::vector
<uint8
>(
447 kBinaryMessage
, kBinaryMessage
+ arraysize(kBinaryMessage
)));
449 EXPECT_CALL(mock_media_route_provider_
,
450 SendRouteBinaryMessageInternal(mojo::String(kRouteId
), _
, _
))
452 const MediaRoute::Id
& route_id
, const std::vector
<uint8
>& data
,
453 const interfaces::MediaRouteProvider::SendRouteMessageCallback
& cb
) {
455 0, memcmp(kBinaryMessage
, &(data
[0]), arraysize(kBinaryMessage
)));
459 SendMessageCallbackHandler handler
;
460 EXPECT_CALL(handler
, Invoke(true));
461 router()->SendRouteBinaryMessage(
462 kRouteId
, expected_binary_data
.Pass(),
463 base::Bind(&SendMessageCallbackHandler::Invoke
,
464 base::Unretained(&handler
)));
468 TEST_F(MediaRouterMojoImplTest
, PresentationSessionMessagesSingleObserver
) {
469 mojo::Array
<interfaces::RouteMessagePtr
> mojo_messages(2);
470 mojo_messages
[0] = interfaces::RouteMessage::New();
471 mojo_messages
[0]->type
= interfaces::RouteMessage::Type::TYPE_TEXT
;
472 mojo_messages
[0]->message
= "text";
473 mojo_messages
[1] = interfaces::RouteMessage::New();
474 mojo_messages
[1]->type
= interfaces::RouteMessage::Type::TYPE_BINARY
;
475 mojo_messages
[1]->data
.push_back(1);
477 ScopedVector
<content::PresentationSessionMessage
> expected_messages
;
478 scoped_ptr
<content::PresentationSessionMessage
> message
;
479 message
.reset(new content::PresentationSessionMessage(
480 content::PresentationMessageType::TEXT
));
481 message
->message
= "text";
482 expected_messages
.push_back(message
.Pass());
484 message
.reset(new content::PresentationSessionMessage(
485 content::PresentationMessageType::ARRAY_BUFFER
));
486 message
->data
.reset(new std::vector
<uint8_t>(1, 1));
487 expected_messages
.push_back(message
.Pass());
489 MediaRoute::Id
expected_route_id("foo");
490 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback
;
491 EXPECT_CALL(mock_media_route_provider_
,
492 ListenForRouteMessages(Eq(expected_route_id
), _
))
493 .WillOnce(SaveArg
<1>(&mojo_callback
));
495 // |pass_ownership| param is "true" here because there is only one observer.
496 ListenForMessagesCallbackHandler
handler(expected_messages
.Pass(), true);
498 EXPECT_CALL(handler
, InvokeObserver());
499 // Creating PresentationSessionMessagesObserver will register itself to the
500 // MediaRouter, which in turn will start listening for route messages.
501 scoped_ptr
<PresentationSessionMessagesObserver
> observer(
502 new PresentationSessionMessagesObserver(
503 base::Bind(&ListenForMessagesCallbackHandler::Invoke
,
504 base::Unretained(&handler
)),
505 expected_route_id
, router()));
508 // Simulate messages by invoking the saved mojo callback.
509 // We expect one more ListenForRouteMessages call since |observer| was
510 // still registered when the first set of messages arrived.
511 mojo_callback
.Run(mojo_messages
.Pass(), false);
512 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback
514 EXPECT_CALL(mock_media_route_provider_
, ListenForRouteMessages(_
, _
))
515 .WillOnce(SaveArg
<1>(&mojo_callback_2
));
518 // Stop listening for messages. In particular, MediaRouterMojoImpl will not
519 // call ListenForRouteMessages again when it sees there are no more observers.
520 mojo::Array
<interfaces::RouteMessagePtr
> mojo_messages_2(1);
521 mojo_messages_2
[0] = interfaces::RouteMessage::New();
522 mojo_messages_2
[0]->type
= interfaces::RouteMessage::Type::TYPE_TEXT
;
523 mojo_messages_2
[0]->message
= "foo";
525 mojo_callback_2
.Run(mojo_messages_2
.Pass(), false);
529 TEST_F(MediaRouterMojoImplTest
, PresentationSessionMessagesMultipleObservers
) {
530 mojo::Array
<interfaces::RouteMessagePtr
> mojo_messages(2);
531 mojo_messages
[0] = interfaces::RouteMessage::New();
532 mojo_messages
[0]->type
= interfaces::RouteMessage::Type::TYPE_TEXT
;
533 mojo_messages
[0]->message
= "text";
534 mojo_messages
[1] = interfaces::RouteMessage::New();
535 mojo_messages
[1]->type
= interfaces::RouteMessage::Type::TYPE_BINARY
;
536 mojo_messages
[1]->data
.push_back(1);
538 ScopedVector
<content::PresentationSessionMessage
> expected_messages
;
539 scoped_ptr
<content::PresentationSessionMessage
> message
;
540 message
.reset(new content::PresentationSessionMessage(
541 content::PresentationMessageType::TEXT
));
542 message
->message
= "text";
543 expected_messages
.push_back(message
.Pass());
545 message
.reset(new content::PresentationSessionMessage(
546 content::PresentationMessageType::ARRAY_BUFFER
));
547 message
->data
.reset(new std::vector
<uint8_t>(1, 1));
548 expected_messages
.push_back(message
.Pass());
550 MediaRoute::Id
expected_route_id("foo");
551 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback
;
552 EXPECT_CALL(mock_media_route_provider_
,
553 ListenForRouteMessages(Eq(expected_route_id
), _
))
554 .WillOnce(SaveArg
<1>(&mojo_callback
));
556 // |pass_ownership| param is "false" here because there are more than one
558 ListenForMessagesCallbackHandler
handler(expected_messages
.Pass(), false);
560 EXPECT_CALL(handler
, InvokeObserver()).Times(2);
561 // Creating PresentationSessionMessagesObserver will register itself to the
562 // MediaRouter, which in turn will start listening for route messages.
563 scoped_ptr
<PresentationSessionMessagesObserver
> observer1(
564 new PresentationSessionMessagesObserver(
565 base::Bind(&ListenForMessagesCallbackHandler::Invoke
,
566 base::Unretained(&handler
)),
567 expected_route_id
, router()));
568 scoped_ptr
<PresentationSessionMessagesObserver
> observer2(
569 new PresentationSessionMessagesObserver(
570 base::Bind(&ListenForMessagesCallbackHandler::Invoke
,
571 base::Unretained(&handler
)),
572 expected_route_id
, router()));
575 // Simulate messages by invoking the saved mojo callback.
576 // We expect one more ListenForRouteMessages call since |observer| was
577 // still registered when the first set of messages arrived.
578 mojo_callback
.Run(mojo_messages
.Pass(), false);
579 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback
581 EXPECT_CALL(mock_media_route_provider_
, ListenForRouteMessages(_
, _
))
582 .WillOnce(SaveArg
<1>(&mojo_callback_2
));
585 // Stop listening for messages. In particular, MediaRouterMojoImpl will not
586 // call ListenForRouteMessages again when it sees there are no more observers.
587 mojo::Array
<interfaces::RouteMessagePtr
> mojo_messages_2(1);
588 mojo_messages_2
[0] = interfaces::RouteMessage::New();
589 mojo_messages_2
[0]->type
= interfaces::RouteMessage::Type::TYPE_TEXT
;
590 mojo_messages_2
[0]->message
= "foo";
593 mojo_callback_2
.Run(mojo_messages_2
.Pass(), false);
597 TEST_F(MediaRouterMojoImplTest
, PresentationSessionMessagesError
) {
598 MediaRoute::Id
expected_route_id("foo");
599 interfaces::MediaRouteProvider::ListenForRouteMessagesCallback mojo_callback
;
600 EXPECT_CALL(mock_media_route_provider_
,
601 ListenForRouteMessages(Eq(expected_route_id
), _
))
602 .WillOnce(SaveArg
<1>(&mojo_callback
));
604 ListenForMessagesCallbackHandler
handler(
605 ScopedVector
<content::PresentationSessionMessage
>(), true);
607 // Creating PresentationSessionMessagesObserver will register itself to the
608 // MediaRouter, which in turn will start listening for route messages.
609 scoped_ptr
<PresentationSessionMessagesObserver
> observer1(
610 new PresentationSessionMessagesObserver(
611 base::Bind(&ListenForMessagesCallbackHandler::Invoke
,
612 base::Unretained(&handler
)),
613 expected_route_id
, router()));
616 mojo_callback
.Run(mojo::Array
<interfaces::RouteMessagePtr
>(0), true);
620 TEST_F(MediaRouterMojoImplTest
, QueuedWhileAsleep
) {
621 EXPECT_CALL(mock_event_page_tracker_
, IsEventPageSuspended(extension_id()))
623 .WillRepeatedly(Return(true));
624 EXPECT_CALL(mock_event_page_tracker_
, WakeEventPage(extension_id(), _
))
626 .WillRepeatedly(Return(true));
627 router()->CloseRoute(kRouteId
);
628 router()->CloseRoute(kRouteId2
);
630 EXPECT_CALL(mock_event_page_tracker_
, IsEventPageSuspended(extension_id()))
632 .WillRepeatedly(Return(false));
633 EXPECT_CALL(mock_media_route_provider_
, CloseRoute(mojo::String(kRouteId
)));
634 EXPECT_CALL(mock_media_route_provider_
, CloseRoute(mojo::String(kRouteId2
)));
635 ConnectProviderManagerService();
639 // Temporarily disabled until the issues with extension system teardown
641 // TODO(kmarshall): Re-enable this test. (http://crbug.com/490468)
642 TEST(MediaRouterMojoExtensionTest
, DISABLED_DeferredBindingAndSuspension
) {
643 base::MessageLoop
message_loop(mojo::common::MessagePumpMojo::Create());
645 // Set up a mock ProcessManager instance.
646 TestingProfile profile
;
647 extensions::ProcessManagerFactory::GetInstance()->SetTestingFactory(
648 &profile
, &TestProcessManager::Create
);
649 TestProcessManager
* process_manager
= static_cast<TestProcessManager
*>(
650 extensions::ProcessManager::Get(&profile
));
652 // Create MR and its proxy, so that it can be accessed through Mojo.
653 MediaRouterMojoImpl
media_router(process_manager
);
654 interfaces::MediaRouterPtr media_router_proxy
;
656 // Create a client object and its Mojo proxy.
657 testing::StrictMock
<MockMediaRouteProvider
> mock_media_route_provider
;
658 interfaces::MediaRouteProviderPtr media_route_provider_proxy
;
660 // CloseRoute is called before *any* extension has connected.
661 // It should be queued.
662 media_router
.CloseRoute(kRouteId
);
664 // Construct bindings so that |media_router| delegates calls to
665 // |mojo_media_router|, which are then handled by
666 // |mock_media_route_provider_service|.
667 scoped_ptr
<mojo::Binding
<interfaces::MediaRouteProvider
>> binding(
668 new mojo::Binding
<interfaces::MediaRouteProvider
>(
669 &mock_media_route_provider
,
670 mojo::GetProxy(&media_route_provider_proxy
)));
671 media_router
.BindToMojoRequest(mojo::GetProxy(&media_router_proxy
),
674 // |mojo_media_router| signals its readiness to the MR by registering
675 // itself via RegisterMediaRouteProvider().
676 // Now that the |media_router| and |mojo_media_router| are fully initialized,
677 // the queued CloseRoute() call should be executed.
678 RegisterMediaRouteProviderHandler provide_handler
;
679 EXPECT_CALL(provide_handler
, Invoke(testing::Not("")));
680 EXPECT_CALL(*process_manager
, IsEventPageSuspended(kExtensionId
))
681 .WillOnce(Return(false));
682 EXPECT_CALL(mock_media_route_provider
, CloseRoute(mojo::String(kRouteId
)));
683 media_router_proxy
->RegisterMediaRouteProvider(
684 media_route_provider_proxy
.Pass(),
685 base::Bind(&RegisterMediaRouteProviderHandler::Invoke
,
686 base::Unretained(&provide_handler
)));
687 message_loop
.RunUntilIdle();
689 // Extension is suspended and re-awoken.
691 media_router
.BindToMojoRequest(mojo::GetProxy(&media_router_proxy
),
693 EXPECT_CALL(*process_manager
, IsEventPageSuspended(kExtensionId
))
694 .WillOnce(Return(true));
695 EXPECT_CALL(*process_manager
, WakeEventPage(kExtensionId
, _
))
696 .WillOnce(testing::DoAll(media::RunCallback
<1>(true), Return(true)));
697 media_router
.CloseRoute(kRouteId2
);
698 message_loop
.RunUntilIdle();
700 // RegisterMediaRouteProvider() is called.
701 // The queued CloseRoute(kRouteId2) call should be executed.
702 EXPECT_CALL(provide_handler
, Invoke(testing::Not("")));
703 EXPECT_CALL(*process_manager
, IsEventPageSuspended(kExtensionId
))
704 .WillOnce(Return(false));
705 EXPECT_CALL(mock_media_route_provider
, CloseRoute(mojo::String(kRouteId2
)));
706 binding
.reset(new mojo::Binding
<interfaces::MediaRouteProvider
>(
707 &mock_media_route_provider
, mojo::GetProxy(&media_route_provider_proxy
)));
708 media_router_proxy
->RegisterMediaRouteProvider(
709 media_route_provider_proxy
.Pass(),
710 base::Bind(&RegisterMediaRouteProviderHandler::Invoke
,
711 base::Unretained(&provide_handler
)));
712 message_loop
.RunUntilIdle();
715 } // namespace media_router