summaryrefslogtreecommitdiffstats
path: root/chrome/test/media_router
diff options
context:
space:
mode:
authorleilei <leilei@chromium.org>2015-06-23 17:12:08 -0700
committerCommit bot <commit-bot@chromium.org>2015-06-24 00:13:24 +0000
commite5a0c629754ddff736a351160762820daac1bc1b (patch)
tree02417ee69dee4c4cbb9e9c55c779a67de7183b79 /chrome/test/media_router
parent3323eee51c645e4db9e24ecc0648161bc814556d (diff)
downloadchromium_src-e5a0c629754ddff736a351160762820daac1bc1b.zip
chromium_src-e5a0c629754ddff736a351160762820daac1bc1b.tar.gz
chromium_src-e5a0c629754ddff736a351160762820daac1bc1b.tar.bz2
[Media Router] Add integration tests and e2e tests for media router and presentation APIs.
BUG=464227 Committed: https://crrev.com/ec50c44f4753c202c4578b3370aac4b26cf3e45d Cr-Commit-Position: refs/heads/master@{#335647} Review URL: https://codereview.chromium.org/1180013008 Cr-Commit-Position: refs/heads/master@{#335820}
Diffstat (limited to 'chrome/test/media_router')
-rw-r--r--chrome/test/media_router/OWNERS1
-rw-r--r--chrome/test/media_router/e2e_tests.gyp25
-rw-r--r--chrome/test/media_router/media_router_base_browsertest.cc128
-rw-r--r--chrome/test/media_router/media_router_base_browsertest.h82
-rw-r--r--chrome/test/media_router/media_router_e2e_browsertest.cc156
-rw-r--r--chrome/test/media_router/media_router_e2e_browsertest.h73
-rw-r--r--chrome/test/media_router/media_router_integration_browsertest.cc97
-rw-r--r--chrome/test/media_router/media_router_integration_browsertest.h40
-rw-r--r--chrome/test/media_router/media_router_tests.gypi32
-rw-r--r--chrome/test/media_router/media_router_tests.isolate46
-rw-r--r--chrome/test/media_router/resources/basic_test.html10
-rw-r--r--chrome/test/media_router/resources/common.js79
-rw-r--r--chrome/test/media_router/test_media_sinks_observer.cc29
-rw-r--r--chrome/test/media_router/test_media_sinks_observer.h34
14 files changed, 832 insertions, 0 deletions
diff --git a/chrome/test/media_router/OWNERS b/chrome/test/media_router/OWNERS
index a138b5a..f30a0b6 100644
--- a/chrome/test/media_router/OWNERS
+++ b/chrome/test/media_router/OWNERS
@@ -7,3 +7,4 @@ wez@chromium.org
apacible@chromium.org
haibinlu@chromium.org
imcheng@chromium.org
+leilei@chromium.org
diff --git a/chrome/test/media_router/e2e_tests.gyp b/chrome/test/media_router/e2e_tests.gyp
new file mode 100644
index 0000000..56aad73
--- /dev/null
+++ b/chrome/test/media_router/e2e_tests.gyp
@@ -0,0 +1,25 @@
+# Copyright (c) 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.
+
+{
+ 'conditions': [
+ ['archive_media_router_tests==1', {
+ 'targets': [
+ {
+ 'target_name': 'media_router_e2e_tests_run',
+ 'type': 'none',
+ 'dependencies': [
+ '../../chrome.gyp:browser_tests',
+ ],
+ 'includes': [
+ '../../../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'media_router_tests.isolate',
+ ],
+ }, # target_name: 'media_router_e2e_tests_run'
+ ],
+ }],
+ ],
+} \ No newline at end of file
diff --git a/chrome/test/media_router/media_router_base_browsertest.cc b/chrome/test/media_router/media_router_base_browsertest.cc
new file mode 100644
index 0000000..a78c5ce
--- /dev/null
+++ b/chrome/test/media_router/media_router_base_browsertest.cc
@@ -0,0 +1,128 @@
+// 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 "chrome/test/media_router/media_router_base_browsertest.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/timer/elapsed_timer.h"
+#include "chrome/browser/extensions/unpacked_installer.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/test_utils.h"
+#include "extensions/browser/process_manager.h"
+
+namespace {
+// Command line argument to specify CRX extension location.
+const char kExtensionCrx[] = "extension-crx";
+// Command line argument to specify unpacked extension location.
+const char kExtensionUnpacked[] = "extension-unpacked";
+} // namespace
+
+namespace media_router {
+
+MediaRouterBaseBrowserTest::MediaRouterBaseBrowserTest()
+ : extension_load_event_(false, false), extension_host_created_(false) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kEnableMediaRouter);
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kEnableBlinkFeatures, "Presentation");
+}
+
+MediaRouterBaseBrowserTest::~MediaRouterBaseBrowserTest() {
+}
+
+void MediaRouterBaseBrowserTest::SetUp() {
+ ParseCommandLine();
+ ExtensionBrowserTest::SetUp();
+}
+
+void MediaRouterBaseBrowserTest::TearDown() {
+ ExtensionBrowserTest::TearDown();
+}
+
+void MediaRouterBaseBrowserTest::SetUpOnMainThread() {
+ extensions::ProcessManager* process_manager =
+ extensions::ProcessManager::Get(browser()->profile());
+ DCHECK(process_manager);
+ process_manager->AddObserver(this);
+ InstallAndEnableMRExtension();
+ extension_load_event_.Wait();
+}
+
+void MediaRouterBaseBrowserTest::TearDownOnMainThread() {
+ UninstallMRExtension();
+ extensions::ProcessManager* process_manager =
+ extensions::ProcessManager::Get(browser()->profile());
+ DCHECK(process_manager);
+ process_manager->RemoveObserver(this);
+}
+
+void MediaRouterBaseBrowserTest::InstallAndEnableMRExtension() {
+ if (is_unpacked()) {
+ const extensions::Extension* extension = LoadExtension(extension_unpacked_);
+ extension_id_ = extension->id();
+ } else {
+ NOTIMPLEMENTED();
+ }
+}
+
+void MediaRouterBaseBrowserTest::UninstallMRExtension() {
+ if (!extension_id_.empty()) {
+ UninstallExtension(extension_id_);
+ }
+}
+
+void MediaRouterBaseBrowserTest::ConditionalWait(
+ base::TimeDelta timeout,
+ base::TimeDelta interval,
+ const base::Callback<bool(void)>& callback) {
+ base::ElapsedTimer timer;
+ while (!callback.Run() && timer.Elapsed() < timeout) {
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), interval);
+ run_loop.Run();
+ }
+}
+
+void MediaRouterBaseBrowserTest::Wait(base::TimeDelta timeout) {
+ base::RunLoop run_loop;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(), timeout);
+ run_loop.Run();
+}
+
+void MediaRouterBaseBrowserTest::OnBackgroundHostCreated(
+ extensions::ExtensionHost* host) {
+ extension_host_created_ = true;
+ DVLOG(0) << "Host created";
+ extension_load_event_.Signal();
+}
+
+void MediaRouterBaseBrowserTest::ParseCommandLine() {
+ DVLOG(0) << "ParseCommandLine";
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+ extension_crx_ = command_line->GetSwitchValuePath(kExtensionCrx);
+ extension_unpacked_ = command_line->GetSwitchValuePath(kExtensionUnpacked);
+
+ // Check if there is mr_extension folder under PRODUCT_DIR folder.
+ if (extension_crx_.empty() && extension_unpacked_.empty()) {
+ base::FilePath base_dir;
+ ASSERT_TRUE(PathService::Get(base::DIR_EXE, &base_dir));
+ base::FilePath extension_path =
+ base_dir.Append(FILE_PATH_LITERAL("mr_extension/"));
+ if (PathExists(extension_path)) {
+ extension_unpacked_ = extension_path;
+ }
+ }
+
+ // Exactly one of these two arguments should be provided.
+ ASSERT_NE(extension_crx_.empty(), extension_unpacked_.empty());
+}
+
+} // namespace media_router
diff --git a/chrome/test/media_router/media_router_base_browsertest.h b/chrome/test/media_router/media_router_base_browsertest.h
new file mode 100644
index 0000000..e1d29c4
--- /dev/null
+++ b/chrome/test/media_router/media_router_base_browsertest.h
@@ -0,0 +1,82 @@
+// 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.
+
+#ifndef CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_BASE_BROWSERTEST_H_
+#define CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_BASE_BROWSERTEST_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/timer/timer.h"
+#include "chrome/browser/extensions/extension_apitest.h"
+#include "extensions/browser/process_manager_observer.h"
+
+namespace media_router {
+
+class MediaRouter;
+
+/**
+ * Base class for media router browser test.
+ *
+ * It provides the basic functions for integration and e2e browser tests,
+ * including install unpacked or packed extension at beginning of the test,
+ * uninstall the extension at the end of the test.
+ *
+ * This class accepts two flags to specify the location of MR extension:
+ * 1. "--extension-crx" flag to specify the packed extension location
+ * 2. "--extension-unpacked" flag to specify the unpacked extension location
+ * Only one of them should be passed when run browser tests.
+ */
+class MediaRouterBaseBrowserTest : public ExtensionBrowserTest,
+ public extensions::ProcessManagerObserver {
+ public:
+ MediaRouterBaseBrowserTest();
+ ~MediaRouterBaseBrowserTest() override;
+
+ // InProcessBrowserTest Overrides
+ void SetUp() override;
+ void TearDown() override;
+
+ protected:
+ // InProcessBrowserTest Overrides
+ void SetUpOnMainThread() override;
+ void TearDownOnMainThread() override;
+
+ void InstallAndEnableMRExtension();
+ void UninstallMRExtension();
+
+ virtual void ParseCommandLine();
+
+ // extensions::ProcessManagerObserver Overrides
+ void OnBackgroundHostCreated(extensions::ExtensionHost* host) override;
+
+ // Wait until get the successful callback or timeout.
+ // TODO(leilei): Replace this method with WaitableEvent class.
+ void ConditionalWait(base::TimeDelta timeout,
+ base::TimeDelta interval,
+ const base::Callback<bool(void)>& callback);
+
+ // Wait for a specific time.
+ void Wait(base::TimeDelta timeout);
+
+ bool is_unpacked() const { return !extension_unpacked_.empty(); }
+
+ bool is_extension_host_created() const { return extension_host_created_; }
+
+ // These values are initialized via flags.
+ base::FilePath extension_crx_;
+ base::FilePath extension_unpacked_;
+
+ base::WaitableEvent extension_load_event_;
+ std::string extension_id_;
+ bool extension_host_created_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MediaRouterBaseBrowserTest);
+};
+
+} // namespace media_router
+
+#endif // CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_BASE_BROWSERTEST_H_
diff --git a/chrome/test/media_router/media_router_e2e_browsertest.cc b/chrome/test/media_router/media_router_e2e_browsertest.cc
new file mode 100644
index 0000000..24f6767
--- /dev/null
+++ b/chrome/test/media_router/media_router_e2e_browsertest.cc
@@ -0,0 +1,156 @@
+// 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 "chrome/test/media_router/media_router_e2e_browsertest.h"
+
+#include "base/command_line.h"
+#include "base/stl_util.h"
+#include "chrome/browser/media/router/media_router.h"
+#include "chrome/browser/media/router/media_router_mojo_impl.h"
+#include "chrome/browser/media/router/media_router_mojo_impl_factory.h"
+#include "chrome/browser/media/router/media_source.h"
+#include "chrome/browser/media/router/media_source_helper.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/sessions/session_tab_helper.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+// Use the following command to run e2e browser tests:
+// ./out/Debug/browser_tests --user-data-dir=<empty user data dir>
+// --extension-unpacked=<mr extension dir>
+// --receiver=<chromecast device name>
+// --enable-pixel-output-in-tests --run-manual
+// --gtest_filter=MediaRouterE2EBrowserTest.<test case name>
+// --enable-logging=stderr
+// --whitelisted-extension-id=enhhojjnijigcajfphajepfemndkmdlo
+// --ui-test-action-timeout=200000
+// --enable-media-router
+
+namespace {
+// Command line argument to specify receiver,
+const char kReceiver[] = "receiver";
+// URL to launch Castv2Player_Staging app on Chromecast
+const char kCastAppPresentationUrl[] =
+ "https://google.com/cast#__castAppId__=BE6E4473";
+} // namespace
+
+namespace media_router {
+
+MediaRouterE2EBrowserTest::MediaRouterE2EBrowserTest()
+ : media_router_(nullptr) {
+}
+
+MediaRouterE2EBrowserTest::~MediaRouterE2EBrowserTest() {
+}
+
+void MediaRouterE2EBrowserTest::SetUpOnMainThread() {
+ MediaRouterBaseBrowserTest::SetUpOnMainThread();
+ media_router_ =
+ MediaRouterMojoImplFactory::GetApiForBrowserContext(browser()->profile());
+ DCHECK(media_router_);
+}
+
+void MediaRouterE2EBrowserTest::TearDownOnMainThread() {
+ MediaRouterBaseBrowserTest::TearDownOnMainThread();
+ media_router_ = nullptr;
+}
+
+void MediaRouterE2EBrowserTest::OnRouteResponseReceived(
+ scoped_ptr<MediaRoute> route,
+ const std::string& error) {
+ ASSERT_TRUE(route.get());
+ route_id_ = route->media_route_id();
+}
+
+void MediaRouterE2EBrowserTest::CreateMediaRoute(const MediaSource& source,
+ const GURL& origin,
+ int tab_id) {
+ DCHECK(media_router_);
+ observer_.reset(new TestMediaSinksObserver(media_router_, source));
+
+ DVLOG(1) << "Receiver name: " << receiver_;
+ // Wait for MediaSinks compatible with |source| to be discovered.
+ ConditionalWait(base::TimeDelta::FromSeconds(30),
+ base::TimeDelta::FromSeconds(1),
+ base::Bind(&MediaRouterE2EBrowserTest::IsSinkDiscovered,
+ base::Unretained(this)));
+
+ const auto& sink_map = observer_->sink_map;
+ const auto it = sink_map.find(receiver_);
+ const MediaSink& sink = it->second;
+
+ // The callback will set route_id_ when invoked.
+ media_router_->CreateRoute(
+ source.id(), sink.id(), origin, tab_id,
+ base::Bind(&MediaRouterE2EBrowserTest::OnRouteResponseReceived,
+ base::Unretained(this)));
+
+ // Wait for the route request to be fulfilled (and route to be started).
+ ConditionalWait(base::TimeDelta::FromSeconds(30),
+ base::TimeDelta::FromSeconds(1),
+ base::Bind(&MediaRouterE2EBrowserTest::IsRouteCreated,
+ base::Unretained(this)));
+}
+
+void MediaRouterE2EBrowserTest::StopMediaRoute() {
+ ASSERT_FALSE(route_id_.empty());
+
+ media_router_->CloseRoute(route_id_);
+
+ observer_.reset();
+ route_id_.clear();
+}
+
+void MediaRouterE2EBrowserTest::ParseCommandLine() {
+ MediaRouterBaseBrowserTest::ParseCommandLine();
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+
+ receiver_ = command_line->GetSwitchValueASCII(kReceiver);
+ ASSERT_FALSE(receiver_.empty());
+}
+
+bool MediaRouterE2EBrowserTest::IsSinkDiscovered() const {
+ return ContainsKey(observer_->sink_map, receiver_);
+}
+
+bool MediaRouterE2EBrowserTest::IsRouteCreated() const {
+ return !route_id_.empty();
+}
+
+// Test cases
+
+IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest, MANUAL_TabMirroring) {
+ EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
+ EXPECT_EQ(1, browser()->tab_strip_model()->count());
+
+ ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
+ browser(), GURL("about:blank"), 1);
+ int tab_id = SessionTabHelper::IdForTab(
+ browser()->tab_strip_model()->GetActiveWebContents());
+
+ // Wait for 30 seconds to make sure the route is stable.
+ CreateMediaRoute(MediaSourceForTab(tab_id), GURL("http://origin/"), tab_id);
+ Wait(base::TimeDelta::FromSeconds(30));
+
+ // Wait for 10 seconds to make sure route has been stopped.
+ StopMediaRoute();
+ Wait(base::TimeDelta::FromSeconds(10));
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterE2EBrowserTest, MANUAL_CastApp) {
+ // Wait for 30 seconds to make sure the route is stable.
+ CreateMediaRoute(MediaSourceForPresentationUrl(kCastAppPresentationUrl),
+ GURL("http://origin/"), kInvalidTabId);
+ Wait(base::TimeDelta::FromSeconds(30));
+
+ // Wait for 10 seconds to make sure route has been stopped.
+ StopMediaRoute();
+ Wait(base::TimeDelta::FromSeconds(10));
+}
+
+} // namespace media_router
diff --git a/chrome/test/media_router/media_router_e2e_browsertest.h b/chrome/test/media_router/media_router_e2e_browsertest.h
new file mode 100644
index 0000000..e88f56c
--- /dev/null
+++ b/chrome/test/media_router/media_router_e2e_browsertest.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_E2E_BROWSERTEST_H_
+#define CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_E2E_BROWSERTEST_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "chrome/browser/media/router/media_route.h"
+#include "chrome/browser/media/router/media_router.h"
+#include "chrome/test/media_router/media_router_base_browsertest.h"
+#include "chrome/test/media_router/test_media_sinks_observer.h"
+
+namespace media_router {
+
+class MediaRouter;
+
+class MediaRouterE2EBrowserTest : public MediaRouterBaseBrowserTest {
+ public:
+ MediaRouterE2EBrowserTest();
+ ~MediaRouterE2EBrowserTest() override;
+
+ protected:
+ // InProcessBrowserTest Overrides
+ void SetUpOnMainThread() override;
+ void TearDownOnMainThread() override;
+
+ // MediaRouterBaseBrowserTest Overrides
+ void ParseCommandLine() override;
+
+ // Callback from MediaRouter when a response to a media route request is
+ // received.
+ void OnRouteResponseReceived(scoped_ptr<MediaRoute> route,
+ const std::string& error);
+
+ // Initializes |observer_| to listen for sinks compatible with |source|,
+ // finds sink with name matching receiver_, and establishes media
+ // route between the source and sink.
+ // |observer_| and |route_id_| will be initialized.
+ // |origin| is the URL of requestor's page.
+ // |tab_id| is the ID of the tab in which the request was made.
+ // |origin| and |tab_id| are used for enforcing same-origin and/or same-tab
+ // scope for JoinRoute() requests. (e.g., if enforced, the page
+ // requesting JoinRoute() must have the same origin as the page that requested
+ // CreateRoute()).
+ void CreateMediaRoute(const MediaSource& source,
+ const GURL& origin,
+ int tab_id);
+
+ // Stops the established media route and unregisters |observer_|.
+ // Note that the route may not be stopped immediately, as it makes an
+ // async call to the Media Route Provider.
+ // |observer_| and |route_id_| will be reset.
+ void StopMediaRoute();
+
+ std::string receiver() const { return receiver_; }
+
+ bool IsSinkDiscovered() const;
+ bool IsRouteCreated() const;
+
+ private:
+ std::string receiver_;
+
+ MediaRouter* media_router_;
+ scoped_ptr<TestMediaSinksObserver> observer_;
+ MediaRoute::Id route_id_;
+};
+
+} // namespace media_router
+
+#endif // CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_E2E_BROWSERTEST_H_
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
new file mode 100644
index 0000000..9e5ddea
--- /dev/null
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -0,0 +1,97 @@
+// 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 "chrome/test/media_router/media_router_integration_browsertest.h"
+
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/path_service.h"
+#include "base/strings/stringprintf.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/browser/ui/webui/media_router/media_router_dialog_controller.h"
+#include "chrome/test/base/ui_test_utils.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/test_navigation_observer.h"
+#include "content/public/test/test_utils.h"
+#include "net/base/filename_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace media_router {
+
+MediaRouterIntegrationBrowserTest::MediaRouterIntegrationBrowserTest() {
+}
+
+MediaRouterIntegrationBrowserTest::~MediaRouterIntegrationBrowserTest() {
+}
+
+void MediaRouterIntegrationBrowserTest::ExecuteJavaScriptAPI(
+ content::WebContents* web_contents,
+ const std::string& script) {
+ std::string result;
+
+ ASSERT_TRUE(
+ content::ExecuteScriptAndExtractString(web_contents, script, &result));
+
+ // Read the test result, the test result set by javascript is a
+ // JSON string with the following format:
+ // {"passed": "<true/false>", "errorMessage": "<error_message>"}
+ scoped_ptr<base::Value> value =
+ base::JSONReader::Read(result, base::JSON_ALLOW_TRAILING_COMMAS);
+
+ // Convert to dictionary.
+ base::DictionaryValue* dict_value = nullptr;
+ ASSERT_TRUE(value->GetAsDictionary(&dict_value));
+
+ // Extract the fields.
+ bool passed = false;
+ ASSERT_TRUE(dict_value->GetBoolean("passed", &passed));
+ std::string error_message;
+ ASSERT_TRUE(dict_value->GetString("errorMessage", &error_message));
+
+ EXPECT_TRUE(passed) << error_message;
+}
+
+void MediaRouterIntegrationBrowserTest::OpenTestPage(
+ base::FilePath::StringPieceType file_name) {
+ base::FilePath base_dir;
+ ASSERT_TRUE(PathService::Get(base::DIR_EXE, &base_dir));
+ base::FilePath full_path =
+ base_dir.Append(FILE_PATH_LITERAL("media_router/browser_test_resources/"))
+ .Append(file_name);
+ ASSERT_TRUE(PathExists(full_path));
+ ui_test_utils::NavigateToURL(browser(), net::FilePathToFileURL(full_path));
+}
+
+void MediaRouterIntegrationBrowserTest::ChooseSink(
+ content::WebContents* web_contents,
+ const std::string& sink_id) {
+ MediaRouterDialogController* controller =
+ MediaRouterDialogController::GetOrCreateForWebContents(web_contents);
+ content::WebContents* dialog_contents = controller->GetMediaRouterDialog();
+ ASSERT_TRUE(dialog_contents);
+ std::string script = base::StringPrintf(
+ "window.document.getElementById('media-router-container')."
+ "showOrCreateRoute_({'id': '%s', 'name': ''}, null)",
+ sink_id.c_str());
+ ASSERT_TRUE(content::ExecuteScript(dialog_contents, script));
+}
+
+IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest, MANUAL_Basic) {
+ OpenTestPage(FILE_PATH_LITERAL("basic_test.html"));
+ content::WebContents* web_contents =
+ browser()->tab_strip_model()->GetActiveWebContents();
+ ASSERT_TRUE(web_contents);
+ content::TestNavigationObserver test_navigation_observer(web_contents, 1);
+ test_navigation_observer.StartWatchingNewWebContents();
+ ExecuteJavaScriptAPI(web_contents, "startSession();");
+ test_navigation_observer.Wait();
+ ChooseSink(web_contents, "id1");
+ ExecuteJavaScriptAPI(web_contents, "checkSession();");
+ Wait(base::TimeDelta::FromSeconds(5));
+ ExecuteJavaScriptAPI(web_contents, "stopSession();");
+}
+
+} // namespace media_router
diff --git a/chrome/test/media_router/media_router_integration_browsertest.h b/chrome/test/media_router/media_router_integration_browsertest.h
new file mode 100644
index 0000000..23c2a5f
--- /dev/null
+++ b/chrome/test/media_router/media_router_integration_browsertest.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_INTEGRATION_BROWSERTEST_H_
+#define CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_INTEGRATION_BROWSERTEST_H_
+
+#include <string>
+
+#include "base/debug/stack_trace.h"
+#include "base/files/file_path.h"
+#include "chrome/test/media_router/media_router_base_browsertest.h"
+
+namespace media_router {
+
+class MediaRouter;
+
+class MediaRouterIntegrationBrowserTest : public MediaRouterBaseBrowserTest {
+ public:
+ MediaRouterIntegrationBrowserTest();
+ ~MediaRouterIntegrationBrowserTest() override;
+
+ protected:
+ // Simulate user action to choose one sink in the popup dialog.
+ // |web_contents|: The web contents of the test page which invokes the popup
+ // dialog.
+ // |sink_id|: The sink id.
+ void ChooseSink(content::WebContents* web_contents,
+ const std::string& sink_id);
+
+ // Execute javascript and check the return value.
+ void ExecuteJavaScriptAPI(content::WebContents* web_contents,
+ const std::string& script);
+
+ void OpenTestPage(base::FilePath::StringPieceType file);
+};
+
+} // namespace media_router
+
+#endif // CHROME_TEST_MEDIA_ROUTER_MEDIA_ROUTER_INTEGRATION_BROWSERTEST_H_
diff --git a/chrome/test/media_router/media_router_tests.gypi b/chrome/test/media_router/media_router_tests.gypi
new file mode 100644
index 0000000..c46a9e8
--- /dev/null
+++ b/chrome/test/media_router/media_router_tests.gypi
@@ -0,0 +1,32 @@
+# 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.
+
+{
+ 'variables': {
+ 'media_router_integration_test_resources': [
+ 'resources/basic_test.html',
+ 'resources/common.js'
+ ],
+ }, # end of variables
+ 'targets': [
+ {
+ 'target_name': 'media_router_integration_test_files',
+ 'type': 'none',
+ 'variables': {
+ 'output_dir': '<(PRODUCT_DIR)/media_router/browser_test_resources',
+ 'resource_files': [
+ '<@(media_router_integration_test_resources)',
+ ]
+ },
+ 'copies': [
+ {
+ 'destination': '<(output_dir)',
+ 'files': [
+ '<@(resource_files)',
+ ],
+ },
+ ],
+ }, # end of target 'media_router_integration_test_files'
+ ], # end of targets
+} \ No newline at end of file
diff --git a/chrome/test/media_router/media_router_tests.isolate b/chrome/test/media_router/media_router_tests.isolate
new file mode 100644
index 0000000..8759728
--- /dev/null
+++ b/chrome/test/media_router/media_router_tests.isolate
@@ -0,0 +1,46 @@
+# Copyright (c) 2014 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.
+{
+ 'conditions': [
+ ['OS=="linux"', {
+ 'variables': {
+ 'command': [
+ 'media_router_tests.py',
+ '--extension',
+ '<(PRODUCT_DIR)/mr_extension/',
+ '--prod_dir',
+ '<(PRODUCT_DIR)',
+ ],
+ 'files': [
+ 'media_router_tests.py',
+ '<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)',
+ '<(PRODUCT_DIR)/chrome_100_percent.pak',
+ '<(PRODUCT_DIR)/chrome_200_percent.pak',
+ '<(PRODUCT_DIR)/libosmesa.so',
+ '<(PRODUCT_DIR)/locales/en-US.pak',
+ '<(PRODUCT_DIR)/mr_extension/',
+ '<(PRODUCT_DIR)/nacl_helper',
+ '<(PRODUCT_DIR)/nacl_helper_bootstrap',
+ '<(PRODUCT_DIR)/nacl_irt_x86_64.nexe',
+ '<(PRODUCT_DIR)/natives_blob.bin',
+ '<(PRODUCT_DIR)/pnacl/',
+ '<(PRODUCT_DIR)/resources.pak',
+ '<(PRODUCT_DIR)/snapshot_blob.bin',
+ '<(PRODUCT_DIR)/xdisplaycheck<(EXECUTABLE_SUFFIX)',
+ ],
+ },
+ }],
+ ['OS=="linux" and component=="shared_library"', {
+ 'variables': {
+ 'files': [
+ '<(PRODUCT_DIR)/lib/',
+ '<(PRODUCT_DIR)/lib64/',
+ ],
+ },
+ }],
+ ],
+ 'includes': [
+ '../../../base/base.isolate',
+ ],
+} \ No newline at end of file
diff --git a/chrome/test/media_router/resources/basic_test.html b/chrome/test/media_router/resources/basic_test.html
new file mode 100644
index 0000000..7d4666f
--- /dev/null
+++ b/chrome/test/media_router/resources/basic_test.html
@@ -0,0 +1,10 @@
+<!DOCTYPE HTML>
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <title>MR Integration Basic Test</title>
+ <link href="https://www.google.com/cast?__testprovider__=true" rel="default-presentation">
+ <script type="text/javascript" src="common.js"></script>
+ </head>
+ <body>
+ </body>
+</html> \ No newline at end of file
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js
new file mode 100644
index 0000000..c03ed2c
--- /dev/null
+++ b/chrome/test/media_router/resources/common.js
@@ -0,0 +1,79 @@
+/**
+ * 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.
+ *
+ * @fileoverview Common APIs for presentation integration tests.
+ *
+ */
+
+var startSessionPromise = null;
+var currentSession = null;
+var presentation = window.navigator.presentation;
+
+
+/**
+ * Waits until one device is available then starts session.
+ */
+function startSession() {
+ presentation.onavailablechange = function (e) {
+ console.log('onavailablechange ' + e.available + '\n');
+ if (!e.available) {
+ sendResult(false, 'device unavailable');
+ } else {
+ var presId = Math.random().toFixed(6).substr(2);
+ // Start new session
+ startSessionPromise = presentation.startSession(
+ "http://www.google.com/#__testprovider__=true", presId)
+ sendResult(true, '');
+ }
+ };
+}
+
+/**
+ * Checks if the session has been started successfully.
+ */
+function checkSession() {
+ if (!startSessionPromise) {
+ sendResult(false, 'Failed to start session');
+ } else {
+ startSessionPromise.then(function (currentSession) {
+ if(!currentSession) {
+ sendResult(false, 'Failed to start session');
+ } else {
+ // set the new session
+ currentSession = currentSession;
+ sendResult(true, '');
+ }
+ }).catch(function() {
+ // close old session if exists
+ currentSession && currentSession.close();
+ sendResult(false, 'Failed to start session');
+ })
+ }
+}
+
+
+/**
+ * Stops current session.
+ */
+function stopSession() {
+ if (currentSession) {
+ currentSession.close();
+ }
+ sendResult(true, '');
+}
+
+
+/**
+ * Sends the test result back to browser test.
+ * @param passed true if test passes, otherwise false.
+ * @param errorMessage empty string if test passes, error message if test
+ * fails.
+ */
+function sendResult(passed, errorMessage) {
+ window.domAutomationController.send(JSON.stringify({
+ passed: passed,
+ errorMessage: errorMessage
+ }));
+} \ No newline at end of file
diff --git a/chrome/test/media_router/test_media_sinks_observer.cc b/chrome/test/media_router/test_media_sinks_observer.cc
new file mode 100644
index 0000000..c4a9fce
--- /dev/null
+++ b/chrome/test/media_router/test_media_sinks_observer.cc
@@ -0,0 +1,29 @@
+// 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 <utility>
+
+#include "chrome/browser/media/router/media_router.h"
+#include "chrome/test/media_router/test_media_sinks_observer.h"
+
+namespace media_router {
+
+TestMediaSinksObserver::TestMediaSinksObserver(MediaRouter* router,
+ const MediaSource& source)
+ : MediaSinksObserver(router, source) {
+}
+
+TestMediaSinksObserver::~TestMediaSinksObserver() {
+}
+
+void TestMediaSinksObserver::OnSinksReceived(
+ const std::vector<MediaSink>& result) {
+ sink_map.clear();
+ for (const MediaSink& sink : result) {
+ sink_map.insert(std::make_pair(sink.name(), sink));
+ }
+}
+
+} // namespace media_router
diff --git a/chrome/test/media_router/test_media_sinks_observer.h b/chrome/test/media_router/test_media_sinks_observer.h
new file mode 100644
index 0000000..d4607d8
--- /dev/null
+++ b/chrome/test/media_router/test_media_sinks_observer.h
@@ -0,0 +1,34 @@
+// 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 <map>
+#include <string>
+#include <vector>
+
+#include "chrome/browser/media/router/media_sinks_observer.h"
+
+#ifndef CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_
+#define CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_
+
+namespace media_router {
+
+class MediaRouter;
+
+// Test class to implement MediaSinksObserver that receives SinkQueryResults
+// from Media Router and is used for verification.
+class TestMediaSinksObserver : public MediaSinksObserver {
+ public:
+ TestMediaSinksObserver(MediaRouter* router, const MediaSource& source);
+ ~TestMediaSinksObserver() override;
+
+ // MediaSinksObserver implementation.
+ void OnSinksReceived(const std::vector<MediaSink>& result) override;
+
+ // Map of <sink_name, media_sink_object>
+ std::map<std::string, const MediaSink> sink_map;
+};
+
+} // namespace media_router
+
+#endif // CHROME_TEST_MEDIA_ROUTER_TEST_MEDIA_SINKS_OBSERVER_H_