Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / media / router / media_router_mojo_impl_unittest.cc
blob3ae87122ad249fb15620c2b57e1f8c16d9e45b31
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 "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"
28 using testing::_;
29 using testing::Eq;
30 using testing::Invoke;
31 using testing::Mock;
32 using testing::Not;
33 using testing::Pointee;
34 using testing::Return;
35 using testing::ReturnRef;
36 using testing::SaveArg;
38 namespace media_router {
40 namespace {
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)
62 return false;
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();
83 } // namespace
85 class RouteResponseCallbackHandler {
86 public:
87 MOCK_METHOD3(Invoke,
88 void(const MediaRoute* route,
89 const std::string& presentation_id,
90 const std::string& error_text));
93 class SendMessageCallbackHandler {
94 public:
95 MOCK_METHOD1(Invoke, void(bool));
98 class ListenForMessagesCallbackHandler {
99 public:
100 ListenForMessagesCallbackHandler(
101 ScopedVector<content::PresentationSessionMessage> expected_messages,
102 bool pass_ownership)
103 : expected_messages_(expected_messages.Pass()),
104 pass_ownership_(pass_ownership) {}
105 void Invoke(const ScopedVector<content::PresentationSessionMessage>& messages,
106 bool pass_ownership) {
107 InvokeObserver();
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],
112 messages[i]));
116 MOCK_METHOD0(InvokeObserver, void());
118 private:
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;
126 closure.Run();
129 class MediaRouterMojoImplTest : public MediaRouterMojoTest {
130 public:
131 MediaRouterMojoImplTest() {}
132 ~MediaRouterMojoImplTest() override {}
135 // ProcessManager with a mocked method subset, for testing extension suspend
136 // handling.
137 class TestProcessManager : public extensions::ProcessManager {
138 public:
139 explicit TestProcessManager(content::BrowserContext* context)
140 : extensions::ProcessManager(
141 context,
142 context,
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));
156 private:
157 DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
160 // Mockable class for awaiting RegisterMediaRouteProvider callbacks.
161 class RegisterMediaRouteProviderHandler {
162 public:
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,
186 int tab_id,
187 const interfaces::MediaRouteProvider::CreateRouteCallback& cb) {
188 cb.Run(route.Pass(), mojo::String());
189 }));
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);
198 ProcessEventLoop();
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, _))
205 .WillOnce(Invoke(
206 [](const mojo::String& source, const mojo::String& sink,
207 const mojo::String& presentation_id, const mojo::String& origin,
208 int tab_id,
209 const interfaces::MediaRouteProvider::CreateRouteCallback& cb) {
210 cb.Run(interfaces::MediaRoutePtr(), mojo::String(kError));
211 }));
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);
220 ProcessEventLoop();
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());
245 }));
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);
254 ProcessEventLoop();
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, _))
261 .WillOnce(Invoke(
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));
266 }));
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);
275 ProcessEventLoop();
278 TEST_F(MediaRouterMojoImplTest, CloseRoute) {
279 EXPECT_CALL(mock_media_route_provider_, CloseRoute(mojo::String(kRouteId)));
280 router()->CloseRoute(kRouteId);
281 ProcessEventLoop();
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>();
290 const Issue* 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());
297 ProcessEventLoop();
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());
310 ProcessEventLoop();
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(_))
324 .Times(3)
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());
354 ProcessEventLoop();
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);
367 ProcessEventLoop();
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(_))
376 .Times(2)
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,
388 false, ""));
389 expected_routes.push_back(MediaRoute(kRouteId2, MediaSource(kSource),
390 MediaSink(kSink, kSink), kDescription,
391 false, ""));
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());
416 ProcessEventLoop();
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());
424 ProcessEventLoop();
427 TEST_F(MediaRouterMojoImplTest, SendRouteMessage) {
428 EXPECT_CALL(
429 mock_media_route_provider_,
430 SendRouteMessage(mojo::String(kRouteId), mojo::String(kMessage), _))
431 .WillOnce(Invoke([](
432 const MediaRoute::Id& route_id, const std::string& message,
433 const interfaces::MediaRouteProvider::SendRouteMessageCallback& cb) {
434 cb.Run(true);
435 }));
437 SendMessageCallbackHandler handler;
438 EXPECT_CALL(handler, Invoke(true));
439 router()->SendRouteMessage(kRouteId, kMessage,
440 base::Bind(&SendMessageCallbackHandler::Invoke,
441 base::Unretained(&handler)));
442 ProcessEventLoop();
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), _, _))
451 .WillOnce(Invoke([](
452 const MediaRoute::Id& route_id, const std::vector<uint8>& data,
453 const interfaces::MediaRouteProvider::SendRouteMessageCallback& cb) {
454 EXPECT_EQ(
455 0, memcmp(kBinaryMessage, &(data[0]), arraysize(kBinaryMessage)));
456 cb.Run(true);
457 }));
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)));
465 ProcessEventLoop();
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()));
506 ProcessEventLoop();
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
513 mojo_callback_2;
514 EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(_, _))
515 .WillOnce(SaveArg<1>(&mojo_callback_2));
516 ProcessEventLoop();
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";
524 observer.reset();
525 mojo_callback_2.Run(mojo_messages_2.Pass(), false);
526 ProcessEventLoop();
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
557 // observers.
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()));
573 ProcessEventLoop();
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
580 mojo_callback_2;
581 EXPECT_CALL(mock_media_route_provider_, ListenForRouteMessages(_, _))
582 .WillOnce(SaveArg<1>(&mojo_callback_2));
583 ProcessEventLoop();
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";
591 observer1.reset();
592 observer2.reset();
593 mojo_callback_2.Run(mojo_messages_2.Pass(), false);
594 ProcessEventLoop();
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()));
614 ProcessEventLoop();
616 mojo_callback.Run(mojo::Array<interfaces::RouteMessagePtr>(0), true);
617 ProcessEventLoop();
620 TEST_F(MediaRouterMojoImplTest, QueuedWhileAsleep) {
621 EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
622 .Times(2)
623 .WillRepeatedly(Return(true));
624 EXPECT_CALL(mock_event_page_tracker_, WakeEventPage(extension_id(), _))
625 .Times(2)
626 .WillRepeatedly(Return(true));
627 router()->CloseRoute(kRouteId);
628 router()->CloseRoute(kRouteId2);
629 ProcessEventLoop();
630 EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
631 .Times(1)
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();
636 ProcessEventLoop();
639 // Temporarily disabled until the issues with extension system teardown
640 // are addressed.
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),
672 kExtensionId);
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.
690 binding.reset();
691 media_router.BindToMojoRequest(mojo::GetProxy(&media_router_proxy),
692 kExtensionId);
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