blob: 4721e54e051d11dbc7ea4588f75490cdc1282bb5 [file] [log] [blame]
// Copyright (c) 2013 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 "base/command_line.h"
#include "base/path_service.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_browsertest.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.cc"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_file_util.h"
#include "chrome/common/extensions/manifest.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
using extensions::Extension;
namespace {
// Command line arguments specific to the chromoting browser tests.
const char kOverrideUserDataDir[] = "override-user-data-dir";
const char kNoCleanup[] = "no-cleanup";
const char kNoInstall[] = "no-install";
const char kWebAppCrx[] = "webapp-crx";
}
namespace remoting {
class RemoteDesktopBrowserTest : public ExtensionBrowserTest {
public:
virtual void SetUp() OVERRIDE {
ParseCommandLine();
ExtensionBrowserTest::SetUp();
}
protected:
// Override InProcessBrowserTest. Change behavior of the default host
// resolver to avoid DNS lookup errors, so we can make network calls.
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
// The resolver object lifetime is managed by sync_test_setup, not here.
EnableDNSLookupForThisTest(
new net::RuleBasedHostResolverProc(host_resolver()));
}
// Override InProcessBrowserTest.
virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
DisableDNSLookupForThisTest();
}
// Install the chromoting extension from a crx file.
void InstallChromotingApp();
// Uninstall the chromoting extension.
void UninstallChromotingApp();
// Test whether the chromoting extension is installed.
void VerifyChromotingLoaded(bool expected);
// Launch the chromoting app.
void LaunchChromotingApp();
// Verify the test has access to the internet (specifically google.com)
void VerifyInternetAccess();
void Authorize();
// Whether to perform the cleanup tasks (uninstalling chromoting, etc).
// This is useful for diagnostic purposes.
bool NoCleanup() { return no_cleanup_; }
// Whether to install the chromoting extension before running the test cases.
// This is useful for diagnostic purposes.
bool NoInstall() { return no_install_; }
private:
void ParseCommandLine();
// Change behavior of the default host resolver to allow DNS lookup
// to proceed instead of being blocked by the test infrastructure.
void EnableDNSLookupForThisTest(
net::RuleBasedHostResolverProc* host_resolver);
// We need to reset the DNS lookup when we finish, or the test will fail.
void DisableDNSLookupForThisTest();
// Helper to get the path to the crx file of the webapp to be tested.
base::FilePath WebAppCrxPath() { return webapp_crx_; }
// Helper to get the extension ID of the installed chromoting webapp.
std::string ChromotingID() { return chromoting_id_; }
// Helper to retrieve the current URL of the active tab in the browser.
GURL GetCurrentURL() {
return browser()->tab_strip_model()->GetActiveWebContents()->GetURL();
}
// This test needs to make live DNS requests for access to
// GAIA and sync server URLs under google.com. We use a scoped version
// to override the default resolver while the test is active.
scoped_ptr<net::ScopedDefaultHostResolverProc> mock_host_resolver_override_;
bool no_cleanup_;
bool no_install_;
std::string chromoting_id_;
base::FilePath webapp_crx_;
};
void RemoteDesktopBrowserTest::ParseCommandLine() {
CommandLine* command_line = CommandLine::ForCurrentProcess();
// The test framework overrides any command line user-data-dir
// argument with a /tmp/.org.chromium.Chromium.XXXXXX directory.
// That happens in the ChromeTestLauncherDelegate, and affects
// all unit tests (no opt out available). It intentionally erases
// any --user-data-dir switch if present and appends a new one.
// Re-override the default data dir if override-user-data-dir
// is specified.
if (command_line->HasSwitch(kOverrideUserDataDir)) {
const base::FilePath& override_user_data_dir =
command_line->GetSwitchValuePath(kOverrideUserDataDir);
ASSERT_FALSE(override_user_data_dir.empty());
command_line->AppendSwitchPath(switches::kUserDataDir,
override_user_data_dir);
}
no_cleanup_ = command_line->HasSwitch(kNoCleanup);
no_install_ = command_line->HasSwitch(kNoInstall);
if (!no_install_) {
webapp_crx_ = command_line->GetSwitchValuePath(kWebAppCrx);
ASSERT_FALSE(webapp_crx_.empty());
}
}
void RemoteDesktopBrowserTest::EnableDNSLookupForThisTest(
net::RuleBasedHostResolverProc* host_resolver) {
// mock_host_resolver_override_ takes ownership of the resolver.
scoped_refptr<net::RuleBasedHostResolverProc> resolver =
new net::RuleBasedHostResolverProc(host_resolver);
resolver->AllowDirectLookup("*.google.com");
// On Linux, we use Chromium's NSS implementation which uses the following
// hosts for certificate verification. Without these overrides, running the
// integration tests on Linux causes errors as we make external DNS lookups.
resolver->AllowDirectLookup("*.thawte.com");
resolver->AllowDirectLookup("*.geotrust.com");
resolver->AllowDirectLookup("*.gstatic.com");
resolver->AllowDirectLookup("*.googleapis.com");
mock_host_resolver_override_.reset(
new net::ScopedDefaultHostResolverProc(resolver.get()));
}
void RemoteDesktopBrowserTest::DisableDNSLookupForThisTest() {
mock_host_resolver_override_.reset();
}
void RemoteDesktopBrowserTest::VerifyInternetAccess() {
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<content::NavigationController>(
&browser()->tab_strip_model()->GetActiveWebContents()->
GetController()));
GURL google_url("http://www.google.com");
ui_test_utils::NavigateToURL(browser(), google_url);
observer.Wait();
EXPECT_EQ(GetCurrentURL().host(), "www.google.com");
}
void RemoteDesktopBrowserTest::InstallChromotingApp() {
base::FilePath install_dir(WebAppCrxPath());
scoped_refptr<const Extension> extension(InstallExtensionWithUIAutoConfirm(
install_dir, 1, browser()));
EXPECT_FALSE(extension.get() == NULL);
}
void RemoteDesktopBrowserTest::UninstallChromotingApp() {
UninstallExtension(ChromotingID());
chromoting_id_.clear();
}
void RemoteDesktopBrowserTest::LaunchChromotingApp() {
ASSERT_FALSE(ChromotingID().empty());
std::string url = "chrome-extension://" + ChromotingID() + "/main.html";
const GURL chromoting_main(url);
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<content::NavigationController>(
&browser()->tab_strip_model()->GetActiveWebContents()->
GetController()));
ui_test_utils::NavigateToURL(browser(), chromoting_main);
observer.Wait();
EXPECT_EQ(GetCurrentURL(), chromoting_main);
}
void RemoteDesktopBrowserTest::VerifyChromotingLoaded(bool expected) {
const ExtensionSet* extensions = extension_service()->extensions();
scoped_refptr<const extensions::Extension> extension;
ExtensionSet::const_iterator iter;
bool installed = false;
for (iter = extensions->begin(); iter != extensions->end(); ++iter) {
extension = *iter;
// Is there a better way to recognize the chromoting extension
// than name comparison?
if (extension->name() == "Chromoting" ||
extension->name() == "Chrome Remote Desktop") {
installed = true;
break;
}
}
if (installed) {
chromoting_id_ = extension->id();
EXPECT_EQ(extension->GetType(),
extensions::Manifest::TYPE_LEGACY_PACKAGED_APP);
EXPECT_TRUE(extension->ShouldDisplayInAppLauncher());
}
EXPECT_EQ(installed, expected);
}
void RemoteDesktopBrowserTest::Authorize() {
// The chromoting extension should be installed.
ASSERT_FALSE(ChromotingID().empty());
// The chromoting main page should be loaded in the current tab
// and isAuthenticated() should be false (auth dialog visible).
std::string url = "chrome-extension://" + ChromotingID() + "/main.html";
ASSERT_EQ(GetCurrentURL().spec(), url);
bool result;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
browser()->tab_strip_model()->GetActiveWebContents(),
"window.domAutomationController.send("
"remoting.OAuth2.prototype.isAuthenticated());",
&result));
EXPECT_FALSE(result);
content::WindowedNotificationObserver observer(
content::NOTIFICATION_LOAD_STOP,
content::Source<content::NavigationController>(
&browser()->tab_strip_model()->GetActiveWebContents()->
GetController()));
ASSERT_TRUE(content::ExecuteScript(
browser()->tab_strip_model()->GetActiveWebContents(),
"remoting.OAuth2.prototype.doAuthRedirect()"));
observer.Wait();
// Verify the active tab is at the "Google Accounts" login page.
EXPECT_EQ(GetCurrentURL().host(), "accounts.google.com");
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
browser()->tab_strip_model()->GetActiveWebContents(),
"window.domAutomationController.send("
"document.getElementById(\"Email\") != null);",
&result));
EXPECT_TRUE(result);
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
browser()->tab_strip_model()->GetActiveWebContents(),
"window.domAutomationController.send("
"document.getElementById(\"Passwd\") != null);",
&result));
EXPECT_TRUE(result);
}
IN_PROC_BROWSER_TEST_F(RemoteDesktopBrowserTest, MANUAL_Launch) {
VerifyInternetAccess();
if (!NoInstall()) {
VerifyChromotingLoaded(false);
InstallChromotingApp();
}
VerifyChromotingLoaded(true);
LaunchChromotingApp();
// TODO: Remove this hack by blocking on the appropriate notification.
// The browser may still be loading images embedded in the webapp. If we
// uinstall it now those load will fail. Navigating away to avoid the load
// failures.
ui_test_utils::NavigateToURL(browser(), GURL("about:blank"));
if (!NoCleanup()) {
UninstallChromotingApp();
VerifyChromotingLoaded(false);
}
}
IN_PROC_BROWSER_TEST_F(RemoteDesktopBrowserTest, MANUAL_Auth) {
VerifyInternetAccess();
if (!NoInstall()) {
VerifyChromotingLoaded(false);
InstallChromotingApp();
}
VerifyChromotingLoaded(true);
LaunchChromotingApp();
Authorize();
if (!NoCleanup()) {
UninstallChromotingApp();
VerifyChromotingLoaded(false);
}
}
} // namespace remoting