Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1235)

Unified Diff: chrome/browser/media/router/media_router_mojo_impl_unittest.cc

Issue 1143603004: [Media Router] Add Media Router Mojo impl code. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed nits Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/media/router/media_router_mojo_impl_unittest.cc
diff --git a/chrome/browser/media/router/media_router_mojo_impl_unittest.cc b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ad1ebf9ab978b3806736423d33bc9459ed2eeb3e
--- /dev/null
+++ b/chrome/browser/media/router/media_router_mojo_impl_unittest.cc
@@ -0,0 +1,364 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
+#include "base/synchronization/waitable_event.h"
+#include "chrome/browser/media/router/media_route.h"
+#include "chrome/browser/media/router/media_router_mojo_test.h"
+#include "chrome/browser/media/router/mock_media_router.h"
+#include "chrome/browser/media/router/test_helper.h"
+#include "chrome/test/base/chrome_render_view_host_test_harness.h"
+#include "chrome/test/base/testing_profile.h"
+#include "extensions/browser/extension_registry.h"
+#include "extensions/browser/process_manager.h"
+#include "extensions/browser/process_manager_factory.h"
+#include "media/base/gmock_callback_support.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::_;
+using testing::Eq;
+using testing::Invoke;
+using testing::Pointee;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SaveArg;
+
+const char kDescription[] = "description";
+const char kError[] = "error";
+const char kExtensionId[] = "extension1234";
+const char kMessage[] = "message";
+const char kSource[] = "source1";
+const char kSource2[] = "source2";
+const char kRouteId[] = "routeId";
+const char kRouteId2[] = "routeId2";
+const char kSink[] = "sink";
+const char kSink2[] = "sink2";
+const char kSinkName[] = "sinkName";
xhwang 2015/05/28 06:53:21 nit: move these into the media_router namespace?
imcheng (use chromium acct) 2015/05/28 20:46:35 Done.
+
+namespace media_router {
+
+// Adapts Invoke(), which takes a move-only scoped_ptr parameter (not mockable)
+// to a variant that accepts raw pointers instead (mock friendly).
+class RouteResponseCallbackHandler {
+ public:
+ void Invoke(scoped_ptr<MediaRoute> route, const std::string& error_text) {
+ InvokeObserver(route.get(), error_text);
+ }
+
+ MOCK_METHOD2(InvokeObserver,
+ void(MediaRoute* route, const std::string& error_text));
+};
+
+template <typename T>
+void StoreAndRun(T* result, const base::Closure& closure, const T& result_val) {
+ *result = result_val;
+ closure.Run();
+}
+
+class MediaRouterMojoImplTest : public MediaRouterMojoTest {
+ public:
+ MediaRouterMojoImplTest() {}
+ ~MediaRouterMojoImplTest() override {}
+};
+
+// ProcessManager with a mocked method subset, for testing extension suspend
+// handling.
+class TestProcessManager : public extensions::ProcessManager {
+ public:
+ explicit TestProcessManager(content::BrowserContext* context)
+ : extensions::ProcessManager(
+ context,
+ context,
+ extensions::ExtensionRegistry::Get(context)) {}
+ ~TestProcessManager() override {}
+
+ static KeyedService* Create(content::BrowserContext* context) {
+ return new TestProcessManager(context);
+ }
+
+ MOCK_METHOD1(IsEventPageSuspended, bool(const std::string& ext_id));
+
+ MOCK_METHOD2(WakeEventPage,
+ bool(const std::string& extension_id,
+ const base::Callback<void(bool)>& callback));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestProcessManager);
+};
+
+// Mockable class for awaiting ProvideMediaRouter callbacks.
+class ProvideMediaRouterHandler {
+ public:
+ MOCK_METHOD1(Invoke, void(const std::string& instance_id));
+};
+
+TEST_F(MediaRouterMojoImplTest, CreateRoute) {
+ MediaRoute expected_route(kRouteId, MediaSource(std::string(kSource)),
+ MediaSink(kSink, kSinkName), "", false);
+ interfaces::MediaRoutePtr route = interfaces::MediaRoute::New();
+ route->media_source = kSource;
+ route->media_sink = interfaces::MediaSink::New();
+ route->media_sink->sink_id = kSink;
+ route->media_sink->name = kSinkName;
+ route->media_route_id = kRouteId;
+ route->description = kDescription;
+
+ // Use a lambda function as an invocation target here to work around
+ // a limitation with GMock::Invoke that prevents it from using move-only types
+ // in runnable parameter lists.
+ EXPECT_CALL(mock_mrpm_host_,
+ CreateRoute(mojo::String(kSource), mojo::String(kSink), _))
+ .WillOnce(Invoke(
+ [&route](const mojo::String& source, const mojo::String& sink,
+ const interfaces::MediaRouter::CreateRouteCallback& cb) {
+ cb.Run(route.Pass(), mojo::String());
+ }));
+
+ RouteResponseCallbackHandler handler;
+ EXPECT_CALL(handler, InvokeObserver(Pointee(Equals(expected_route)), ""));
+ observer_impl_->CreateRoute(kSource, kSink,
+ base::Bind(&RouteResponseCallbackHandler::Invoke,
+ base::Unretained(&handler)));
+ ProcessEventLoop();
+}
+
+TEST_F(MediaRouterMojoImplTest, CreateRouteFails) {
+ EXPECT_CALL(mock_mrpm_host_,
+ CreateRoute(mojo::String(kSource), mojo::String(kSink), _))
+ .WillOnce(
+ Invoke([](const mojo::String& source, const mojo::String& sink,
+ const interfaces::MediaRouter::CreateRouteCallback& cb) {
+ cb.Run(interfaces::MediaRoutePtr(), mojo::String(kError));
+ }));
+
+ RouteResponseCallbackHandler handler;
+ EXPECT_CALL(handler, InvokeObserver(nullptr, kError));
+ observer_impl_->CreateRoute(kSource, kSink,
+ base::Bind(&RouteResponseCallbackHandler::Invoke,
+ base::Unretained(&handler)));
+ ProcessEventLoop();
+}
+
+TEST_F(MediaRouterMojoImplTest, CloseRoute) {
+ EXPECT_CALL(mock_mrpm_host_, CloseRoute(mojo::String(kRouteId)));
+ observer_impl_->CloseRoute(kRouteId);
+ ProcessEventLoop();
+}
+
+TEST_F(MediaRouterMojoImplTest, RegisterAndUnregisterMediaSinksObserver) {
+ MediaSource media_source(kSource);
+
+ MockMediaRouter mock_router;
+ EXPECT_CALL(mock_mrpm_host_, StartObservingMediaSinks(mojo::String(kSource)))
+ .Times(2);
+ EXPECT_CALL(mock_mrpm_host_,
+ StartObservingMediaSinks(mojo::String(kSource2)));
+
+ MediaSinksObserver* captured_observer;
+ EXPECT_CALL(mock_router, RegisterMediaSinksObserver(_))
+ .Times(3)
+ .WillRepeatedly(SaveArg<0>(&captured_observer));
+
+ MockMediaSinksObserver sinks_observer(&mock_router, media_source);
+ EXPECT_EQ(&sinks_observer, captured_observer);
+ observer_impl_->RegisterMediaSinksObserver(&sinks_observer);
+ MockMediaSinksObserver extra_sinks_observer(&mock_router, media_source);
+ EXPECT_EQ(&extra_sinks_observer, captured_observer);
+ observer_impl_->RegisterMediaSinksObserver(&extra_sinks_observer);
+ MockMediaSinksObserver unrelated_sinks_observer(&mock_router,
+ MediaSource(kSource2));
+ EXPECT_EQ(&unrelated_sinks_observer, captured_observer);
+ observer_impl_->RegisterMediaSinksObserver(&unrelated_sinks_observer);
+
+ std::vector<MediaSink> expected_sinks;
+ expected_sinks.push_back(MediaSink(kSink, kSinkName));
+ expected_sinks.push_back(MediaSink(kSink2, kSinkName));
+
+ mojo::Array<interfaces::MediaSinkPtr> mojo_sinks(2);
+ mojo_sinks[0] = interfaces::MediaSink::New();
+ mojo_sinks[0]->sink_id = kSink;
+ mojo_sinks[0]->name = kSink;
+ mojo_sinks[1] = interfaces::MediaSink::New();
+ mojo_sinks[1]->sink_id = kSink2;
+ mojo_sinks[1]->name = kSink2;
+
+ EXPECT_CALL(sinks_observer, OnSinksReceived(SequenceEquals(expected_sinks)));
+ EXPECT_CALL(extra_sinks_observer,
+ OnSinksReceived(SequenceEquals(expected_sinks)));
+ observer_proxy_->OnSinksReceived(media_source.id(), mojo_sinks.Pass());
+ ProcessEventLoop();
+
+ EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&sinks_observer));
+ EXPECT_CALL(mock_router, UnregisterMediaSinksObserver(&extra_sinks_observer));
+ EXPECT_CALL(mock_router,
+ UnregisterMediaSinksObserver(&unrelated_sinks_observer));
+ EXPECT_CALL(mock_mrpm_host_, StopObservingMediaSinks(mojo::String(kSource)));
+ EXPECT_CALL(mock_mrpm_host_, StopObservingMediaSinks(mojo::String(kSource2)));
+ observer_impl_->UnregisterMediaSinksObserver(&sinks_observer);
+ observer_impl_->UnregisterMediaSinksObserver(&extra_sinks_observer);
+ observer_impl_->UnregisterMediaSinksObserver(&unrelated_sinks_observer);
+ ProcessEventLoop();
+}
+
+TEST_F(MediaRouterMojoImplTest, RegisterAndUnregisterMediaRoutesObserver) {
+ MockMediaRouter mock_router;
+ EXPECT_CALL(mock_mrpm_host_, StartObservingMediaRoutes()).Times(2);
+
+ MediaRoutesObserver* observer_captured;
+ EXPECT_CALL(mock_router, RegisterMediaRoutesObserver(_))
+ .Times(2)
+ .WillRepeatedly(SaveArg<0>(&observer_captured));
+ MockMediaRoutesObserver routes_observer(&mock_router);
+ EXPECT_EQ(observer_captured, &routes_observer);
+ MockMediaRoutesObserver extra_routes_observer(&mock_router);
+ EXPECT_EQ(observer_captured, &extra_routes_observer);
+ observer_impl_->RegisterMediaRoutesObserver(&routes_observer);
+ observer_impl_->RegisterMediaRoutesObserver(&extra_routes_observer);
+
+ std::vector<MediaRoute> expected_routes;
+ expected_routes.push_back(MediaRoute(kRouteId, MediaSource(kSource),
+ MediaSink(kSink, kSink), kDescription,
+ false));
+ expected_routes.push_back(MediaRoute(kRouteId2, MediaSource(kSource),
+ MediaSink(kSink, kSink), kDescription,
+ false));
+
+ mojo::Array<interfaces::MediaRoutePtr> mojo_routes(2);
+ mojo_routes[0] = interfaces::MediaRoute::New();
+ mojo_routes[0]->media_route_id = kRouteId;
+ mojo_routes[0]->media_source = kSource;
+ mojo_routes[0]->media_sink = interfaces::MediaSink::New();
+ mojo_routes[0]->media_sink->sink_id = kSink;
+ mojo_routes[0]->media_sink->name = kSink;
+ mojo_routes[0]->description = kDescription;
+ mojo_routes[0]->is_local = false;
+ mojo_routes[1] = interfaces::MediaRoute::New();
+ mojo_routes[1]->media_route_id = kRouteId2;
+ mojo_routes[1]->media_source = kSource;
+ mojo_routes[1]->media_sink = interfaces::MediaSink::New();
+ mojo_routes[1]->media_sink->sink_id = kSink;
+ mojo_routes[1]->media_sink->name = kSink;
+ mojo_routes[1]->description = kDescription;
+ mojo_routes[1]->is_local = false;
+
+ EXPECT_CALL(routes_observer,
+ OnRoutesUpdated(SequenceEquals(expected_routes)));
+ EXPECT_CALL(extra_routes_observer,
+ OnRoutesUpdated(SequenceEquals(expected_routes)));
+ observer_proxy_->OnRoutesUpdated(mojo_routes.Pass());
+ ProcessEventLoop();
+
+ EXPECT_CALL(mock_router, UnregisterMediaRoutesObserver(&routes_observer));
+ EXPECT_CALL(mock_router,
+ UnregisterMediaRoutesObserver(&extra_routes_observer));
+ observer_impl_->UnregisterMediaRoutesObserver(&routes_observer);
+ observer_impl_->UnregisterMediaRoutesObserver(&extra_routes_observer);
+ EXPECT_CALL(mock_mrpm_host_, StopObservingMediaRoutes());
+ ProcessEventLoop();
+}
+
+TEST_F(MediaRouterMojoImplTest, PostMessage) {
+ EXPECT_CALL(mock_mrpm_host_,
+ PostMessage(mojo::String(kRouteId), mojo::String(kMessage)));
+ observer_impl_->PostMessage(kRouteId, kMessage);
+ ProcessEventLoop();
+}
+
+TEST_F(MediaRouterMojoImplTest, QueuedWhileAsleep) {
+ EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id_))
+ .Times(2)
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_event_page_tracker_, WakeEventPage(extension_id_, _))
+ .Times(2)
+ .WillRepeatedly(Return(true));
+ observer_impl_->CloseRoute(kRouteId);
+ observer_impl_->CloseRoute(kRouteId2);
+ ProcessEventLoop();
+ EXPECT_CALL(mock_event_page_tracker_, IsEventPageSuspended(extension_id_))
+ .Times(1)
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(mock_mrpm_host_, CloseRoute(mojo::String(kRouteId)));
+ EXPECT_CALL(mock_mrpm_host_, CloseRoute(mojo::String(kRouteId2)));
+ ConnectProviderManagerService();
+ ProcessEventLoop();
+}
+
+// Temporarily disabled until the issues with extension system teardown
+// are addressed.
+// TODO(kmarshall): Re-enable this test. (http://crbug.com/490468)
+TEST(MediaRouterMojoExtensionTest, DISABLED_DeferredBindingAndSuspension) {
+ base::MessageLoop message_loop_(mojo::common::MessagePumpMojo::Create());
+
+ // Set up a mock ProcessManager instance.
+ TestingProfile profile;
+ extensions::ProcessManagerFactory::GetInstance()->SetTestingFactory(
+ &profile, &TestProcessManager::Create);
+ TestProcessManager* process_manager = static_cast<TestProcessManager*>(
+ extensions::ProcessManager::Get(&profile));
+
+ // Create MR and its proxy, so that it can be accessed through Mojo.
+ MediaRouterMojoImpl media_router;
+ interfaces::MediaRouterObserverPtr media_router_proxy;
xhwang 2015/05/28 06:53:21 Can we be consistent about naming mojo::InterfaceP
imcheng (use chromium acct) 2015/05/28 20:46:35 Done.
+
+ // Create a client object and its Mojo proxy.
+ testing::StrictMock<MockMojoMediaRouterService> mrpm;
xhwang 2015/05/28 06:53:21 throughout this CL, we have mrpm in many places. I
imcheng (use chromium acct) 2015/05/28 20:46:35 Done.
+ interfaces::MediaRouterPtr mrpm_proxy;
xhwang 2015/05/28 06:53:21 ditto about mrpm and proxy.
imcheng (use chromium acct) 2015/05/28 20:46:35 Done.
+
+ // CloseRoute is called before *any* extension has connected.
+ // It should be queued.
+ media_router.CloseRoute(kRouteId);
+
+ // MRPM connects.
+ scoped_ptr<mojo::Binding<interfaces::MediaRouter>> mrpm_binding(
+ new mojo::Binding<interfaces::MediaRouter>(&mrpm,
+ mojo::GetProxy(&mrpm_proxy)));
+ media_router.BindToMojoRequest(mojo::GetProxy(&media_router_proxy));
+ media_router.InitExtensionInfo(kExtensionId, &profile);
+
+ // The MRPM signals its readiness to the MR by registering itself via
+ // ProvideMediaRouter().
+ // Now that the MR and MRPM are fully initialized, the queued
+ // CloseRoute() call should be executed.
+ ProvideMediaRouterHandler provide_handler;
+ EXPECT_CALL(provide_handler, Invoke(testing::Not("")));
+ EXPECT_CALL(*process_manager, IsEventPageSuspended(kExtensionId))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mrpm, CloseRoute(mojo::String(kRouteId)));
+ media_router_proxy->ProvideMediaRouter(
+ mrpm_proxy.Pass(), base::Bind(&ProvideMediaRouterHandler::Invoke,
+ base::Unretained(&provide_handler)));
+ message_loop_.RunUntilIdle();
+
+ // MRPM's extension is suspended and re-awoken.
+ mrpm_binding.reset();
+ media_router.BindToMojoRequest(mojo::GetProxy(&media_router_proxy));
+ media_router.InitExtensionInfo(kExtensionId, &profile);
+ EXPECT_CALL(*process_manager, IsEventPageSuspended(kExtensionId))
+ .WillOnce(Return(true));
+ EXPECT_CALL(*process_manager, WakeEventPage(kExtensionId, _))
+ .WillOnce(testing::DoAll(media::RunCallback<1>(true), Return(true)));
+ media_router.CloseRoute(kRouteId2);
+ message_loop_.RunUntilIdle();
+
+ // ProvideMediaRouter() is called.
+ // The queued CloseRoute(kRouteId2) call should be executed.
+ EXPECT_CALL(provide_handler, Invoke(testing::Not("")));
+ EXPECT_CALL(*process_manager, IsEventPageSuspended(kExtensionId))
+ .WillOnce(Return(false));
+ EXPECT_CALL(mrpm, CloseRoute(mojo::String(kRouteId2)));
+ mrpm_binding.reset(new mojo::Binding<interfaces::MediaRouter>(
+ &mrpm, mojo::GetProxy(&mrpm_proxy)));
+ media_router_proxy->ProvideMediaRouter(
+ mrpm_proxy.Pass(), base::Bind(&ProvideMediaRouterHandler::Invoke,
+ base::Unretained(&provide_handler)));
+ message_loop_.RunUntilIdle();
+}
+
+} // namespace media_router

Powered by Google App Engine
This is Rietveld 408576698