[MediaRouter] Update MR-2-Extension's PostMessage to return boolean.
[chromium-blink-merge.git] / chrome / browser / media / router / media_router_mojo_impl_unittest.cc
blob87ad51158da4710b433d59723189fc4eec830117
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/media_route.h"
13 #include "chrome/browser/media/router/media_router_mojo_test.h"
14 #include "chrome/browser/media/router/mock_media_router.h"
15 #include "chrome/browser/media/router/test_helper.h"
16 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
17 #include "chrome/test/base/testing_profile.h"
18 #include "extensions/browser/extension_registry.h"
19 #include "extensions/browser/process_manager.h"
20 #include "extensions/browser/process_manager_factory.h"
21 #include "media/base/gmock_callback_support.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
25 using testing::_;
26 using testing::Eq;
27 using testing::Invoke;
28 using testing::Pointee;
29 using testing::Return;
30 using testing::ReturnRef;
31 using testing::SaveArg;
33 namespace media_router {
35 namespace {
37 const char kDescription[] = "description";
38 const char kError[] = "error";
39 const char kExtensionId[] = "extension1234";
40 const char kMessage[] = "message";
41 const char kSource[] = "source1";
42 const char kSource2[] = "source2";
43 const char kRouteId[] = "routeId";
44 const char kRouteId2[] = "routeId2";
45 const char kSink[] = "sink";
46 const char kSink2[] = "sink2";
47 const char kSinkName[] = "sinkName";
49 } // namespace
51 // Adapts Invoke(), which takes a move-only scoped_ptr parameter (not mockable)
52 // to a variant that accepts raw pointers instead (mock friendly).
53 class RouteResponseCallbackHandler {
54 public:
55 void Invoke(scoped_ptr<MediaRoute> route, const std::string& error_text) {
56 InvokeObserver(route.get(), error_text);
59 MOCK_METHOD2(InvokeObserver,
60 void(MediaRoute* route, const std::string& error_text));
63 class SendMessageCallbackHandler {
64 public:
65 MOCK_METHOD1(Invoke, void(bool));
68 template <typename T>
69 void StoreAndRun(T* result, const base::Closure& closure, const T& result_val) {
70 *result = result_val;
71 closure.Run();
74 class MediaRouterMojoImplTest : public MediaRouterMojoTest {
75 public:
76 MediaRouterMojoImplTest() {}
77 ~MediaRouterMojoImplTest() override {}
80 // ProcessManager with a mocked method subset, for testing extension suspend
81 // handling.
82 class TestProcessManager : public extensions::ProcessManager {
83 public:
84 explicit TestProcessManager(content::BrowserContext* context)
85 : extensions::ProcessManager(
86 context,
87 context,
88 extensions::ExtensionRegistry::Get(context)) {}
89 ~TestProcessManager() override {}
91 static scoped_ptr<KeyedService> Create(content::BrowserContext* context) {
92 return make_scoped_ptr(new TestProcessManager(context));
95 MOCK_METHOD1(IsEventPageSuspended, bool(const std::string& ext_id));
97 MOCK_METHOD2(WakeEventPage,
98 bool(const std::string& extension_id,
99 const base::Callback<void(bool)>& callback));
101 private:
102 DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
105 // Mockable class for awaiting ProvideMediaRouter callbacks.
106 class ProvideMediaRouterHandler {
107 public:
108 MOCK_METHOD1(Invoke, void(const std::string& instance_id));
111 TEST_F(MediaRouterMojoImplTest, CreateRoute) {
112 MediaRoute expected_route(kRouteId, MediaSource(std::string(kSource)),
113 MediaSink(kSink, kSinkName), "", false);
114 interfaces::MediaRoutePtr route = interfaces::MediaRoute::New();
115 route->media_source = kSource;
116 route->media_sink = interfaces::MediaSink::New();
117 route->media_sink->sink_id = kSink;
118 route->media_sink->name = kSinkName;
119 route->media_route_id = kRouteId;
120 route->description = kDescription;
122 // Use a lambda function as an invocation target here to work around
123 // a limitation with GMock::Invoke that prevents it from using move-only types
124 // in runnable parameter lists.
125 EXPECT_CALL(mock_mojo_media_router_service_,
126 CreateRoute(mojo::String(kSource), mojo::String(kSink), _))
127 .WillOnce(Invoke(
128 [&route](const mojo::String& source, const mojo::String& sink,
129 const interfaces::MediaRouter::CreateRouteCallback& cb) {
130 cb.Run(route.Pass(), mojo::String());
131 }));
133 RouteResponseCallbackHandler handler;
134 EXPECT_CALL(handler, InvokeObserver(Pointee(Equals(expected_route)), ""));
135 router()->CreateRoute(kSource, kSink,
136 base::Bind(&RouteResponseCallbackHandler::Invoke,
137 base::Unretained(&handler)));
138 ProcessEventLoop();
141 TEST_F(MediaRouterMojoImplTest, CreateRouteFails) {
142 EXPECT_CALL(mock_mojo_media_router_service_,
143 CreateRoute(mojo::String(kSource), mojo::String(kSink), _))
144 .WillOnce(
145 Invoke([](const mojo::String& source, const mojo::String& sink,
146 const interfaces::MediaRouter::CreateRouteCallback& cb) {
147 cb.Run(interfaces::MediaRoutePtr(), mojo::String(kError));
148 }));
150 RouteResponseCallbackHandler handler;
151 EXPECT_CALL(handler, InvokeObserver(nullptr, kError));
152 router()->CreateRoute(kSource, kSink,
153 base::Bind(&RouteResponseCallbackHandler::Invoke,
154 base::Unretained(&handler)));
155 ProcessEventLoop();
158 TEST_F(MediaRouterMojoImplTest, CloseRoute) {
159 EXPECT_CALL(mock_mojo_media_router_service_,
160 CloseRoute(mojo::String(kRouteId)));
161 router()->CloseRoute(kRouteId);
162 ProcessEventLoop();
165 TEST_F(MediaRouterMojoImplTest, RegisterAndUnregisterMediaSinksObserver) {
166 MediaSource media_source(kSource);
168 MockMediaRouter mock_router;
169 EXPECT_CALL(mock_mojo_media_router_service_,
170 StartObservingMediaSinks(mojo::String(kSource))).Times(2);
171 EXPECT_CALL(mock_mojo_media_router_service_,
172 StartObservingMediaSinks(mojo::String(kSource2)));
174 MediaSinksObserver* captured_observer;
175 EXPECT_CALL(mock_router, RegisterMediaSinksObserver(_))
176 .Times(3)
177 .WillRepeatedly(SaveArg<0>(&captured_observer));
179 MockMediaSinksObserver sinks_observer(&mock_router, media_source);
180 EXPECT_EQ(&sinks_observer, captured_observer);
181 router()->RegisterMediaSinksObserver(&sinks_observer);
182 MockMediaSinksObserver extra_sinks_observer(&mock_router, media_source);
183 EXPECT_EQ(&extra_sinks_observer, captured_observer);
184 router()->RegisterMediaSinksObserver(&extra_sinks_observer);
185 MockMediaSinksObserver unrelated_sinks_observer(&mock_router,
186 MediaSource(kSource2));
187 EXPECT_EQ(&unrelated_sinks_observer, captured_observer);
188 router()->RegisterMediaSinksObserver(&unrelated_sinks_observer);
190 std::vector<MediaSink> expected_sinks;
191 expected_sinks.push_back(MediaSink(kSink, kSinkName));
192 expected_sinks.push_back(MediaSink(kSink2, kSinkName));
194 mojo::Array<interfaces::MediaSinkPtr> mojo_sinks(2);
195 mojo_sinks[0] = interfaces::MediaSink::New();
196 mojo_sinks[0]->sink_id = kSink;
197 mojo_sinks[0]->name = kSink;
198 mojo_sinks[1] = interfaces::MediaSink::New();
199 mojo_sinks[1]->sink_id = kSink2;
200 mojo_sinks[1]->name = kSink2;
202 EXPECT_CALL(sinks_observer, OnSinksReceived(SequenceEquals(expected_sinks)));
203 EXPECT_CALL(extra_sinks_observer,
204 OnSinksReceived(SequenceEquals(expected_sinks)));
205 mojo_media_router_observer_->OnSinksReceived(media_source.id(),
206 mojo_sinks.Pass());
207 ProcessEventLoop();
209 EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&sinks_observer));
210 EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&extra_sinks_observer));
211 EXPECT_CALL(mock_router,
212 UnregisterMediaSinksObserver(&unrelated_sinks_observer));
213 EXPECT_CALL(mock_mojo_media_router_service_,
214 StopObservingMediaSinks(mojo::String(kSource)));
215 EXPECT_CALL(mock_mojo_media_router_service_,
216 StopObservingMediaSinks(mojo::String(kSource2)));
217 router()->UnregisterMediaSinksObserver(&sinks_observer);
218 router()->UnregisterMediaSinksObserver(&extra_sinks_observer);
219 router()->UnregisterMediaSinksObserver(&unrelated_sinks_observer);
220 ProcessEventLoop();
223 TEST_F(MediaRouterMojoImplTest, RegisterAndUnregisterMediaRoutesObserver) {
224 MockMediaRouter mock_router;
225 EXPECT_CALL(mock_mojo_media_router_service_, StartObservingMediaRoutes())
226 .Times(2);
228 MediaRoutesObserver* observer_captured;
229 EXPECT_CALL(mock_router, RegisterMediaRoutesObserver(_))
230 .Times(2)
231 .WillRepeatedly(SaveArg<0>(&observer_captured));
232 MockMediaRoutesObserver routes_observer(&mock_router);
233 EXPECT_EQ(observer_captured, &routes_observer);
234 MockMediaRoutesObserver extra_routes_observer(&mock_router);
235 EXPECT_EQ(observer_captured, &extra_routes_observer);
236 router()->RegisterMediaRoutesObserver(&routes_observer);
237 router()->RegisterMediaRoutesObserver(&extra_routes_observer);
239 std::vector<MediaRoute> expected_routes;
240 expected_routes.push_back(MediaRoute(kRouteId, MediaSource(kSource),
241 MediaSink(kSink, kSink), kDescription,
242 false));
243 expected_routes.push_back(MediaRoute(kRouteId2, MediaSource(kSource),
244 MediaSink(kSink, kSink), kDescription,
245 false));
247 mojo::Array<interfaces::MediaRoutePtr> mojo_routes(2);
248 mojo_routes[0] = interfaces::MediaRoute::New();
249 mojo_routes[0]->media_route_id = kRouteId;
250 mojo_routes[0]->media_source = kSource;
251 mojo_routes[0]->media_sink = interfaces::MediaSink::New();
252 mojo_routes[0]->media_sink->sink_id = kSink;
253 mojo_routes[0]->media_sink->name = kSink;
254 mojo_routes[0]->description = kDescription;
255 mojo_routes[0]->is_local = false;
256 mojo_routes[1] = interfaces::MediaRoute::New();
257 mojo_routes[1]->media_route_id = kRouteId2;
258 mojo_routes[1]->media_source = kSource;
259 mojo_routes[1]->media_sink = interfaces::MediaSink::New();
260 mojo_routes[1]->media_sink->sink_id = kSink;
261 mojo_routes[1]->media_sink->name = kSink;
262 mojo_routes[1]->description = kDescription;
263 mojo_routes[1]->is_local = false;
265 EXPECT_CALL(routes_observer,
266 OnRoutesUpdated(SequenceEquals(expected_routes)));
267 EXPECT_CALL(extra_routes_observer,
268 OnRoutesUpdated(SequenceEquals(expected_routes)));
269 mojo_media_router_observer_->OnRoutesUpdated(mojo_routes.Pass());
270 ProcessEventLoop();
272 EXPECT_CALL(mock_router, UnregisterMediaRoutesObserver(&routes_observer));
273 EXPECT_CALL(mock_router,
274 UnregisterMediaRoutesObserver(&extra_routes_observer));
275 router()->UnregisterMediaRoutesObserver(&routes_observer);
276 router()->UnregisterMediaRoutesObserver(&extra_routes_observer);
277 EXPECT_CALL(mock_mojo_media_router_service_, StopObservingMediaRoutes());
278 ProcessEventLoop();
281 TEST_F(MediaRouterMojoImplTest, SendRouteMessage) {
282 EXPECT_CALL(
283 mock_mojo_media_router_service_,
284 SendRouteMessage(mojo::String(kRouteId), mojo::String(kMessage), _))
285 .WillOnce(Invoke(
286 [](const MediaRoute::Id& route_id, const std::string& message,
287 const interfaces::MediaRouter::SendRouteMessageCallback& cb) {
288 cb.Run(true);
289 }));
291 SendMessageCallbackHandler handler;
292 EXPECT_CALL(handler, Invoke(true));
293 router()->SendRouteMessage(kRouteId, kMessage,
294 base::Bind(&SendMessageCallbackHandler::Invoke,
295 base::Unretained(&handler)));
296 ProcessEventLoop();
299 TEST_F(MediaRouterMojoImplTest, QueuedWhileAsleep) {
300 EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
301 .Times(2)
302 .WillRepeatedly(Return(true));
303 EXPECT_CALL(mock_event_page_tracker_, WakeEventPage(extension_id(), _))
304 .Times(2)
305 .WillRepeatedly(Return(true));
306 router()->CloseRoute(kRouteId);
307 router()->CloseRoute(kRouteId2);
308 ProcessEventLoop();
309 EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id()))
310 .Times(1)
311 .WillRepeatedly(Return(false));
312 EXPECT_CALL(mock_mojo_media_router_service_,
313 CloseRoute(mojo::String(kRouteId)));
314 EXPECT_CALL(mock_mojo_media_router_service_,
315 CloseRoute(mojo::String(kRouteId2)));
316 ConnectProviderManagerService();
317 ProcessEventLoop();
320 // Temporarily disabled until the issues with extension system teardown
321 // are addressed.
322 // TODO(kmarshall): Re-enable this test. (http://crbug.com/490468)
323 TEST(MediaRouterMojoExtensionTest, DISABLED_DeferredBindingAndSuspension) {
324 base::MessageLoop message_loop(mojo::common::MessagePumpMojo::Create());
326 // Set up a mock ProcessManager instance.
327 TestingProfile profile;
328 extensions::ProcessManagerFactory::GetInstance()->SetTestingFactory(
329 &profile, &TestProcessManager::Create);
330 TestProcessManager* process_manager = static_cast<TestProcessManager*>(
331 extensions::ProcessManager::Get(&profile));
333 // Create MR and its proxy, so that it can be accessed through Mojo.
334 MediaRouterMojoImpl media_router(process_manager);
335 interfaces::MediaRouterObserverPtr mojo_media_router_observer;
337 // Create a client object and its Mojo proxy.
338 testing::StrictMock<MockMojoMediaRouterService>
339 mock_mojo_media_router_service;
340 interfaces::MediaRouterPtr mojo_media_router;
342 // CloseRoute is called before *any* extension has connected.
343 // It should be queued.
344 media_router.CloseRoute(kRouteId);
346 // Construct bindings so that |media_router| delegates calls to
347 // |mojo_media_router|, which are then handled by
348 // |mock_mojo_media_router_service|.
349 scoped_ptr<mojo::Binding<interfaces::MediaRouter>> binding(
350 new mojo::Binding<interfaces::MediaRouter>(
351 &mock_mojo_media_router_service, mojo::GetProxy(&mojo_media_router)));
352 media_router.BindToMojoRequest(mojo::GetProxy(&mojo_media_router_observer),
353 kExtensionId);
355 // |mojo_media_router| signals its readiness to the MR by registering
356 // itself via ProvideMediaRouter().
357 // Now that the |media_router| and |mojo_media_router| are fully initialized,
358 // the queued CloseRoute() call should be executed.
359 ProvideMediaRouterHandler provide_handler;
360 EXPECT_CALL(provide_handler, Invoke(testing::Not("")));
361 EXPECT_CALL(*process_manager, IsEventPageSuspended(kExtensionId))
362 .WillOnce(Return(false));
363 EXPECT_CALL(mock_mojo_media_router_service,
364 CloseRoute(mojo::String(kRouteId)));
365 mojo_media_router_observer->ProvideMediaRouter(
366 mojo_media_router.Pass(), base::Bind(&ProvideMediaRouterHandler::Invoke,
367 base::Unretained(&provide_handler)));
368 message_loop.RunUntilIdle();
370 // Extension is suspended and re-awoken.
371 binding.reset();
372 media_router.BindToMojoRequest(mojo::GetProxy(&mojo_media_router_observer),
373 kExtensionId);
374 EXPECT_CALL(*process_manager, IsEventPageSuspended(kExtensionId))
375 .WillOnce(Return(true));
376 EXPECT_CALL(*process_manager, WakeEventPage(kExtensionId, _))
377 .WillOnce(testing::DoAll(media::RunCallback<1>(true), Return(true)));
378 media_router.CloseRoute(kRouteId2);
379 message_loop.RunUntilIdle();
381 // ProvideMediaRouter() is called.
382 // The queued CloseRoute(kRouteId2) call should be executed.
383 EXPECT_CALL(provide_handler, Invoke(testing::Not("")));
384 EXPECT_CALL(*process_manager, IsEventPageSuspended(kExtensionId))
385 .WillOnce(Return(false));
386 EXPECT_CALL(mock_mojo_media_router_service,
387 CloseRoute(mojo::String(kRouteId2)));
388 binding.reset(new mojo::Binding<interfaces::MediaRouter>(
389 &mock_mojo_media_router_service, mojo::GetProxy(&mojo_media_router)));
390 mojo_media_router_observer->ProvideMediaRouter(
391 mojo_media_router.Pass(), base::Bind(&ProvideMediaRouterHandler::Invoke,
392 base::Unretained(&provide_handler)));
393 message_loop.RunUntilIdle();
396 } // namespace media_router