summaryrefslogtreecommitdiff
path: root/chrome/test
diff options
context:
space:
mode:
authorTorne (Richard Coles) <torne@google.com>2013-08-30 15:14:49 +0100
committerTorne (Richard Coles) <torne@google.com>2013-08-30 15:14:49 +0100
commit424c4d7b64af9d0d8fd9624f381f469654d5e3d2 (patch)
treeaf8b16dc2ba7fc8c8bb1c9fa18b907c847f3883d /chrome/test
parentc70ef2906f891fe7d218980660e4cda465717916 (diff)
downloadchromium_org-424c4d7b64af9d0d8fd9624f381f469654d5e3d2.tar.gz
Merge from Chromium at DEPS revision r220549
This commit was generated by merge_to_master.py. Change-Id: I8fcb82db764ec1eb0294280936c177bd9ba8a9e9
Diffstat (limited to 'chrome/test')
-rw-r--r--chrome/test/android/OWNERS6
-rw-r--r--chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java112
-rw-r--r--chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java68
-rw-r--r--chrome/test/base/test_browser_window.cc5
-rw-r--r--chrome/test/base/test_browser_window.h1
-rw-r--r--chrome/test/base/test_location_bar.h3
-rw-r--r--chrome/test/base/testing_pref_service_syncable.cc5
-rw-r--r--chrome/test/chromedriver/alert_commands.cc4
-rw-r--r--chrome/test/chromedriver/capabilities.cc208
-rw-r--r--chrome/test/chromedriver/capabilities.h11
-rw-r--r--chrome/test/chromedriver/capabilities_unittest.cc12
-rw-r--r--chrome/test/chromedriver/chrome/automation_extension.cc16
-rw-r--r--chrome/test/chromedriver/chrome/automation_extension.h5
-rw-r--r--chrome/test/chromedriver/chrome/chrome.h11
-rw-r--r--chrome/test/chromedriver/chrome/chrome_android_impl.cc4
-rw-r--r--chrome/test/chromedriver/chrome/chrome_android_impl.h1
-rw-r--r--chrome/test/chromedriver/chrome/chrome_desktop_impl.cc78
-rw-r--r--chrome/test/chromedriver/chrome/chrome_desktop_impl.h13
-rw-r--r--chrome/test/chromedriver/chrome/chrome_existing_impl.cc28
-rw-r--r--chrome/test/chromedriver/chrome/chrome_existing_impl.h30
-rw-r--r--chrome/test/chromedriver/chrome/chrome_finder.cc14
-rw-r--r--chrome/test/chromedriver/chrome/chrome_impl.cc4
-rw-r--r--chrome/test/chromedriver/chrome/chrome_impl.h1
-rw-r--r--chrome/test/chromedriver/chrome/devtools_client.h4
-rw-r--r--chrome/test/chromedriver/chrome/devtools_client_impl.cc43
-rw-r--r--chrome/test/chromedriver/chrome/devtools_client_impl.h2
-rw-r--r--chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc2
-rw-r--r--chrome/test/chromedriver/chrome/devtools_http_client.cc16
-rw-r--r--chrome/test/chromedriver/chrome/devtools_http_client.h5
-rw-r--r--chrome/test/chromedriver/chrome/stub_chrome.cc8
-rw-r--r--chrome/test/chromedriver/chrome/stub_chrome.h2
-rw-r--r--chrome/test/chromedriver/chrome/stub_web_view.cc3
-rw-r--r--chrome/test/chromedriver/chrome/stub_web_view.h3
-rw-r--r--chrome/test/chromedriver/chrome/web_view.h12
-rw-r--r--chrome/test/chromedriver/chrome/web_view_impl.cc10
-rw-r--r--chrome/test/chromedriver/chrome/web_view_impl.h3
-rw-r--r--chrome/test/chromedriver/chrome_launcher.cc249
-rw-r--r--chrome/test/chromedriver/chrome_launcher.h4
-rw-r--r--chrome/test/chromedriver/chrome_launcher_unittest.cc71
-rw-r--r--chrome/test/chromedriver/client/chromedriver.py16
-rw-r--r--chrome/test/chromedriver/commands.cc6
-rw-r--r--chrome/test/chromedriver/commands_unittest.cc10
-rw-r--r--chrome/test/chromedriver/element_commands.cc3
-rw-r--r--chrome/test/chromedriver/element_util.cc3
-rw-r--r--chrome/test/chromedriver/extension/background.js50
-rw-r--r--chrome/test/chromedriver/extension/manifest.json2
-rw-r--r--chrome/test/chromedriver/js/execute_async_script.js6
-rw-r--r--chrome/test/chromedriver/js/execute_async_script_test.html4
-rw-r--r--chrome/test/chromedriver/keycode_text_conversion_win.cc4
-rw-r--r--chrome/test/chromedriver/net/net_util.cc28
-rw-r--r--chrome/test/chromedriver/net/net_util.h20
-rw-r--r--chrome/test/chromedriver/net/sync_websocket_impl.cc10
-rw-r--r--chrome/test/chromedriver/net/websocket.cc59
-rwxr-xr-xchrome/test/chromedriver/run_buildbot_steps.py65
-rw-r--r--chrome/test/chromedriver/session.cc17
-rw-r--r--chrome/test/chromedriver/session.h10
-rw-r--r--chrome/test/chromedriver/session_commands.cc25
-rwxr-xr-xchrome/test/chromedriver/test/run_all_tests.py15
-rwxr-xr-xchrome/test/chromedriver/test/run_py_tests.py60
-rw-r--r--chrome/test/chromedriver/test/webserver.py1
-rw-r--r--chrome/test/chromedriver/util.cc4
-rw-r--r--chrome/test/chromedriver/window_commands.cc32
-rw-r--r--chrome/test/functional/PYAUTO_TESTS34
-rwxr-xr-xchrome/test/functional/chromeos_cellular_sanity.py31
-rw-r--r--chrome/test/functional/chromeos_device_policy.py216
-rw-r--r--chrome/test/functional/chromeos_ephemeral.py172
-rwxr-xr-xchrome/test/functional/chromeos_gsm_compliance.py110
-rwxr-xr-xchrome/test/functional/chromeos_login.py371
-rwxr-xr-xchrome/test/functional/chromeos_offline.py30
-rwxr-xr-xchrome/test/functional/chromeos_onc.py144
-rwxr-xr-xchrome/test/functional/chromeos_oobe.py74
-rw-r--r--chrome/test/functional/chromeos_retail_mode.py51
-rwxr-xr-xchrome/test/functional/chromeos_txt_msg_functional.py161
-rwxr-xr-xchrome/test/functional/chromeos_vpn.py74
-rwxr-xr-xchrome/test/functional/chromeos_wifi_compliance.py110
-rwxr-xr-xchrome/test/functional/chromeos_wifi_functional.py191
-rwxr-xr-xchrome/test/functional/webpagereplay.py50
-rwxr-xr-xchrome/test/functional/wifi_downloads.py201
-rwxr-xr-xchrome/test/functional/wifi_notification.py92
-rw-r--r--chrome/test/mini_installer/chrome_helper.py82
-rw-r--r--chrome/test/mini_installer/config/chrome_installed.prop16
-rw-r--r--chrome/test/mini_installer/config/chrome_inuse.prop5
-rw-r--r--chrome/test/mini_installer/config/chrome_not_installed.prop5
-rw-r--r--chrome/test/mini_installer/config/chrome_not_inuse.prop5
-rw-r--r--chrome/test/mini_installer/config/config.config20
-rw-r--r--chrome/test/mini_installer/launch_chrome.py50
-rw-r--r--chrome/test/mini_installer/path_resolver.py52
-rw-r--r--chrome/test/mini_installer/process_verifier.py36
-rw-r--r--chrome/test/mini_installer/quit_chrome.py54
-rw-r--r--chrome/test/mini_installer/registry_verifier.py91
-rw-r--r--chrome/test/mini_installer/test_installer.py17
-rw-r--r--chrome/test/mini_installer/uninstall_chrome.py22
-rw-r--r--chrome/test/mini_installer/verifier.py3
-rw-r--r--chrome/test/perf/feature_startup_test.cc2
-rw-r--r--chrome/test/perf/rendering/throughput_tests.cc4
-rw-r--r--chrome/test/perf/url_parse_perftest.cc6
-rw-r--r--chrome/test/ppapi/ppapi_browsertest.cc28
-rw-r--r--chrome/test/pyautolib/chromeos_network.py180
-rwxr-xr-xchrome/test/pyautolib/pyauto.py360
-rw-r--r--chrome/test/telemetry/chromeos/login_unittest.py13
100 files changed, 1649 insertions, 3041 deletions
diff --git a/chrome/test/android/OWNERS b/chrome/test/android/OWNERS
new file mode 100644
index 0000000000..a223621c02
--- /dev/null
+++ b/chrome/test/android/OWNERS
@@ -0,0 +1,6 @@
+aruslan@chromium.org
+bulach@chromium.org
+dtrainor@chromium.org
+nyquist@chromium.org
+tedchoc@chromium.org
+yfriedman@chromium.org
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java
new file mode 100644
index 0000000000..06fd89e865
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationData.java
@@ -0,0 +1,112 @@
+// Copyright 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.
+
+package org.chromium.chrome.test.util;
+
+import android.content.Context;
+
+import org.chromium.content.browser.test.util.Criteria;
+import org.chromium.content.browser.test.util.CriteriaHelper;
+
+import java.io.File;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A utility class to do operations on the application data directory, such as clearing the
+ * application data.
+ */
+public final class ApplicationData {
+
+ private static final long MAX_CLEAR_APP_DATA_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(3);
+ private static final long CLEAR_APP_DATA_POLL_INTERVAL_MS = MAX_CLEAR_APP_DATA_TIMEOUT_MS / 10;
+
+ private ApplicationData() {}
+
+ /**
+ * Clear all files in target contexts application directory, except the directory 'lib'.
+ * The timeout is specified in |MAX_CLEAR_APP_DATA_TIMEOUT_MS|.
+ *
+ * When deleting all files is complete, the 'cache' directory is recreated, to ensure that the
+ * framework does not try to create it for sandbox processes and fail.
+ *
+ * When this is invoked from tests, the target context from the instrumentation must be used.
+ *
+ * @param targetContext the target Context.
+ *
+ * @return Whether clearing the application data was successful.
+ */
+ public static boolean clearAppData(Context targetContext) throws InterruptedException {
+ final String appDir = getAppDirFromTargetContext(targetContext);
+ return CriteriaHelper.pollForCriteria(
+ new Criteria() {
+ private boolean mDataRemoved = false;
+
+ @Override
+ public boolean isSatisfied() {
+ if (!mDataRemoved && !removeAppData(appDir)) {
+ return false;
+ }
+ mDataRemoved = true;
+ // We have to make sure the cache directory still exists, as the framework
+ // will try to create it otherwise and will fail for sandbox processes with
+ // a NullPointerException.
+ File cacheDir = new File(appDir, "cache");
+ return cacheDir.exists() || cacheDir.mkdir();
+ }
+ },
+ MAX_CLEAR_APP_DATA_TIMEOUT_MS, CLEAR_APP_DATA_POLL_INTERVAL_MS);
+ }
+
+ /**
+ * Find the absolute path of the application data directory for the given target context.
+ *
+ * When this is invoked from tests, the target context from the instrumentation must be used.
+ *
+ * @param targetContext the target Context.
+ *
+ * @return the absolute path of the application data directory.
+ */
+ public static String getAppDirFromTargetContext(Context targetContext) {
+ String cacheDir = targetContext.getCacheDir().getAbsolutePath();
+ return cacheDir.substring(0, cacheDir.lastIndexOf('/'));
+ }
+
+ /**
+ * Remove all files and directories under the given application directory, except 'lib'.
+ *
+ * @param appDir the application directory to remove.
+ *
+ * @return whether removal succeeded.
+ */
+ private static boolean removeAppData(String appDir) {
+ File[] files = new File(appDir).listFiles();
+ if (files == null)
+ return true;
+ for (File file : files) {
+ if (!file.getAbsolutePath().endsWith("/lib") && !removeFile(file))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Remove the given file or directory.
+ *
+ * @param file the file or directory to remove.
+ *
+ * @return whether removal succeeded.
+ */
+ private static boolean removeFile(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ if (files == null)
+ return true;
+ for (File sub_file : files) {
+ if (!removeFile(sub_file))
+ return false;
+ }
+ }
+ return file.delete();
+ }
+}
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java
new file mode 100644
index 0000000000..5f7e70dff6
--- /dev/null
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/TestHttpServerClient.java
@@ -0,0 +1,68 @@
+// Copyright 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.
+
+package org.chromium.chrome.test.util;
+
+import junit.framework.Assert;
+
+import org.chromium.chrome.browser.util.StreamUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * A test utility class to get URLs that point to the test HTTP server, and to verify that it is up
+ * and giving expected responses to given URLs.
+ */
+public final class TestHttpServerClient {
+ private static final int SERVER_PORT = 8000;
+
+ private TestHttpServerClient() {
+ }
+
+ /**
+ * Construct a suitable URL for loading a test data file from the hosts' HTTP server.
+ *
+ * @param path path relative to the document root.
+ * @return an HTTP url.
+ */
+ public static String getUrl(String path) {
+ return "http://localhost:" + SERVER_PORT + "/" + path;
+ }
+
+ /**
+ * Establishes a connection with the test server at default URL and verifies that it is running.
+ */
+ public static void checkServerIsUp() {
+ checkServerIsUp(getUrl("chrome/test/data/android/ok.txt"), "OK Computer");
+ }
+
+ /**
+ * Establishes a connection with the test server at a given URL and verifies that it is running
+ * by making sure that the expected response is received.
+ */
+ public static void checkServerIsUp(String serverUrl, String expectedResponse) {
+ InputStream is = null;
+ try {
+ URL testUrl = new URL(serverUrl);
+ is = testUrl.openStream();
+ byte[] buffer = new byte[128];
+ int length = is.read(buffer);
+ Assert.assertNotSame("Failed to access test HTTP Server at URL: " + serverUrl,
+ -1, expectedResponse.length());
+ Assert.assertEquals("Failed to access test HTTP Server at URL: " + serverUrl,
+ expectedResponse, new String(buffer, 0, length).trim());
+ } catch (MalformedURLException e) {
+ Assert.fail(
+ "Failed to check test HTTP server at URL: " + serverUrl + ". Status: " + e);
+ } catch (IOException e) {
+ Assert.fail(
+ "Failed to check test HTTP server at URL: " + serverUrl + ". Status: " + e);
+ } finally {
+ StreamUtil.closeQuietly(is);
+ }
+ }
+}
diff --git a/chrome/test/base/test_browser_window.cc b/chrome/test/base/test_browser_window.cc
index 2b5f05ada4..ae158f8a17 100644
--- a/chrome/test/base/test_browser_window.cc
+++ b/chrome/test/base/test_browser_window.cc
@@ -138,6 +138,11 @@ web_modal::WebContentsModalDialogHost*
return NULL;
}
+int
+TestBrowserWindow::GetRenderViewHeightInsetWithDetachedBookmarkBar() {
+ return 0;
+}
+
namespace chrome {
namespace {
diff --git a/chrome/test/base/test_browser_window.h b/chrome/test/base/test_browser_window.h
index 40cff07126..347e2a30c1 100644
--- a/chrome/test/base/test_browser_window.h
+++ b/chrome/test/base/test_browser_window.h
@@ -140,6 +140,7 @@ class TestBrowserWindow : public BrowserWindow {
const gfx::Rect& rect,
const content::PasswordForm& form,
autofill::PasswordGenerator* generator) OVERRIDE {}
+ virtual int GetRenderViewHeightInsetWithDetachedBookmarkBar() OVERRIDE;
protected:
virtual void DestroyBrowser() OVERRIDE {}
diff --git a/chrome/test/base/test_location_bar.h b/chrome/test/base/test_location_bar.h
index 22ef364b71..11efa96328 100644
--- a/chrome/test/base/test_location_bar.h
+++ b/chrome/test/base/test_location_bar.h
@@ -26,7 +26,7 @@ class TestLocationBar : public LocationBar {
transition_ = transition;
}
- // Overridden from LocationBar:
+ // LocationBar:
virtual void ShowFirstRunBubble() OVERRIDE {}
virtual string16 GetInputString() const OVERRIDE;
virtual WindowOpenDisposition GetWindowOpenDisposition() const OVERRIDE;
@@ -46,7 +46,6 @@ class TestLocationBar : public LocationBar {
virtual LocationBarTesting* GetLocationBarForTesting() OVERRIDE;
private:
-
// Test-supplied values that will be returned through the LocationBar
// interface.
string16 input_string_;
diff --git a/chrome/test/base/testing_pref_service_syncable.cc b/chrome/test/base/testing_pref_service_syncable.cc
index 3addba32ac..4d012e9e6c 100644
--- a/chrome/test/base/testing_pref_service_syncable.cc
+++ b/chrome/test/base/testing_pref_service_syncable.cc
@@ -20,8 +20,9 @@ TestingPrefServiceBase<PrefServiceSyncable, user_prefs::PrefRegistrySyncable>::
: PrefServiceSyncable(
pref_notifier,
new PrefValueStore(managed_prefs,
- NULL,
- NULL,
+ NULL, // supervised_user_prefs
+ NULL, // extension_prefs
+ NULL, // command_line_prefs
user_prefs,
recommended_prefs,
pref_registry->defaults().get(),
diff --git a/chrome/test/chromedriver/alert_commands.cc b/chrome/test/chromedriver/alert_commands.cc
index 85836b9a3f..de7118d572 100644
--- a/chrome/test/chromedriver/alert_commands.cc
+++ b/chrome/test/chromedriver/alert_commands.cc
@@ -31,8 +31,8 @@ Status ExecuteAlertCommand(
if (status.IsError())
return status;
- status = web_view->WaitForPendingNavigations(session->GetCurrentFrameId(),
- session->page_load_timeout);
+ status = web_view->WaitForPendingNavigations(
+ session->GetCurrentFrameId(), session->page_load_timeout, true);
if (status.IsError() && status.code() != kUnexpectedAlertOpen)
return status;
diff --git a/chrome/test/chromedriver/capabilities.cc b/chrome/test/chromedriver/capabilities.cc
index b052f0f7f7..7444641064 100644
--- a/chrome/test/chromedriver/capabilities.cc
+++ b/chrome/test/chromedriver/capabilities.cc
@@ -8,21 +8,38 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/log.h"
#include "chrome/test/chromedriver/chrome/status.h"
+#include "net/base/net_util.h"
namespace {
typedef base::Callback<Status(const base::Value&, Capabilities*)> Parser;
-Status ParseDetach(
+Status ParseBoolean(
+ bool* to_set,
const base::Value& option,
Capabilities* capabilities) {
- if (!option.GetAsBoolean(&capabilities->detach))
- return Status(kUnknownError, "'detach' must be a boolean");
+ if (!option.GetAsBoolean(to_set))
+ return Status(kUnknownError, "value must be a boolean");
+ return Status(kOk);
+}
+
+Status ParseString(std::string* to_set,
+ const base::Value& option,
+ Capabilities* capabilities) {
+ std::string str;
+ if (!option.GetAsString(&str))
+ return Status(kUnknownError, "value must be a string");
+ if (str.empty())
+ return Status(kUnknownError, "value cannot be empty");
+ *to_set = str;
return Status(kOk);
}
@@ -37,6 +54,10 @@ Status IgnoreDeprecatedOption(
return Status(kOk);
}
+Status IgnoreCapability(const base::Value& option, Capabilities* capabilities) {
+ return Status(kOk);
+}
+
Status ParseChromeBinary(
const base::Value& option,
Capabilities* capabilities) {
@@ -198,7 +219,39 @@ Status ParseExcludeSwitches(const base::Value& option,
return Status(kOk);
}
-Status ParseDesktopChromeCapabilities(
+Status ParseUseExistingBrowser(const base::Value& option,
+ Capabilities* capabilities) {
+ std::string server_addr;
+ if (!option.GetAsString(&server_addr))
+ return Status(kUnknownError, "must be 'host:port'");
+
+ std::vector<std::string> values;
+ base::SplitString(server_addr, ':', &values);
+ if (values.size() != 2)
+ return Status(kUnknownError, "must be 'host:port'");
+
+ int port = 0;
+ base::StringToInt(values[1], &port);
+ if (port <= 0)
+ return Status(kUnknownError, "port must be >= 0");
+
+ capabilities->use_existing_browser = NetAddress(values[0], port);
+ return Status(kOk);
+}
+
+Status ParseLoggingPrefs(const base::Value& option,
+ Capabilities* capabilities) {
+ const base::DictionaryValue* logging_prefs_dict = NULL;
+ if (!option.GetAsDictionary(&logging_prefs_dict))
+ return Status(kUnknownError, "'loggingPrefs' must be a dictionary");
+
+ // TODO(klm): verify log types.
+ // TODO(klm): verify log levels.
+ capabilities->logging_prefs.reset(logging_prefs_dict->DeepCopy());
+ return Status(kOk);
+}
+
+Status ParseChromeOptions(
Log* log,
const base::Value& capability,
Capabilities* capabilities) {
@@ -206,18 +259,41 @@ Status ParseDesktopChromeCapabilities(
if (!capability.GetAsDictionary(&chrome_options))
return Status(kUnknownError, "'chromeOptions' must be a dictionary");
- std::map<std::string, Parser> parser_map;
+ bool is_android = chrome_options->HasKey("androidPackage");
+ bool is_existing = chrome_options->HasKey("useExistingBrowser");
- parser_map["detach"] = base::Bind(&ParseDetach);
- parser_map["loadAsync"] =
- base::Bind(&IgnoreDeprecatedOption, log, "loadAsync");
- parser_map["binary"] = base::Bind(&ParseChromeBinary);
- parser_map["logPath"] = base::Bind(&ParseLogPath);
- parser_map["args"] = base::Bind(&ParseArgs, false);
- parser_map["prefs"] = base::Bind(&ParsePrefs);
- parser_map["localState"] = base::Bind(&ParseLocalState);
- parser_map["extensions"] = base::Bind(&ParseExtensions);
- parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches);
+ std::map<std::string, Parser> parser_map;
+ // Ignore 'binary' and 'extensions' capability, since the Java client
+ // always passes them.
+ parser_map["binary"] = base::Bind(&IgnoreCapability);
+ parser_map["extensions"] = base::Bind(&IgnoreCapability);
+ if (is_android) {
+ parser_map["androidActivity"] =
+ base::Bind(&ParseString, &capabilities->android_activity);
+ parser_map["androidDeviceSerial"] =
+ base::Bind(&ParseString, &capabilities->android_device_serial);
+ parser_map["androidPackage"] =
+ base::Bind(&ParseString, &capabilities->android_package);
+ parser_map["androidProcess"] =
+ base::Bind(&ParseString, &capabilities->android_process);
+ parser_map["args"] = base::Bind(&ParseArgs, true);
+ } else if (is_existing) {
+ parser_map["args"] = base::Bind(&IgnoreCapability);
+ parser_map["useExistingBrowser"] = base::Bind(&ParseUseExistingBrowser);
+ } else {
+ parser_map["forceDevToolsScreenshot"] = base::Bind(
+ &ParseBoolean, &capabilities->force_devtools_screenshot);
+ parser_map["args"] = base::Bind(&ParseArgs, false);
+ parser_map["binary"] = base::Bind(&ParseChromeBinary);
+ parser_map["detach"] = base::Bind(&ParseBoolean, &capabilities->detach);
+ parser_map["excludeSwitches"] = base::Bind(&ParseExcludeSwitches);
+ parser_map["extensions"] = base::Bind(&ParseExtensions);
+ parser_map["loadAsync"] =
+ base::Bind(&IgnoreDeprecatedOption, log, "loadAsync");
+ parser_map["localState"] = base::Bind(&ParseLocalState);
+ parser_map["logPath"] = base::Bind(&ParseLogPath);
+ parser_map["prefs"] = base::Bind(&ParsePrefs);
+ }
for (base::DictionaryValue::Iterator it(*chrome_options); !it.IsAtEnd();
it.Advance()) {
@@ -227,79 +303,7 @@ Status ParseDesktopChromeCapabilities(
}
Status status = parser_map[it.key()].Run(it.value(), capabilities);
if (status.IsError())
- return status;
- }
- return Status(kOk);
-}
-
-Status ParseAndroidChromeCapabilities(const base::DictionaryValue& desired_caps,
- Capabilities* capabilities) {
- const base::Value* chrome_options = NULL;
- if (desired_caps.Get("chromeOptions", &chrome_options)) {
- const base::DictionaryValue* chrome_options_dict = NULL;
- if (!chrome_options->GetAsDictionary(&chrome_options_dict))
- return Status(kUnknownError, "'chromeOptions' must be a dictionary");
-
- const base::Value* android_package_value;
- if (chrome_options_dict->Get("androidPackage", &android_package_value)) {
- if (!android_package_value->GetAsString(&capabilities->android_package) ||
- capabilities->android_package.empty()) {
- return Status(kUnknownError,
- "'androidPackage' must be a non-empty string");
- }
-
- const base::Value* device_serial_value;
- if (chrome_options_dict->Get("androidDeviceSerial",
- &device_serial_value)) {
- if (!device_serial_value->GetAsString(
- &capabilities->android_device_serial) ||
- capabilities->android_device_serial.empty()) {
- return Status(kUnknownError,
- "'androidDeviceSerial' must be a non-empty string");
- }
- }
-
- const base::Value* activity_value;
- if (chrome_options_dict->Get("androidActivity",
- &activity_value)) {
- if (!activity_value->GetAsString(
- &capabilities->android_activity) ||
- capabilities->android_activity.empty()) {
- return Status(kUnknownError,
- "'androidActivity' must be a non-empty string");
- }
- }
-
- const base::Value* process_value;
- if (chrome_options_dict->Get("androidProcess",
- &process_value)) {
- if (!process_value->GetAsString(
- &capabilities->android_process) ||
- capabilities->android_process.empty()) {
- return Status(kUnknownError,
- "'androidProcess' must be a non-empty string");
- }
- }
-
- const base::Value* args_value;
- if (chrome_options_dict->Get("args", &args_value))
- return ParseArgs(true, *args_value, capabilities);
- }
- }
- return Status(kOk);
-}
-
-Status ParseLoggingPrefs(const base::DictionaryValue& desired_caps,
- Capabilities* capabilities) {
- const base::Value* logging_prefs = NULL;
- if (desired_caps.Get("loggingPrefs", &logging_prefs)) {
- const base::DictionaryValue* logging_prefs_dict = NULL;
- if (!logging_prefs->GetAsDictionary(&logging_prefs_dict)) {
- return Status(kUnknownError, "'loggingPrefs' must be a dictionary");
- }
- // TODO(klm): verify log types.
- // TODO(klm): verify log levels.
- capabilities->logging_prefs.reset(logging_prefs_dict->DeepCopy());
+ return Status(kUnknownError, "cannot parse " + it.key(), status);
}
return Status(kOk);
}
@@ -307,7 +311,8 @@ Status ParseLoggingPrefs(const base::DictionaryValue& desired_caps,
} // namespace
Capabilities::Capabilities()
- : detach(false),
+ : force_devtools_screenshot(false),
+ detach(false),
command(CommandLine::NO_PROGRAM) {}
Capabilities::~Capabilities() {}
@@ -316,29 +321,26 @@ bool Capabilities::IsAndroid() const {
return !android_package.empty();
}
+bool Capabilities::IsExistingBrowser() const {
+ return use_existing_browser.IsValid();
+}
+
Status Capabilities::Parse(
const base::DictionaryValue& desired_caps,
Log* log) {
- Status status = ParseLoggingPrefs(desired_caps, this);
- if (status.IsError())
- return status;
- status = ParseAndroidChromeCapabilities(desired_caps, this);
- if (status.IsError())
- return status;
- if (IsAndroid())
- return Status(kOk);
-
std::map<std::string, Parser> parser_map;
+ parser_map["chromeOptions"] = base::Bind(&ParseChromeOptions, log);
+ parser_map["loggingPrefs"] = base::Bind(&ParseLoggingPrefs);
parser_map["proxy"] = base::Bind(&ParseProxy);
- parser_map["chromeOptions"] =
- base::Bind(&ParseDesktopChromeCapabilities, log);
for (std::map<std::string, Parser>::iterator it = parser_map.begin();
it != parser_map.end(); ++it) {
const base::Value* capability = NULL;
if (desired_caps.Get(it->first, &capability)) {
- status = it->second.Run(*capability, this);
- if (status.IsError())
- return status;
+ Status status = it->second.Run(*capability, this);
+ if (status.IsError()) {
+ return Status(
+ kUnknownError, "cannot parse capability: " + it->first, status);
+ }
}
}
return Status(kOk);
diff --git a/chrome/test/chromedriver/capabilities.h b/chrome/test/chromedriver/capabilities.h
index c5e243ea76..4fc5734f58 100644
--- a/chrome/test/chromedriver/capabilities.h
+++ b/chrome/test/chromedriver/capabilities.h
@@ -12,6 +12,7 @@
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/memory/scoped_ptr.h"
+#include "chrome/test/chromedriver/net/net_util.h"
namespace base {
class DictionaryValue;
@@ -24,11 +25,18 @@ struct Capabilities {
Capabilities();
~Capabilities();
+ // Return true if existing host:port session is to be used.
+ bool IsExistingBrowser() const;
+
// Return true if android package is specified.
bool IsAndroid() const;
Status Parse(const base::DictionaryValue& desired_caps, Log* log);
+ // True if should always use DevTools for taking screenshots.
+ // This is experimental and may be removed at a later point.
+ bool force_devtools_screenshot;
+
// Whether the lifetime of the started Chrome browser process should be
// bound to ChromeDriver's process. If true, Chrome will not quit if
// ChromeDriver dies.
@@ -50,6 +58,9 @@ struct Capabilities {
// Set of switches which should be removed from default list when launching
// Chrome.
std::set<std::string> exclude_switches;
+
+ // If provided, the remote debugging address to connect to.
+ NetAddress use_existing_browser;
};
#endif // CHROME_TEST_CHROMEDRIVER_CAPABILITIES_H_
diff --git a/chrome/test/chromedriver/capabilities_unittest.cc b/chrome/test/chromedriver/capabilities_unittest.cc
index 759646885e..9717c593ea 100644
--- a/chrome/test/chromedriver/capabilities_unittest.cc
+++ b/chrome/test/chromedriver/capabilities_unittest.cc
@@ -333,3 +333,15 @@ TEST(ParseCapabilities, ExcludeSwitches) {
ASSERT_TRUE(switches.find("switch1") != switches.end());
ASSERT_TRUE(switches.find("switch2") != switches.end());
}
+
+TEST(ParseCapabilities, UseExistingBrowser) {
+ Capabilities capabilities;
+ base::DictionaryValue caps;
+ caps.SetString("chromeOptions.useExistingBrowser", "abc:123");
+ Logger log(Log::kError);
+ Status status = capabilities.Parse(caps, &log);
+ ASSERT_TRUE(status.IsOk());
+ ASSERT_TRUE(capabilities.IsExistingBrowser());
+ ASSERT_EQ("abc", capabilities.use_existing_browser.host());
+ ASSERT_EQ(123, capabilities.use_existing_browser.port());
+}
diff --git a/chrome/test/chromedriver/chrome/automation_extension.cc b/chrome/test/chromedriver/chrome/automation_extension.cc
index 65e035af9d..27999c8b85 100644
--- a/chrome/test/chromedriver/chrome/automation_extension.cc
+++ b/chrome/test/chromedriver/chrome/automation_extension.cc
@@ -14,6 +14,22 @@ AutomationExtension::AutomationExtension(scoped_ptr<WebView> web_view)
AutomationExtension::~AutomationExtension() {}
+Status AutomationExtension::CaptureScreenshot(std::string* screenshot) {
+ base::ListValue args;
+ scoped_ptr<base::Value> result;
+ Status status = web_view_->CallAsyncFunction(
+ std::string(),
+ "captureScreenshot",
+ args,
+ base::TimeDelta::FromSeconds(10),
+ &result);
+ if (status.IsError())
+ return Status(kUnknownError, "cannot take screenshot", status);
+ if (!result->GetAsString(screenshot))
+ return Status(kUnknownError, "screenshot is not a string");
+ return Status(kOk);
+}
+
Status AutomationExtension::GetWindowPosition(int* x, int* y) {
int temp_width, temp_height;
return GetWindowInfo(x, y, &temp_width, &temp_height);
diff --git a/chrome/test/chromedriver/chrome/automation_extension.h b/chrome/test/chromedriver/chrome/automation_extension.h
index aea732d8f3..b89ff5aa6c 100644
--- a/chrome/test/chromedriver/chrome/automation_extension.h
+++ b/chrome/test/chromedriver/chrome/automation_extension.h
@@ -5,6 +5,8 @@
#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_AUTOMATION_EXTENSION_H_
#define CHROME_TEST_CHROMEDRIVER_CHROME_AUTOMATION_EXTENSION_H_
+#include <string>
+
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
@@ -21,6 +23,9 @@ class AutomationExtension {
explicit AutomationExtension(scoped_ptr<WebView> web_view);
~AutomationExtension();
+ // Captures the visible part of the current tab as a base64-encoded PNG.
+ Status CaptureScreenshot(std::string* screenshot);
+
// Gets the position of the current window.
Status GetWindowPosition(int* x, int* y);
diff --git a/chrome/test/chromedriver/chrome/chrome.h b/chrome/test/chromedriver/chrome/chrome.h
index 899fa4c6f2..ef4ce8328f 100644
--- a/chrome/test/chromedriver/chrome/chrome.h
+++ b/chrome/test/chromedriver/chrome/chrome.h
@@ -16,6 +16,14 @@ class Chrome {
public:
virtual ~Chrome() {}
+ enum Type {
+ DESKTOP,
+ ANDROID,
+ EXISTING
+ };
+
+ virtual Type GetType() = 0;
+
virtual std::string GetVersion() = 0;
virtual int GetBuildNo() = 0;
@@ -29,6 +37,9 @@ class Chrome {
// Closes the specified WebView.
virtual Status CloseWebView(const std::string& id) = 0;
+ // Activates the specified WebView.
+ virtual Status ActivateWebView(const std::string& id) = 0;
+
// Gets the automation extension.
virtual Status GetAutomationExtension(AutomationExtension** extension) = 0;
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.cc b/chrome/test/chromedriver/chrome/chrome_android_impl.cc
index 3301e02063..986606b3a7 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.cc
@@ -18,6 +18,10 @@ ChromeAndroidImpl::ChromeAndroidImpl(
ChromeAndroidImpl::~ChromeAndroidImpl() {}
+Chrome::Type ChromeAndroidImpl::GetType() {
+ return ANDROID;
+}
+
std::string ChromeAndroidImpl::GetOperatingSystemName() {
return "ANDROID";
}
diff --git a/chrome/test/chromedriver/chrome/chrome_android_impl.h b/chrome/test/chromedriver/chrome/chrome_android_impl.h
index 139a0e0841..ef273416e0 100644
--- a/chrome/test/chromedriver/chrome/chrome_android_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_android_impl.h
@@ -24,6 +24,7 @@ class ChromeAndroidImpl : public ChromeImpl {
virtual ~ChromeAndroidImpl();
// Overridden from Chrome:
+ virtual Type GetType() OVERRIDE;
virtual std::string GetOperatingSystemName() OVERRIDE;
virtual Status Quit() OVERRIDE;
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
index c4549179f6..415d7e4dfd 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.cc
@@ -87,42 +87,58 @@ ChromeDesktopImpl::~ChromeDesktopImpl() {
base::CloseProcessHandle(process_);
}
-Status ChromeDesktopImpl::GetAutomationExtension(
- AutomationExtension** extension) {
- if (!automation_extension_) {
- base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(10);
- std::string id;
- while (base::Time::Now() < deadline) {
- WebViewsInfo views_info;
- Status status = devtools_http_client_->GetWebViewsInfo(&views_info);
- if (status.IsError())
- return status;
-
- for (size_t i = 0; i < views_info.GetSize(); ++i) {
- if (views_info.Get(i).url.find(
- "chrome-extension://aapnijgdinlhnhlmodcfapnahmbfebeb") == 0) {
- id = views_info.Get(i).id;
- break;
- }
- }
- if (!id.empty())
+Status ChromeDesktopImpl::WaitForPageToLoad(const std::string& url,
+ const base::TimeDelta& timeout,
+ scoped_ptr<WebView>* web_view) {
+ base::Time deadline = base::Time::Now() + timeout;
+ std::string id;
+ while (base::Time::Now() < deadline) {
+ WebViewsInfo views_info;
+ Status status = devtools_http_client_->GetWebViewsInfo(&views_info);
+ if (status.IsError())
+ return status;
+
+ for (size_t i = 0; i < views_info.GetSize(); ++i) {
+ if (views_info.Get(i).url.find(url) == 0) {
+ id = views_info.Get(i).id;
break;
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+ }
}
- if (id.empty())
- return Status(kUnknownError, "automation extension cannot be found");
+ if (!id.empty())
+ break;
+ base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+ }
+ if (id.empty())
+ return Status(kUnknownError, "page could not be found: " + url);
+
+ scoped_ptr<WebView> web_view_tmp(new WebViewImpl(
+ id, GetBuildNo(), devtools_http_client_->CreateClient(id), log_));
+ Status status = web_view_tmp->ConnectIfNecessary();
+ if (status.IsError())
+ return status;
+
+ status = web_view_tmp->WaitForPendingNavigations(
+ std::string(), deadline - base::Time::Now(), false);
+ if (status.IsOk())
+ *web_view = web_view_tmp.Pass();
+ return status;
+}
- scoped_ptr<WebView> web_view(new WebViewImpl(
- id, GetBuildNo(), devtools_http_client_->CreateClient(id), log_));
- Status status = web_view->ConnectIfNecessary();
- if (status.IsError())
- return status;
+Chrome::Type ChromeDesktopImpl::GetType() {
+ return DESKTOP;
+}
- // Wait for the extension background page to load.
- status = web_view->WaitForPendingNavigations(
- std::string(), 5 * 60 * 1000);
+Status ChromeDesktopImpl::GetAutomationExtension(
+ AutomationExtension** extension) {
+ if (!automation_extension_) {
+ scoped_ptr<WebView> web_view;
+ Status status = WaitForPageToLoad(
+ "chrome-extension://aapnijgdinlhnhlmodcfapnahmbfebeb/"
+ "_generated_background_page.html",
+ base::TimeDelta::FromSeconds(10),
+ &web_view);
if (status.IsError())
- return status;
+ return Status(kUnknownError, "cannot get automation extension", status);
automation_extension_.reset(new AutomationExtension(web_view.Pass()));
}
diff --git a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
index bc1762018a..52c9b98ada 100644
--- a/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_desktop_impl.h
@@ -9,12 +9,18 @@
#include "base/compiler_specific.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
#include "base/process/process.h"
#include "chrome/test/chromedriver/chrome/chrome_impl.h"
+namespace base {
+class TimeDelta;
+}
+
class AutomationExtension;
class DevToolsHttpClient;
class Status;
+class WebView;
class ChromeDesktopImpl : public ChromeImpl {
public:
@@ -27,7 +33,14 @@ class ChromeDesktopImpl : public ChromeImpl {
base::ScopedTempDir* extension_dir);
virtual ~ChromeDesktopImpl();
+ // Waits for a page with the given URL to appear and finish loading.
+ // Returns an error if the timeout is exceeded.
+ Status WaitForPageToLoad(const std::string& url,
+ const base::TimeDelta& timeout,
+ scoped_ptr<WebView>* web_view);
+
// Overridden from Chrome:
+ virtual Type GetType() OVERRIDE;
virtual Status GetAutomationExtension(
AutomationExtension** extension) OVERRIDE;
virtual std::string GetOperatingSystemName() OVERRIDE;
diff --git a/chrome/test/chromedriver/chrome/chrome_existing_impl.cc b/chrome/test/chromedriver/chrome/chrome_existing_impl.cc
new file mode 100644
index 0000000000..64ead8d67a
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/chrome_existing_impl.cc
@@ -0,0 +1,28 @@
+// 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 "chrome/test/chromedriver/chrome/chrome_existing_impl.h"
+#include "chrome/test/chromedriver/chrome/devtools_http_client.h"
+#include "chrome/test/chromedriver/chrome/status.h"
+
+ChromeExistingImpl::ChromeExistingImpl(
+ scoped_ptr<DevToolsHttpClient> client,
+ ScopedVector<DevToolsEventListener>& devtools_event_listeners,
+ Log* log)
+ : ChromeImpl(client.Pass(), devtools_event_listeners, log) {}
+
+ChromeExistingImpl::~ChromeExistingImpl() {}
+
+Chrome::Type ChromeExistingImpl::GetType() {
+ return EXISTING;
+}
+
+std::string ChromeExistingImpl::GetOperatingSystemName() {
+ return std::string();
+}
+
+Status ChromeExistingImpl::Quit() {
+ return Status(kOk);
+}
+
diff --git a/chrome/test/chromedriver/chrome/chrome_existing_impl.h b/chrome/test/chromedriver/chrome/chrome_existing_impl.h
new file mode 100644
index 0000000000..4362dfe819
--- /dev/null
+++ b/chrome/test/chromedriver/chrome/chrome_existing_impl.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_EXISTING_IMPL_H_
+#define CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_EXISTING_IMPL_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "chrome/test/chromedriver/chrome/chrome_impl.h"
+
+class DevToolsHttpClient;
+
+class ChromeExistingImpl : public ChromeImpl {
+ public:
+ ChromeExistingImpl(
+ scoped_ptr<DevToolsHttpClient> client,
+ ScopedVector<DevToolsEventListener>& devtools_event_listeners,
+ Log* log);
+ virtual ~ChromeExistingImpl();
+
+ // Overridden from Chrome.
+ virtual Type GetType() OVERRIDE;
+ virtual std::string GetOperatingSystemName() OVERRIDE;
+ virtual Status Quit() OVERRIDE;
+};
+
+#endif // CHROME_TEST_CHROMEDRIVER_CHROME_CHROME_EXISTING_IMPL_H_
diff --git a/chrome/test/chromedriver/chrome/chrome_finder.cc b/chrome/test/chromedriver/chrome/chrome_finder.cc
index a6e9426e78..2cb69c1225 100644
--- a/chrome/test/chromedriver/chrome/chrome_finder.cc
+++ b/chrome/test/chromedriver/chrome/chrome_finder.cc
@@ -101,10 +101,18 @@ bool FindChrome(base::FilePath* browser_exe) {
#endif
std::vector<base::FilePath> browser_exes(
browser_exes_array, browser_exes_array + arraysize(browser_exes_array));
- std::vector<base::FilePath> locations;
base::FilePath module_dir;
- if (PathService::Get(base::DIR_MODULE, &module_dir))
- locations.push_back(module_dir);
+ if (PathService::Get(base::DIR_MODULE, &module_dir)) {
+ for (size_t i = 0; i < browser_exes.size(); ++i) {
+ base::FilePath path = module_dir.Append(browser_exes[i]);
+ if (base::PathExists(path)) {
+ *browser_exe = path;
+ return true;
+ }
+ }
+ }
+
+ std::vector<base::FilePath> locations;
GetApplicationDirs(&locations);
return internal::FindExe(
base::Bind(&base::PathExists),
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.cc b/chrome/test/chromedriver/chrome/chrome_impl.cc
index 720c8db6eb..e4c4971e95 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.cc
+++ b/chrome/test/chromedriver/chrome/chrome_impl.cc
@@ -99,6 +99,10 @@ Status ChromeImpl::CloseWebView(const std::string& id) {
return Status(kOk);
}
+Status ChromeImpl::ActivateWebView(const std::string& id) {
+ return devtools_http_client_->ActivateWebView(id);
+}
+
Status ChromeImpl::GetAutomationExtension(AutomationExtension** extension) {
return Status(kUnknownError, "automation extension not supported");
}
diff --git a/chrome/test/chromedriver/chrome/chrome_impl.h b/chrome/test/chromedriver/chrome/chrome_impl.h
index 3659dbb2e1..be43cb01dc 100644
--- a/chrome/test/chromedriver/chrome/chrome_impl.h
+++ b/chrome/test/chromedriver/chrome/chrome_impl.h
@@ -34,6 +34,7 @@ class ChromeImpl : public Chrome {
virtual Status GetWebViewById(const std::string& id,
WebView** web_view) OVERRIDE;
virtual Status CloseWebView(const std::string& id) OVERRIDE;
+ virtual Status ActivateWebView(const std::string& id) OVERRIDE;
virtual Status GetAutomationExtension(
AutomationExtension** extension) OVERRIDE;
diff --git a/chrome/test/chromedriver/chrome/devtools_client.h b/chrome/test/chromedriver/chrome/devtools_client.h
index db79210eb5..05f5dfc544 100644
--- a/chrome/test/chromedriver/chrome/devtools_client.h
+++ b/chrome/test/chromedriver/chrome/devtools_client.h
@@ -43,8 +43,8 @@ class DevToolsClient {
// Handles events until the given function reports the condition is met
// and there are no more received events to handle. If the given
// function ever returns an error, returns immediately with the error.
- // If the condition is not met within |timeout|ms, kTimeout status
- // is returned eventually.
+ // If the condition is not met within |timeout|, kTimeout status
+ // is returned eventually. If |timeout| is 0, this function will not block.
virtual Status HandleEventsUntil(const ConditionalFunc& conditional_func,
const base::TimeDelta& timeout) = 0;
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.cc b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
index 4077112588..c9191916bd 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.cc
@@ -47,6 +47,11 @@ class ScopedIncrementer {
int* count_;
};
+Status ConditionIsMet(bool* is_condition_met) {
+ *is_condition_met = true;
+ return Status(kOk);
+}
+
} // namespace
namespace internal {
@@ -158,17 +163,7 @@ void DevToolsClientImpl::AddListener(DevToolsEventListener* listener) {
}
Status DevToolsClientImpl::HandleReceivedEvents() {
- if (!socket_->IsConnected())
- return Status(kDisconnected, "not connected to DevTools");
-
- while (true) {
- if (!socket_->HasNextMessage())
- return Status(kOk);
-
- Status status = ProcessNextMessage(-1);
- if (status.IsError())
- return status;
- }
+ return HandleEventsUntil(base::Bind(&ConditionIsMet), base::TimeDelta());
}
Status DevToolsClientImpl::HandleEventsUntil(
@@ -177,14 +172,10 @@ Status DevToolsClientImpl::HandleEventsUntil(
return Status(kDisconnected, "not connected to DevTools");
base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
-
+ base::TimeDelta next_message_timeout = timeout;
while (true) {
- if (base::TimeTicks::Now() >= deadline)
- return Status(kTimeout, base::StringPrintf(
- "exceeded %dms", static_cast<int>(timeout.InMilliseconds())));
-
if (!socket_->HasNextMessage()) {
- bool is_condition_met;
+ bool is_condition_met = false;
Status status = conditional_func.Run(&is_condition_met);
if (status.IsError())
return status;
@@ -192,12 +183,10 @@ Status DevToolsClientImpl::HandleEventsUntil(
return Status(kOk);
}
- // To keep this simple, we don't pass the delta time to
- // ProcessNextMessage. As a result, we may not immediately
- // return after |timeout|ms.
- Status status = ProcessNextMessage(-1);
- if (status.IsError() && status.code() != kTimeout)
+ Status status = ProcessNextMessage(-1, next_message_timeout);
+ if (status.IsError())
return status;
+ next_message_timeout = deadline - base::TimeTicks::Now();
}
}
@@ -228,7 +217,8 @@ Status DevToolsClientImpl::SendCommandInternal(
make_linked_ptr(new ResponseInfo(method));
response_info_map_[command_id] = response_info;
while (response_info->state == kWaiting) {
- Status status = ProcessNextMessage(command_id);
+ Status status = ProcessNextMessage(
+ command_id, base::TimeDelta::FromMinutes(10));
if (status.IsError()) {
if (response_info->state == kReceived)
response_info_map_.erase(command_id);
@@ -247,7 +237,9 @@ Status DevToolsClientImpl::SendCommandInternal(
return Status(kOk);
}
-Status DevToolsClientImpl::ProcessNextMessage(int expected_id) {
+Status DevToolsClientImpl::ProcessNextMessage(
+ int expected_id,
+ const base::TimeDelta& timeout) {
ScopedIncrementer increment_stack_count(&stack_count_);
Status status = EnsureListenersNotifiedOfConnect();
@@ -266,8 +258,7 @@ Status DevToolsClientImpl::ProcessNextMessage(int expected_id) {
return Status(kOk);
std::string message;
- switch (socket_->ReceiveNextMessage(&message,
- base::TimeDelta::FromMinutes(1))) {
+ switch (socket_->ReceiveNextMessage(&message, timeout)) {
case SyncWebSocket::kOk:
log_->AddEntry(Log::kDebug, "received Inspector response " + message);
break;
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl.h b/chrome/test/chromedriver/chrome/devtools_client_impl.h
index 4dad6a56bf..1fe1f0a870 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl.h
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl.h
@@ -118,7 +118,7 @@ class DevToolsClientImpl : public DevToolsClient {
const std::string& method,
const base::DictionaryValue& params,
scoped_ptr<base::DictionaryValue>* result);
- Status ProcessNextMessage(int expected_id);
+ Status ProcessNextMessage(int expected_id, const base::TimeDelta& timeout);
Status ProcessEvent(const internal::InspectorEvent& event);
Status ProcessCommandResponse(
const internal::InspectorCommandResponse& response);
diff --git a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
index 4ccaa2db84..6e9fa558e1 100644
--- a/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
+++ b/chrome/test/chromedriver/chrome/devtools_client_impl_unittest.cc
@@ -66,6 +66,8 @@ class MockSyncWebSocket : public SyncWebSocket {
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
+ if (timeout <= base::TimeDelta())
+ return SyncWebSocket::kTimeout;
base::DictionaryValue response;
response.SetInteger("id", id_);
base::DictionaryValue result;
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.cc b/chrome/test/chromedriver/chrome/devtools_http_client.cc
index 5b3cad0565..6b8e89bbc8 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.cc
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.cc
@@ -65,16 +65,16 @@ const WebViewInfo* WebViewsInfo::GetForId(const std::string& id) const {
}
DevToolsHttpClient::DevToolsHttpClient(
- int port,
+ const NetAddress& address,
scoped_refptr<URLRequestContextGetter> context_getter,
const SyncWebSocketFactory& socket_factory,
Log* log)
: context_getter_(context_getter),
socket_factory_(socket_factory),
log_(log),
- server_url_(base::StringPrintf("http://127.0.0.1:%d", port)),
- web_socket_url_prefix_(
- base::StringPrintf("ws://127.0.0.1:%d/devtools/page/", port)) {}
+ server_url_("http://" + address.ToString()),
+ web_socket_url_prefix_(base::StringPrintf(
+ "ws://%s/devtools/page/", address.ToString().c_str())) {}
DevToolsHttpClient::~DevToolsHttpClient() {}
@@ -166,6 +166,14 @@ Status DevToolsHttpClient::CloseWebView(const std::string& id) {
return Status(kUnknownError, "failed to close window in 20 seconds");
}
+Status DevToolsHttpClient::ActivateWebView(const std::string& id) {
+ std::string data;
+ if (!FetchUrlAndLog(
+ server_url_ + "/json/activate/" + id, context_getter_.get(), &data))
+ return Status(kUnknownError, "cannot activate web view");
+ return Status(kOk);
+}
+
const std::string& DevToolsHttpClient::version() const {
return version_;
}
diff --git a/chrome/test/chromedriver/chrome/devtools_http_client.h b/chrome/test/chromedriver/chrome/devtools_http_client.h
index 552419d846..888652150b 100644
--- a/chrome/test/chromedriver/chrome/devtools_http_client.h
+++ b/chrome/test/chromedriver/chrome/devtools_http_client.h
@@ -18,6 +18,7 @@ class TimeDelta;
class DevToolsClient;
class Log;
+class NetAddress;
class Status;
class URLRequestContextGetter;
@@ -58,7 +59,7 @@ class WebViewsInfo {
class DevToolsHttpClient {
public:
DevToolsHttpClient(
- int port,
+ const NetAddress& address,
scoped_refptr<URLRequestContextGetter> context_getter,
const SyncWebSocketFactory& socket_factory,
Log* log);
@@ -72,6 +73,8 @@ class DevToolsHttpClient {
Status CloseWebView(const std::string& id);
+ Status ActivateWebView(const std::string& id);
+
const std::string& version() const;
int build_no() const;
diff --git a/chrome/test/chromedriver/chrome/stub_chrome.cc b/chrome/test/chromedriver/chrome/stub_chrome.cc
index 4e93bb22aa..4f8fc45b88 100644
--- a/chrome/test/chromedriver/chrome/stub_chrome.cc
+++ b/chrome/test/chromedriver/chrome/stub_chrome.cc
@@ -10,6 +10,10 @@ StubChrome::StubChrome() {}
StubChrome::~StubChrome() {}
+Chrome::Type StubChrome::GetType() {
+ return DESKTOP;
+}
+
std::string StubChrome::GetVersion() {
return std::string();
}
@@ -30,6 +34,10 @@ Status StubChrome::CloseWebView(const std::string& id) {
return Status(kOk);
}
+Status StubChrome::ActivateWebView(const std::string& id) {
+ return Status(kOk);
+}
+
Status StubChrome::GetAutomationExtension(AutomationExtension** extension) {
return Status(kOk);
}
diff --git a/chrome/test/chromedriver/chrome/stub_chrome.h b/chrome/test/chromedriver/chrome/stub_chrome.h
index 73f41eefc5..e4e4628dab 100644
--- a/chrome/test/chromedriver/chrome/stub_chrome.h
+++ b/chrome/test/chromedriver/chrome/stub_chrome.h
@@ -19,12 +19,14 @@ class StubChrome : public Chrome {
virtual ~StubChrome();
// Overridden from Chrome:
+ virtual Type GetType() OVERRIDE;
virtual std::string GetVersion() OVERRIDE;
virtual int GetBuildNo() OVERRIDE;
virtual Status GetWebViewIds(std::list<std::string>* web_view_ids) OVERRIDE;
virtual Status GetWebViewById(const std::string& id,
WebView** web_view) OVERRIDE;
virtual Status CloseWebView(const std::string& id) OVERRIDE;
+ virtual Status ActivateWebView(const std::string& id) OVERRIDE;
virtual Status GetAutomationExtension(
AutomationExtension** extension) OVERRIDE;
virtual std::string GetOperatingSystemName() OVERRIDE;
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.cc b/chrome/test/chromedriver/chrome/stub_web_view.cc
index a40fb604e1..9d90fd7787 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.cc
+++ b/chrome/test/chromedriver/chrome/stub_web_view.cc
@@ -91,7 +91,8 @@ Status StubWebView::DeleteCookie(const std::string& name,
}
Status StubWebView::WaitForPendingNavigations(const std::string& frame_id,
- int timeout) {
+ const base::TimeDelta& timeout,
+ bool stop_load_on_timeout) {
return Status(kOk);
}
diff --git a/chrome/test/chromedriver/chrome/stub_web_view.h b/chrome/test/chromedriver/chrome/stub_web_view.h
index 952b1b5b1a..b19baf310c 100644
--- a/chrome/test/chromedriver/chrome/stub_web_view.h
+++ b/chrome/test/chromedriver/chrome/stub_web_view.h
@@ -54,7 +54,8 @@ class StubWebView : public WebView {
virtual Status DeleteCookie(const std::string& name,
const std::string& url) OVERRIDE;
virtual Status WaitForPendingNavigations(const std::string& frame_id,
- int timeout) OVERRIDE;
+ const base::TimeDelta& timeout,
+ bool stop_load_on_timeout) OVERRIDE;
virtual Status IsPendingNavigation(
const std::string& frame_id, bool* is_pending) OVERRIDE;
virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE;
diff --git a/chrome/test/chromedriver/chrome/web_view.h b/chrome/test/chromedriver/chrome/web_view.h
index 5e11d598df..10decb0a53 100644
--- a/chrome/test/chromedriver/chrome/web_view.h
+++ b/chrome/test/chromedriver/chrome/web_view.h
@@ -50,6 +50,7 @@ class WebView {
// the result. |frame| is a frame ID or an empty string for the main frame.
// If the expression evaluates to a element, it will be bound to a unique ID
// (per frame) and the ID will be returned.
+ // |result| will never be NULL on success.
virtual Status EvaluateScript(const std::string& frame,
const std::string& expression,
scoped_ptr<base::Value>* result) = 0;
@@ -59,6 +60,7 @@ class WebView {
// frame. |args| may contain IDs that refer to previously returned elements.
// These will be translated back to their referred objects before invoking the
// function.
+ // |result| will never be NULL on success.
virtual Status CallFunction(const std::string& frame,
const std::string& function,
const base::ListValue& args,
@@ -68,6 +70,7 @@ class WebView {
// two callbacks. The first may be invoked with a value to return to the user.
// The second may be used to report an error. This function waits until
// one of the callbacks is invoked or the timeout occurs.
+ // |result| will never be NULL on success.
virtual Status CallAsyncFunction(const std::string& frame,
const std::string& function,
const base::ListValue& args,
@@ -77,6 +80,7 @@ class WebView {
// Same as |CallAsyncFunction|, except no additional error callback is passed
// to the function. Also, |kJavaScriptError| or |kScriptTimeout| is used
// as the error code instead of |kUnknownError| in appropriate cases.
+ // |result| will never be NULL on success.
virtual Status CallUserAsyncFunction(const std::string& frame,
const std::string& function,
const base::ListValue& args,
@@ -112,10 +116,12 @@ class WebView {
// If |frame_id| is "", waits for navigations on the main frame.
// If a modal dialog appears while waiting, kUnexpectedAlertOpen will be
// returned.
- // If there are still pending navigations after |timeout|ms,
- // page load is stopped, and kTimeout status is returned.
+ // If timeout is exceeded, will return a timeout status.
+ // If |stop_load_on_timeout| is true, will attempt to stop the page load on
+ // timeout before returning the timeout status.
virtual Status WaitForPendingNavigations(const std::string& frame_id,
- int timeout) = 0;
+ const base::TimeDelta& timeout,
+ bool stop_load_on_timeout) = 0;
// Returns whether the frame is pending navigation.
virtual Status IsPendingNavigation(
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.cc b/chrome/test/chromedriver/chrome/web_view_impl.cc
index b463b0e007..dd5d8ac9b3 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.cc
+++ b/chrome/test/chromedriver/chrome/web_view_impl.cc
@@ -320,13 +320,15 @@ Status WebViewImpl::DeleteCookie(const std::string& name,
}
Status WebViewImpl::WaitForPendingNavigations(const std::string& frame_id,
- int timeout) {
+ const base::TimeDelta& timeout,
+ bool stop_load_on_timeout) {
log_->AddEntry(Log::kLog, "waiting for pending navigations...");
Status status = client_->HandleEventsUntil(
- base::Bind(&WebViewImpl::IsNotPendingNavigation, base::Unretained(this),
+ base::Bind(&WebViewImpl::IsNotPendingNavigation,
+ base::Unretained(this),
frame_id),
- base::TimeDelta::FromMilliseconds(timeout));
- if (status.code() == kTimeout) {
+ timeout);
+ if (status.code() == kTimeout && stop_load_on_timeout) {
log_->AddEntry(Log::kLog, "timed out. stopping navigations...");
scoped_ptr<base::Value> unused_value;
EvaluateScript(std::string(), "window.stop();", &unused_value);
diff --git a/chrome/test/chromedriver/chrome/web_view_impl.h b/chrome/test/chromedriver/chrome/web_view_impl.h
index 239d7b4e0d..1067ad0092 100644
--- a/chrome/test/chromedriver/chrome/web_view_impl.h
+++ b/chrome/test/chromedriver/chrome/web_view_impl.h
@@ -74,7 +74,8 @@ class WebViewImpl : public WebView {
virtual Status DeleteCookie(const std::string& name,
const std::string& url) OVERRIDE;
virtual Status WaitForPendingNavigations(const std::string& frame_id,
- int timeout) OVERRIDE;
+ const base::TimeDelta& timeout,
+ bool stop_load_on_timeout) OVERRIDE;
virtual Status IsPendingNavigation(
const std::string& frame_id, bool* is_pending) OVERRIDE;
virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE;
diff --git a/chrome/test/chromedriver/chrome_launcher.cc b/chrome/test/chromedriver/chrome_launcher.cc
index 6987a2644c..c9b0e49054 100644
--- a/chrome/test/chromedriver/chrome_launcher.cc
+++ b/chrome/test/chromedriver/chrome_launcher.cc
@@ -27,6 +27,7 @@
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/chrome_android_impl.h"
#include "chrome/test/chromedriver/chrome/chrome_desktop_impl.h"
+#include "chrome/test/chromedriver/chrome/chrome_existing_impl.h"
#include "chrome/test/chromedriver/chrome/chrome_finder.h"
#include "chrome/test/chromedriver/chrome/device_manager.h"
#include "chrome/test/chromedriver/chrome/devtools_http_client.h"
@@ -35,8 +36,11 @@
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/chrome/user_data_dir.h"
#include "chrome/test/chromedriver/chrome/version.h"
+#include "chrome/test/chromedriver/chrome/web_view.h"
#include "chrome/test/chromedriver/chrome/zip.h"
+#include "chrome/test/chromedriver/net/net_util.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"
+#include "crypto/sha2.h"
namespace {
@@ -78,7 +82,8 @@ Status PrepareCommandLine(int port,
const Capabilities& capabilities,
CommandLine* prepared_command,
base::ScopedTempDir* user_data_dir,
- base::ScopedTempDir* extension_dir) {
+ base::ScopedTempDir* extension_dir,
+ std::vector<std::string>* extension_bg_pages) {
CommandLine command = capabilities.command;
base::FilePath program = command.GetProgram();
if (program.empty()) {
@@ -134,8 +139,11 @@ Status PrepareCommandLine(int port,
return Status(kUnknownError,
"cannot create temp dir for unpacking extensions");
}
- Status status = internal::ProcessExtensions(
- capabilities.extensions, extension_dir->path(), true, &command);
+ Status status = internal::ProcessExtensions(capabilities.extensions,
+ extension_dir->path(),
+ true,
+ &command,
+ extension_bg_pages);
if (status.IsError())
return status;
@@ -144,13 +152,13 @@ Status PrepareCommandLine(int port,
}
Status WaitForDevToolsAndCheckVersion(
- int port,
+ const NetAddress& address,
URLRequestContextGetter* context_getter,
const SyncWebSocketFactory& socket_factory,
Log* log,
scoped_ptr<DevToolsHttpClient>* user_client) {
scoped_ptr<DevToolsHttpClient> client(new DevToolsHttpClient(
- port, context_getter, socket_factory, log));
+ address, context_getter, socket_factory, log));
base::Time deadline = base::Time::Now() + base::TimeDelta::FromSeconds(20);
Status status = client->Init(deadline - base::Time::Now());
if (status.IsError())
@@ -172,6 +180,29 @@ Status WaitForDevToolsAndCheckVersion(
return Status(kUnknownError, "unable to discover open pages");
}
+Status LaunchExistingChromeSession(
+ URLRequestContextGetter* context_getter,
+ const SyncWebSocketFactory& socket_factory,
+ Log* log,
+ const Capabilities& capabilities,
+ ScopedVector<DevToolsEventListener>& devtools_event_listeners,
+ scoped_ptr<Chrome>* chrome) {
+ Status status(kOk);
+ scoped_ptr<DevToolsHttpClient> devtools_client;
+ status = WaitForDevToolsAndCheckVersion(
+ capabilities.use_existing_browser, context_getter, socket_factory, log,
+ &devtools_client);
+ if (status.IsError()) {
+ return Status(kUnknownError, "cannot connect to chrome at " +
+ capabilities.use_existing_browser.ToString(),
+ status);
+ }
+ chrome->reset(new ChromeExistingImpl(devtools_client.Pass(),
+ devtools_event_listeners,
+ log));
+ return Status(kOk);
+}
+
Status LaunchDesktopChrome(
URLRequestContextGetter* context_getter,
int port,
@@ -183,8 +214,13 @@ Status LaunchDesktopChrome(
CommandLine command(CommandLine::NO_PROGRAM);
base::ScopedTempDir user_data_dir;
base::ScopedTempDir extension_dir;
- Status status = PrepareCommandLine(port, capabilities,
- &command, &user_data_dir, &extension_dir);
+ std::vector<std::string> extension_bg_pages;
+ Status status = PrepareCommandLine(port,
+ capabilities,
+ &command,
+ &user_data_dir,
+ &extension_dir,
+ &extension_bg_pages);
if (status.IsError())
return status;
@@ -214,7 +250,7 @@ Status LaunchDesktopChrome(
scoped_ptr<DevToolsHttpClient> devtools_client;
status = WaitForDevToolsAndCheckVersion(
- port, context_getter, socket_factory, log, &devtools_client);
+ NetAddress(port), context_getter, socket_factory, log, &devtools_client);
if (status.IsError()) {
int exit_code;
@@ -250,12 +286,25 @@ Status LaunchDesktopChrome(
}
return status;
}
- chrome->reset(new ChromeDesktopImpl(devtools_client.Pass(),
- devtools_event_listeners,
- log,
- process,
- &user_data_dir,
- &extension_dir));
+ scoped_ptr<ChromeDesktopImpl> chrome_desktop(
+ new ChromeDesktopImpl(devtools_client.Pass(),
+ devtools_event_listeners,
+ log,
+ process,
+ &user_data_dir,
+ &extension_dir));
+ for (size_t i = 0; i < extension_bg_pages.size(); ++i) {
+ scoped_ptr<WebView> web_view;
+ Status status = chrome_desktop->WaitForPageToLoad(
+ extension_bg_pages[i], base::TimeDelta::FromSeconds(10), &web_view);
+ if (status.IsError()) {
+ return Status(kUnknownError,
+ "failed to wait for extension background page to load: " +
+ extension_bg_pages[i],
+ status);
+ }
+ }
+ *chrome = chrome_desktop.Pass();
return Status(kOk);
}
@@ -294,7 +343,7 @@ Status LaunchAndroidChrome(
}
scoped_ptr<DevToolsHttpClient> devtools_client;
- status = WaitForDevToolsAndCheckVersion(port,
+ status = WaitForDevToolsAndCheckVersion(NetAddress(port),
context_getter,
socket_factory,
log,
@@ -311,13 +360,22 @@ Status LaunchAndroidChrome(
Status LaunchChrome(
URLRequestContextGetter* context_getter,
- int port,
const SyncWebSocketFactory& socket_factory,
Log* log,
DeviceManager* device_manager,
const Capabilities& capabilities,
ScopedVector<DevToolsEventListener>& devtools_event_listeners,
scoped_ptr<Chrome>* chrome) {
+ if (capabilities.IsExistingBrowser()) {
+ return LaunchExistingChromeSession(
+ context_getter, socket_factory,
+ log, capabilities, devtools_event_listeners, chrome);
+ }
+
+ int port;
+ if (!FindOpenPort(&port))
+ return Status(kUnknownError, "failed to find an open port for Chrome");
+
if (capabilities.IsAndroid()) {
return LaunchAndroidChrome(
context_getter, port, socket_factory, log, capabilities,
@@ -331,43 +389,137 @@ Status LaunchChrome(
namespace internal {
+void ConvertHexadecimalToIDAlphabet(std::string* id) {
+ for (size_t i = 0; i < id->size(); ++i) {
+ int val;
+ if (base::HexStringToInt(base::StringPiece(id->begin() + i,
+ id->begin() + i + 1),
+ &val)) {
+ (*id)[i] = val + 'a';
+ } else {
+ (*id)[i] = 'a';
+ }
+ }
+}
+
+std::string GenerateExtensionId(const std::string& input) {
+ uint8 hash[16];
+ crypto::SHA256HashString(input, hash, sizeof(hash));
+ std::string output = StringToLowerASCII(base::HexEncode(hash, sizeof(hash)));
+ ConvertHexadecimalToIDAlphabet(&output);
+ return output;
+}
+
+Status GetExtensionBackgroundPage(const base::DictionaryValue* manifest,
+ const std::string& id,
+ std::string* bg_page) {
+ std::string bg_page_name;
+ bool persistent = true;
+ manifest->GetBoolean("background.persistent", &persistent);
+ const base::Value* unused_value;
+ if (manifest->Get("background.scripts", &unused_value))
+ bg_page_name = "_generated_background_page.html";
+ manifest->GetString("background.page", &bg_page_name);
+ manifest->GetString("background_page", &bg_page_name);
+ if (bg_page_name.empty() || !persistent)
+ return Status(kOk);
+ *bg_page = "chrome-extension://" + id + "/" + bg_page_name;
+ return Status(kOk);
+}
+
+Status ProcessExtension(const std::string& extension,
+ const base::FilePath& temp_dir,
+ base::FilePath* path,
+ std::string* bg_page) {
+ // Decodes extension string.
+ // Some WebDriver client base64 encoders follow RFC 1521, which require that
+ // 'encoded lines be no more than 76 characters long'. Just remove any
+ // newlines.
+ std::string extension_base64;
+ RemoveChars(extension, "\n", &extension_base64);
+ std::string decoded_extension;
+ if (!base::Base64Decode(extension_base64, &decoded_extension))
+ return Status(kUnknownError, "cannot base64 decode");
+
+ // Get extension's ID from public key in crx file.
+ // Assumes crx v2. See http://developer.chrome.com/extensions/crx.html.
+ std::string key_len_str = decoded_extension.substr(8, 4);
+ if (key_len_str.size() != 4)
+ return Status(kUnknownError, "cannot extract public key length");
+ uint32 key_len = *reinterpret_cast<const uint32*>(key_len_str.c_str());
+ std::string public_key = decoded_extension.substr(16, key_len);
+ if (key_len != public_key.size())
+ return Status(kUnknownError, "invalid public key length");
+ std::string public_key_base64;
+ if (!base::Base64Encode(public_key, &public_key_base64))
+ return Status(kUnknownError, "cannot base64 encode public key");
+ std::string id = GenerateExtensionId(public_key);
+
+ // Unzip the crx file.
+ base::ScopedTempDir temp_crx_dir;
+ if (!temp_crx_dir.CreateUniqueTempDir())
+ return Status(kUnknownError, "cannot create temp dir");
+ base::FilePath extension_crx = temp_crx_dir.path().AppendASCII("temp.crx");
+ int size = static_cast<int>(decoded_extension.length());
+ if (file_util::WriteFile(extension_crx, decoded_extension.c_str(), size) !=
+ size) {
+ return Status(kUnknownError, "cannot write file");
+ }
+ base::FilePath extension_dir = temp_dir.AppendASCII("extension_" + id);
+ if (!zip::Unzip(extension_crx, extension_dir))
+ return Status(kUnknownError, "cannot unzip");
+
+ // Parse the manifest and set the 'key' if not already present.
+ base::FilePath manifest_path(extension_dir.AppendASCII("manifest.json"));
+ std::string manifest_data;
+ if (!file_util::ReadFileToString(manifest_path, &manifest_data))
+ return Status(kUnknownError, "cannot read manifest");
+ scoped_ptr<base::Value> manifest_value(base::JSONReader::Read(manifest_data));
+ base::DictionaryValue* manifest;
+ if (!manifest_value || !manifest_value->GetAsDictionary(&manifest))
+ return Status(kUnknownError, "invalid manifest");
+ if (!manifest->HasKey("key")) {
+ manifest->SetString("key", public_key_base64);
+ base::JSONWriter::Write(manifest, &manifest_data);
+ if (file_util::WriteFile(
+ manifest_path, manifest_data.c_str(), manifest_data.size()) !=
+ static_cast<int>(manifest_data.size())) {
+ return Status(kUnknownError, "cannot add 'key' to manifest");
+ }
+ }
+
+ // Get extension's background page URL, if there is one.
+ std::string bg_page_tmp;
+ Status status = GetExtensionBackgroundPage(manifest, id, &bg_page_tmp);
+ if (status.IsError())
+ return status;
+
+ *path = extension_dir;
+ if (bg_page_tmp.size())
+ *bg_page = bg_page_tmp;
+ return Status(kOk);
+}
+
Status ProcessExtensions(const std::vector<std::string>& extensions,
const base::FilePath& temp_dir,
bool include_automation_extension,
- CommandLine* command) {
+ CommandLine* command,
+ std::vector<std::string>* bg_pages) {
+ std::vector<std::string> bg_pages_tmp;
std::vector<base::FilePath::StringType> extension_paths;
- size_t count = 0;
- for (std::vector<std::string>::const_iterator it = extensions.begin();
- it != extensions.end(); ++it) {
- std::string extension_base64;
- // Decodes extension string.
- // Some WebDriver client base64 encoders follow RFC 1521, which require that
- // 'encoded lines be no more than 76 characters long'. Just remove any
- // newlines.
- RemoveChars(*it, "\n", &extension_base64);
- std::string decoded_extension;
- if (!base::Base64Decode(extension_base64, &decoded_extension))
- return Status(kUnknownError, "failed to base64 decode extension");
-
- // Writes decoded extension into a temporary .crx file.
- base::ScopedTempDir temp_crx_dir;
- if (!temp_crx_dir.CreateUniqueTempDir())
- return Status(kUnknownError,
- "cannot create temp dir for writing extension CRX file");
- base::FilePath extension_crx = temp_crx_dir.path().AppendASCII("temp.crx");
- int size = static_cast<int>(decoded_extension.length());
- if (file_util::WriteFile(extension_crx, decoded_extension.c_str(), size)
- != size) {
- return Status(kUnknownError, "failed to write extension file");
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ base::FilePath path;
+ std::string bg_page;
+ Status status = ProcessExtension(extensions[i], temp_dir, &path, &bg_page);
+ if (status.IsError()) {
+ return Status(
+ kUnknownError,
+ base::StringPrintf("cannot process extension #%" PRIuS, i + 1),
+ status);
}
-
- // Unzips the temporary .crx file.
- count++;
- base::FilePath extension_dir = temp_dir.AppendASCII(
- base::StringPrintf("extension%" PRIuS, count));
- if (!zip::Unzip(extension_crx, extension_dir))
- return Status(kUnknownError, "failed to unzip the extension CRX file");
- extension_paths.push_back(extension_dir.value());
+ extension_paths.push_back(path.value());
+ if (bg_page.length())
+ bg_pages_tmp.push_back(bg_page);
}
if (include_automation_extension) {
@@ -388,6 +540,7 @@ Status ProcessExtensions(const std::vector<std::string>& extensions,
extension_paths, FILE_PATH_LITERAL(','));
command->AppendSwitchNative("load-extension", extension_paths_value);
}
+ bg_pages->swap(bg_pages_tmp);
return Status(kOk);
}
diff --git a/chrome/test/chromedriver/chrome_launcher.h b/chrome/test/chromedriver/chrome_launcher.h
index 405c275ef3..a226d7eb03 100644
--- a/chrome/test/chromedriver/chrome_launcher.h
+++ b/chrome/test/chromedriver/chrome_launcher.h
@@ -30,7 +30,6 @@ class URLRequestContextGetter;
Status LaunchChrome(
URLRequestContextGetter* context_getter,
- int port,
const SyncWebSocketFactory& socket_factory,
Log* log,
DeviceManager* device_manager,
@@ -42,7 +41,8 @@ namespace internal {
Status ProcessExtensions(const std::vector<std::string>& extensions,
const base::FilePath& temp_dir,
bool include_automation_extension,
- CommandLine* command);
+ CommandLine* command,
+ std::vector<std::string>* bg_pages);
Status PrepareUserDataDir(
const base::FilePath& user_data_dir,
const base::DictionaryValue* custom_prefs,
diff --git a/chrome/test/chromedriver/chrome_launcher_unittest.cc b/chrome/test/chromedriver/chrome_launcher_unittest.cc
index 369fb9c71c..c61346051b 100644
--- a/chrome/test/chromedriver/chrome_launcher_unittest.cc
+++ b/chrome/test/chromedriver/chrome_launcher_unittest.cc
@@ -21,62 +21,80 @@ TEST(ProcessExtensions, NoExtension) {
CommandLine command(CommandLine::NO_PROGRAM);
std::vector<std::string> extensions;
base::FilePath extension_dir;
+ std::vector<std::string> bg_pages;
Status status = internal::ProcessExtensions(extensions, extension_dir,
- false, &command);
+ false, &command, &bg_pages);
ASSERT_TRUE(status.IsOk());
ASSERT_FALSE(command.HasSwitch("load-extension"));
+ ASSERT_EQ(0u, bg_pages.size());
}
-TEST(ProcessExtensions, SingleExtension) {
+bool AddExtensionForInstall(const std::string& relative_path,
+ std::vector<std::string>* extensions) {
base::FilePath source_root;
PathService::Get(base::DIR_SOURCE_ROOT, &source_root);
base::FilePath crx_file_path = source_root.AppendASCII(
- "chrome/test/data/chromedriver/ext_test_1.crx");
+ "chrome/test/data/chromedriver/" + relative_path);
std::string crx_contents;
- ASSERT_TRUE(file_util::ReadFileToString(crx_file_path, &crx_contents));
+ if (!file_util::ReadFileToString(crx_file_path, &crx_contents))
+ return false;
- std::vector<std::string> extensions;
std::string crx_encoded;
- ASSERT_TRUE(base::Base64Encode(crx_contents, &crx_encoded));
- extensions.push_back(crx_encoded);
+ if (!base::Base64Encode(crx_contents, &crx_encoded))
+ return false;
+ extensions->push_back(crx_encoded);
+ return true;
+}
+
+TEST(ProcessExtensions, SingleExtensionWithBgPage) {
+ std::vector<std::string> extensions;
+ ASSERT_TRUE(AddExtensionForInstall("ext_slow_loader.crx", &extensions));
base::ScopedTempDir extension_dir;
ASSERT_TRUE(extension_dir.CreateUniqueTempDir());
CommandLine command(CommandLine::NO_PROGRAM);
+ std::vector<std::string> bg_pages;
Status status = internal::ProcessExtensions(extensions, extension_dir.path(),
- false, &command);
+ false, &command, &bg_pages);
ASSERT_TRUE(status.IsOk());
ASSERT_TRUE(command.HasSwitch("load-extension"));
base::FilePath temp_ext_path = command.GetSwitchValuePath("load-extension");
ASSERT_TRUE(base::PathExists(temp_ext_path));
+ std::string manifest_txt;
+ ASSERT_TRUE(file_util::ReadFileToString(
+ temp_ext_path.AppendASCII("manifest.json"), &manifest_txt));
+ scoped_ptr<base::Value> manifest(base::JSONReader::Read(manifest_txt));
+ ASSERT_TRUE(manifest);
+ base::DictionaryValue* manifest_dict = NULL;
+ ASSERT_TRUE(manifest->GetAsDictionary(&manifest_dict));
+ std::string key;
+ ASSERT_TRUE(manifest_dict->GetString("key", &key));
+ ASSERT_EQ(
+ "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8qhZthEHjTIA3IYMzi79s2KFepVziY0du"
+ "JzHcqRUB/YHSGseIUqcYXGazJhDz/"
+ "4FbRg8ef9fQazL1UbMMGBIf4za1kJ2os2MsRrNXzHslkbtcLVj2VfofhuHJmu+"
+ "CnKJ77UWamJiNAaQSiclu4duwnEWrkx+g/8ChQfhZzC4jvQIDAQAB",
+ key);
+ ASSERT_EQ(1u, bg_pages.size());
+ ASSERT_EQ(
+ "chrome-extension://jijhlkpcmmeckhlgdipjhnchhoabdjae/"
+ "_generated_background_page.html",
+ bg_pages[0]);
}
-TEST(ProcessExtensions, MultipleExtensions) {
- base::FilePath source_root;
- PathService::Get(base::DIR_SOURCE_ROOT, &source_root);
- base::FilePath test_ext_path = source_root.AppendASCII(
- "chrome/test/data/chromedriver");
- base::FilePath test_crx_1 = test_ext_path.AppendASCII("ext_test_1.crx");
- base::FilePath test_crx_2 = test_ext_path.AppendASCII("ext_test_2.crx");
-
- std::string crx_1_contents, crx_2_contents;
- ASSERT_TRUE(file_util::ReadFileToString(test_crx_1, &crx_1_contents));
- ASSERT_TRUE(file_util::ReadFileToString(test_crx_2, &crx_2_contents));
-
+TEST(ProcessExtensions, MultipleExtensionsNoBgPages) {
std::vector<std::string> extensions;
- std::string crx_1_encoded, crx_2_encoded;
- ASSERT_TRUE(base::Base64Encode(crx_1_contents, &crx_1_encoded));
- ASSERT_TRUE(base::Base64Encode(crx_2_contents, &crx_2_encoded));
- extensions.push_back(crx_1_encoded);
- extensions.push_back(crx_2_encoded);
+ ASSERT_TRUE(AddExtensionForInstall("ext_test_1.crx", &extensions));
+ ASSERT_TRUE(AddExtensionForInstall("ext_test_2.crx", &extensions));
base::ScopedTempDir extension_dir;
ASSERT_TRUE(extension_dir.CreateUniqueTempDir());
CommandLine command(CommandLine::NO_PROGRAM);
+ std::vector<std::string> bg_pages;
Status status = internal::ProcessExtensions(extensions, extension_dir.path(),
- false, &command);
+ false, &command, &bg_pages);
ASSERT_TRUE(status.IsOk());
ASSERT_TRUE(command.HasSwitch("load-extension"));
CommandLine::StringType ext_paths = command.GetSwitchValueNative(
@@ -86,6 +104,7 @@ TEST(ProcessExtensions, MultipleExtensions) {
ASSERT_EQ(2u, ext_path_list.size());
ASSERT_TRUE(base::PathExists(base::FilePath(ext_path_list[0])));
ASSERT_TRUE(base::PathExists(base::FilePath(ext_path_list[1])));
+ ASSERT_EQ(0u, bg_pages.size());
}
namespace {
diff --git a/chrome/test/chromedriver/client/chromedriver.py b/chrome/test/chromedriver/client/chromedriver.py
index ac5c478a45..ae2ecd8848 100644
--- a/chrome/test/chromedriver/client/chromedriver.py
+++ b/chrome/test/chromedriver/client/chromedriver.py
@@ -62,7 +62,7 @@ class ChromeDriver(object):
def __init__(self, server_url, chrome_binary=None, android_package=None,
chrome_switches=None, chrome_extensions=None,
- chrome_log_path=None):
+ chrome_log_path=None, chrome_existing_browser=None):
self._executor = command_executor.CommandExecutor(server_url)
options = {}
@@ -83,13 +83,17 @@ class ChromeDriver(object):
assert type(chrome_log_path) is str
options['logPath'] = chrome_log_path
+ if chrome_existing_browser:
+ assert type(chrome_existing_browser) is str
+ options['useExistingBrowser'] = chrome_existing_browser
+
params = {
'desiredCapabilities': {
'chromeOptions': options
}
}
- self._session_id = self._executor.Execute(
+ self._session_id = self._ExecuteCommand(
Command.NEW_SESSION, params)['sessionId']
def _WrapValue(self, value):
@@ -122,12 +126,16 @@ class ChromeDriver(object):
else:
return value
- def ExecuteCommand(self, command, params={}):
- params['sessionId'] = self._session_id
+ def _ExecuteCommand(self, command, params={}):
params = self._WrapValue(params)
response = self._executor.Execute(command, params)
if response['status'] != 0:
raise _ExceptionForResponse(response)
+ return response
+
+ def ExecuteCommand(self, command, params={}):
+ params['sessionId'] = self._session_id
+ response = self._ExecuteCommand(command, params)
return self._UnwrapValue(response['value'])
def GetWindowHandles(self):
diff --git a/chrome/test/chromedriver/commands.cc b/chrome/test/chromedriver/commands.cc
index ac0eeea95f..480c157ee4 100644
--- a/chrome/test/chromedriver/commands.cc
+++ b/chrome/test/chromedriver/commands.cc
@@ -79,10 +79,6 @@ Status CreateSessionOnSessionThreadHelper(
const base::DictionaryValue& params,
const std::string& session_id,
scoped_ptr<base::Value>* out_value) {
- int port;
- if (!FindOpenPort(&port))
- return Status(kUnknownError, "failed to find an open port for Chrome");
-
const base::DictionaryValue* desired_caps;
if (!params.GetDictionary("desiredCapabilities", &desired_caps))
return Status(kUnknownError, "cannot find dict 'desiredCapabilities'");
@@ -102,7 +98,6 @@ Status CreateSessionOnSessionThreadHelper(
scoped_ptr<Chrome> chrome;
status = LaunchChrome(bound_params.context_getter.get(),
- port,
bound_params.socket_factory,
bound_params.log,
bound_params.device_manager,
@@ -124,6 +119,7 @@ Status CreateSessionOnSessionThreadHelper(
session->devtools_logs.swap(devtools_logs);
session->window = web_view_ids.front();
session->detach = capabilities.detach;
+ session->force_devtools_screenshot = capabilities.force_devtools_screenshot;
out_value->reset(session->capabilities->DeepCopy());
lazy_tls_session.Pointer()->Set(session.release());
return Status(kOk);
diff --git a/chrome/test/chromedriver/commands_unittest.cc b/chrome/test/chromedriver/commands_unittest.cc
index 064fb95664..e377d29218 100644
--- a/chrome/test/chromedriver/commands_unittest.cc
+++ b/chrome/test/chromedriver/commands_unittest.cc
@@ -338,7 +338,7 @@ class FindElementWebView : public StubWebView {
TEST(CommandsTest, SuccessfulFindElement) {
FindElementWebView web_view(true, kElementExistsQueryTwice);
Session session("id");
- session.implicit_wait = 1000;
+ session.implicit_wait = base::TimeDelta::FromSeconds(1);
session.SwitchToSubFrame("frame_id1", std::string());
base::DictionaryValue params;
params.SetString("using", "id");
@@ -367,7 +367,7 @@ TEST(CommandsTest, FailedFindElement) {
TEST(CommandsTest, SuccessfulFindElements) {
FindElementWebView web_view(false, kElementExistsQueryTwice);
Session session("id");
- session.implicit_wait = 1000;
+ session.implicit_wait = base::TimeDelta::FromSeconds(1);
session.SwitchToSubFrame("frame_id2", std::string());
base::DictionaryValue params;
params.SetString("using", "name");
@@ -401,7 +401,7 @@ TEST(CommandsTest, FailedFindElements) {
TEST(CommandsTest, SuccessfulFindChildElement) {
FindElementWebView web_view(true, kElementExistsQueryTwice);
Session session("id");
- session.implicit_wait = 1000;
+ session.implicit_wait = base::TimeDelta::FromSeconds(1);
session.SwitchToSubFrame("frame_id3", std::string());
base::DictionaryValue params;
params.SetString("using", "tag name");
@@ -439,7 +439,7 @@ TEST(CommandsTest, FailedFindChildElement) {
TEST(CommandsTest, SuccessfulFindChildElements) {
FindElementWebView web_view(false, kElementExistsQueryTwice);
Session session("id");
- session.implicit_wait = 1000;
+ session.implicit_wait = base::TimeDelta::FromSeconds(1);
session.SwitchToSubFrame("frame_id4", std::string());
base::DictionaryValue params;
params.SetString("using", "class name");
@@ -480,7 +480,7 @@ TEST(CommandsTest, FailedFindChildElements) {
TEST(CommandsTest, TimeoutInFindElement) {
Session session("id");
FindElementWebView web_view(true, kElementExistsTimeout);
- session.implicit_wait = 2;
+ session.implicit_wait = base::TimeDelta::FromMilliseconds(2);
base::DictionaryValue params;
params.SetString("using", "id");
params.SetString("value", "a");
diff --git a/chrome/test/chromedriver/element_commands.cc b/chrome/test/chromedriver/element_commands.cc
index 81e83a36dd..989ed7276b 100644
--- a/chrome/test/chromedriver/element_commands.cc
+++ b/chrome/test/chromedriver/element_commands.cc
@@ -47,8 +47,7 @@ Status SendKeysToElement(
return status;
if (is_focused)
break;
- if ((base::Time::Now() - start_time).InMilliseconds() >=
- session->implicit_wait) {
+ if (base::Time::Now() - start_time >= session->implicit_wait) {
return Status(kElementNotVisible);
}
base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
diff --git a/chrome/test/chromedriver/element_util.cc b/chrome/test/chromedriver/element_util.cc
index 6c4bca00c2..0ba4246886 100644
--- a/chrome/test/chromedriver/element_util.cc
+++ b/chrome/test/chromedriver/element_util.cc
@@ -271,8 +271,7 @@ Status FindElement(
}
}
- if ((base::Time::Now() - start_time).InMilliseconds() >=
- session->implicit_wait) {
+ if (base::Time::Now() - start_time >= session->implicit_wait) {
if (only_one) {
return Status(kNoSuchElement);
} else {
diff --git a/chrome/test/chromedriver/extension/background.js b/chrome/test/chromedriver/extension/background.js
index 56d79464ec..16ea857d15 100644
--- a/chrome/test/chromedriver/extension/background.js
+++ b/chrome/test/chromedriver/extension/background.js
@@ -2,13 +2,49 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+/*
+ * Checks for an extension error that occurred during the asynchronous call.
+ * If an error occurs, will invoke the error callback and throw an exception.
+ *
+ * @param {function(!Error)} errCallback The callback to invoke for error
+ * reporting.
+ */
+function checkForExtensionError(errCallback) {
+ if (typeof(chrome.extension.lastError) != 'undefined') {
+ var error = new Error(chrome.extension.lastError.message);
+ errCallback(error);
+ throw error;
+ }
+}
+
+/**
+ * Captures a screenshot of the visible tab.
+ *
+ * @param {function(string)} callback The callback to invoke with the base64
+ * encoded PNG.
+ * @param {function(!Error)} errCallback The callback to invoke for error
+ * reporting.
+ */
+function captureScreenshot(callback, errCallback) {
+ chrome.tabs.captureVisibleTab({format:'png'}, function(dataUrl) {
+ checkForExtensionError(errCallback);
+ var base64 = ';base64,';
+ callback(dataUrl.substr(dataUrl.indexOf(base64) + base64.length))
+ });
+}
+
/**
* Gets info about the current window.
*
* @param {function(*)} callback The callback to invoke with the window info.
+ * @param {function(!Error)} errCallback The callback to invoke for error
+ * reporting.
*/
-function getWindowInfo(callback) {
- chrome.windows.getCurrent({populate: true}, callback);
+function getWindowInfo(callback, errCallback) {
+ chrome.windows.getCurrent({populate: true}, function(window) {
+ checkForExtensionError(errCallback);
+ callback(window);
+ });
}
/**
@@ -16,9 +52,15 @@ function getWindowInfo(callback) {
*
* @param {Object} updateInfo Update info to pass to chrome.windows.update.
* @param {function()} callback Invoked when the updating is complete.
+ * @param {function(!Error)} errCallback The callback to invoke for error
+ * reporting.
*/
-function updateWindow(updateInfo, callback) {
+function updateWindow(updateInfo, callback, errCallback) {
chrome.windows.getCurrent({}, function(window) {
- chrome.windows.update(window.id, updateInfo, callback);
+ checkForExtensionError(errCallback);
+ chrome.windows.update(window.id, updateInfo, function(window) {
+ checkForExtensionError(errCallback);
+ callback();
+ });
});
}
diff --git a/chrome/test/chromedriver/extension/manifest.json b/chrome/test/chromedriver/extension/manifest.json
index 79319b22f4..f058112b09 100644
--- a/chrome/test/chromedriver/extension/manifest.json
+++ b/chrome/test/chromedriver/extension/manifest.json
@@ -8,6 +8,6 @@
"scripts": ["background.js"]
},
"permissions": [
- "tabs"
+ "tabs", "<all_urls>"
]
}
diff --git a/chrome/test/chromedriver/js/execute_async_script.js b/chrome/test/chromedriver/js/execute_async_script.js
index ac8d5a7f7f..c55c65bbb5 100644
--- a/chrome/test/chromedriver/js/execute_async_script.js
+++ b/chrome/test/chromedriver/js/execute_async_script.js
@@ -68,7 +68,11 @@ function executeAsyncScript(script, args, isUserSupplied, opt_timeoutMillis) {
function reportScriptError(error) {
var code = isUserSupplied ? StatusCode.JAVASCRIPT_ERROR :
(error.code || StatusCode.UNKNOWN_ERROR);
- report(code, error.message);
+ var message = error.message;
+ if (error.stack) {
+ message += "\nJavaScript stack:\n" + error.stack;
+ }
+ report(code, message);
}
args.push(reportValue);
if (!isUserSupplied)
diff --git a/chrome/test/chromedriver/js/execute_async_script_test.html b/chrome/test/chromedriver/js/execute_async_script_test.html
index 48a1cd8b46..d1ebe262ab 100644
--- a/chrome/test/chromedriver/js/execute_async_script_test.html
+++ b/chrome/test/chromedriver/js/execute_async_script_test.html
@@ -52,12 +52,12 @@ function testNonUserScript() {
executeAsyncScript('arguments[2](new Error("ERR"))', [33], false);
assertEquals(StatusCode.UNKNOWN_ERROR, info.result.status);
- assertEquals('ERR', info.result.value);
+ assertEquals(0, info.result.value.indexOf('ERR'));
executeAsyncScript('var e = new Error("ERR"); e.code = 111; arguments[1](e)',
[], false);
assertEquals(111, info.result.status);
- assertEquals('ERR', info.result.value);
+ assertEquals(0, info.result.value.indexOf('ERR'));
}
function testNoResultBeforeTimeout() {
diff --git a/chrome/test/chromedriver/keycode_text_conversion_win.cc b/chrome/test/chromedriver/keycode_text_conversion_win.cc
index 56a912b16f..b51187c85b 100644
--- a/chrome/test/chromedriver/keycode_text_conversion_win.cc
+++ b/chrome/test/chromedriver/keycode_text_conversion_win.cc
@@ -40,8 +40,8 @@ bool ConvertCharToKeyCode(
std::string* error_msg) {
short vkey_and_modifiers = ::VkKeyScanW(key);
bool translated = vkey_and_modifiers != -1 &&
- LOBYTE(vkey_and_modifiers) != -1 &&
- HIBYTE(vkey_and_modifiers) != -1;
+ LOBYTE(vkey_and_modifiers) != 0xFF &&
+ HIBYTE(vkey_and_modifiers) != 0xFF;
*error_msg = std::string();
if (translated) {
*key_code = static_cast<ui::KeyboardCode>(LOBYTE(vkey_and_modifiers));
diff --git a/chrome/test/chromedriver/net/net_util.cc b/chrome/test/chromedriver/net/net_util.cc
index 2bc700624a..490afb8185 100644
--- a/chrome/test/chromedriver/net/net_util.cc
+++ b/chrome/test/chromedriver/net/net_util.cc
@@ -2,12 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "chrome/test/chromedriver/net/net_util.h"
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/stringprintf.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/test/chromedriver/net/url_request_context_getter.h"
#include "net/base/ip_endpoint.h"
@@ -63,6 +66,31 @@ class SyncUrlFetcher : public net::URLFetcherDelegate {
} // namespace
+NetAddress::NetAddress() : port_(-1) {}
+
+NetAddress::NetAddress(int port) : host_("127.0.0.1"), port_(port) {}
+
+NetAddress::NetAddress(const std::string& host, int port)
+ : host_(host), port_(port) {}
+
+NetAddress::~NetAddress() {}
+
+bool NetAddress::IsValid() const {
+ return port_ >= 0 && port_ < (1 << 16);
+}
+
+std::string NetAddress::ToString() const {
+ return host_ + base::StringPrintf(":%d", port_);
+}
+
+const std::string& NetAddress::host() const {
+ return host_;
+}
+
+int NetAddress::port() const {
+ return port_;
+}
+
bool FetchUrl(const std::string& url,
URLRequestContextGetter* getter,
std::string* response) {
diff --git a/chrome/test/chromedriver/net/net_util.h b/chrome/test/chromedriver/net/net_util.h
index 723e748730..bd6a906b22 100644
--- a/chrome/test/chromedriver/net/net_util.h
+++ b/chrome/test/chromedriver/net/net_util.h
@@ -9,6 +9,26 @@
class URLRequestContextGetter;
+class NetAddress {
+ public:
+ NetAddress(); // Creates an invalid address.
+ explicit NetAddress(int port); // Host is set to 127.0.0.1.
+ NetAddress(const std::string& host, int port);
+ ~NetAddress();
+
+ bool IsValid() const;
+
+ // Returns host:port.
+ std::string ToString() const;
+
+ const std::string& host() const;
+ int port() const;
+
+ private:
+ std::string host_;
+ int port_;
+};
+
// Synchronously fetches data from a GET HTTP request to the given URL.
// Returns true if response is 200 OK and sets response body to |response|.
bool FetchUrl(const std::string& url,
diff --git a/chrome/test/chromedriver/net/sync_websocket_impl.cc b/chrome/test/chromedriver/net/sync_websocket_impl.cc
index 88814e4247..2451fcaf23 100644
--- a/chrome/test/chromedriver/net/sync_websocket_impl.cc
+++ b/chrome/test/chromedriver/net/sync_websocket_impl.cc
@@ -72,17 +72,17 @@ bool SyncWebSocketImpl::Core::Send(const std::string& message) {
return success;
}
-SyncWebSocket::StatusCode
-SyncWebSocketImpl::Core::ReceiveNextMessage(
+SyncWebSocket::StatusCode SyncWebSocketImpl::Core::ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) {
base::AutoLock lock(lock_);
base::TimeTicks deadline = base::TimeTicks::Now() + timeout;
+ base::TimeDelta next_wait = timeout;
while (received_queue_.empty() && is_connected_) {
- base::TimeDelta delta = deadline - base::TimeTicks::Now();
- if (delta <= base::TimeDelta())
+ if (next_wait <= base::TimeDelta())
return SyncWebSocket::kTimeout;
- on_update_event_.TimedWait(delta);
+ on_update_event_.TimedWait(next_wait);
+ next_wait = deadline - base::TimeTicks::Now();
}
if (!is_connected_)
return SyncWebSocket::kDisconnected;
diff --git a/chrome/test/chromedriver/net/websocket.cc b/chrome/test/chromedriver/net/websocket.cc
index 4398f9b271..76d17dac75 100644
--- a/chrome/test/chromedriver/net/websocket.cc
+++ b/chrome/test/chromedriver/net/websocket.cc
@@ -4,6 +4,8 @@
#include "chrome/test/chromedriver/net/websocket.h"
+#include <string.h>
+
#include "base/base64.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -17,24 +19,49 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/sys_addrinfo.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/websockets/websocket_frame.h"
+#if defined(OS_WIN)
+#include <Winsock2.h>
+#endif
+
+namespace {
+
+bool ResolveHost(const std::string& host, net::IPAddressNumber* address) {
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+ struct addrinfo* result;
+ if (getaddrinfo(host.c_str(), NULL, &hints, &result))
+ return false;
+
+ for (struct addrinfo* addr = result; addr; addr = addr->ai_next) {
+ if (addr->ai_family == AF_INET || addr->ai_family == AF_INET6) {
+ net::IPEndPoint end_point;
+ if (!end_point.FromSockAddr(addr->ai_addr, addr->ai_addrlen)) {
+ freeaddrinfo(result);
+ return false;
+ }
+ *address = end_point.address();
+ }
+ }
+ freeaddrinfo(result);
+ return true;
+}
+
+} // namespace
+
WebSocket::WebSocket(const GURL& url, WebSocketListener* listener)
: url_(url),
listener_(listener),
state_(INITIALIZED),
write_buffer_(new net::DrainableIOBuffer(new net::IOBuffer(0), 0)),
- read_buffer_(new net::IOBufferWithSize(4096)) {
- net::IPAddressNumber address;
- CHECK(net::ParseIPLiteralToNumber(url_.HostNoBrackets(), &address));
- int port = 80;
- base::StringToInt(url_.port(), &port);
- net::AddressList addresses(net::IPEndPoint(address, port));
- net::NetLog::Source source;
- socket_.reset(new net::TCPClientSocket(addresses, NULL, source));
-}
+ read_buffer_(new net::IOBufferWithSize(4096)) {}
WebSocket::~WebSocket() {
CHECK(thread_checker_.CalledOnValidThread());
@@ -43,6 +70,20 @@ WebSocket::~WebSocket() {
void WebSocket::Connect(const net::CompletionCallback& callback) {
CHECK(thread_checker_.CalledOnValidThread());
CHECK_EQ(INITIALIZED, state_);
+
+ net::IPAddressNumber address;
+ if (!net::ParseIPLiteralToNumber(url_.HostNoBrackets(), &address)) {
+ if (!ResolveHost(url_.HostNoBrackets(), &address)) {
+ callback.Run(net::ERR_ADDRESS_UNREACHABLE);
+ return;
+ }
+ }
+ int port = 80;
+ base::StringToInt(url_.port(), &port);
+ net::AddressList addresses(net::IPEndPoint(address, port));
+ net::NetLog::Source source;
+ socket_.reset(new net::TCPClientSocket(addresses, NULL, source));
+
state_ = CONNECTING;
connect_callback_ = callback;
int code = socket_->Connect(base::Bind(
diff --git a/chrome/test/chromedriver/run_buildbot_steps.py b/chrome/test/chromedriver/run_buildbot_steps.py
index 2b1765dbb3..871011b36e 100755
--- a/chrome/test/chromedriver/run_buildbot_steps.py
+++ b/chrome/test/chromedriver/run_buildbot_steps.py
@@ -5,10 +5,13 @@
"""Runs all the buildbot steps for ChromeDriver except for update/compile."""
+import csv
+import datetime
import optparse
import os
import platform
import shutil
+import StringIO
import subprocess
import sys
import tempfile
@@ -78,6 +81,14 @@ def Download():
os.chmod(os.path.join(build_dir, 'chromedriver2_server'), 0700)
+def GetDownloads():
+ site = 'https://code.google.com/p/chromedriver/downloads/list'
+ s = urllib2.urlopen(site)
+ downloads = s.read()
+ s.close()
+ return downloads
+
+
def MaybeRelease(revision):
# Version is embedded as: const char kChromeDriverVersion[] = "0.1";
# Minimum supported Chrome version is embedded as:
@@ -98,12 +109,7 @@ def MaybeRelease(revision):
zip_name = 'chromedriver_%s%s_%s.zip' % (
util.GetPlatformName(), bitness, version)
- site = 'https://code.google.com/p/chromedriver/downloads/list'
- s = urllib2.urlopen(site)
- downloads = s.read()
- s.close()
-
- if zip_name in downloads:
+ if zip_name in GetDownloads():
return 0
util.MarkBuildStepStart('releasing %s' % zip_name)
@@ -128,7 +134,7 @@ def MaybeRelease(revision):
os.path.join(_THIS_DIR, 'third_party', 'googlecode',
'googlecode_upload.py'),
'--summary',
- 'ChromeDriver server for %s%s (v%s.%s.dyu) supports Chrome v%s-%s' % (
+ 'ChromeDriver server for %s%s (v%s.%s) supports Chrome v%s-%s' % (
util.GetPlatformName(), bitness, version, revision,
chrome_min_version, chrome_max_version),
'--project', 'chromedriver',
@@ -138,6 +144,51 @@ def MaybeRelease(revision):
with open(os.devnull, 'wb') as no_output:
if subprocess.Popen(cmd, stdout=no_output, stderr=no_output).wait():
util.MarkBuildStepError()
+ MaybeUploadReleaseNotes(version)
+
+def MaybeUploadReleaseNotes(version):
+ name_template = 'release_notes_%s.txt'
+ new_name = name_template % version
+ prev_version = '.'.join([version.split('.')[0],
+ str(int(version.split('.')[1]) - 1)])
+ old_name = name_template % prev_version
+
+ fixed_issues = []
+ query = ('https://code.google.com/p/chromedriver/issues/csv?'
+ 'q=status%3AToBeReleased&colspec=ID%20Summary')
+ issues = StringIO.StringIO(urllib2.urlopen(query).read().split('\n', 1)[1])
+ for issue in csv.reader(issues):
+ if not issue:
+ continue
+ id = issue[0]
+ desc = issue[1]
+ labels = issue[2]
+ fixed_issues += ['Resolved issue %s: %s [%s]' % (id, desc, labels)]
+
+ old_notes = urllib2.urlopen(
+ 'https://chromedriver.googlecode.com/files/%s' % old_name).read()
+ new_notes = '----------ChromeDriver v%s (%s)----------\n%s\n\n%s' % (
+ version, datetime.date.today().isoformat(),
+ '\n'.join(fixed_issues),
+ old_notes)
+ release_notes_txt = os.path.join(util.MakeTempDir(), new_name)
+ with open(release_notes_txt, 'w') as f:
+ f.write(new_notes)
+
+ if new_name in GetDownloads():
+ return
+ cmd = [
+ sys.executable,
+ os.path.join(_THIS_DIR, 'third_party', 'googlecode',
+ 'googlecode_upload.py'),
+ '--summary', 'Release notes',
+ '--project', 'chromedriver',
+ '--user', 'chromedriver.bot@gmail.com',
+ release_notes_txt
+ ]
+ with open(os.devnull, 'wb') as no_output:
+ if subprocess.Popen(cmd, stdout=no_output, stderr=no_output).wait():
+ util.MarkBuildStepError()
def KillChromes():
diff --git a/chrome/test/chromedriver/session.cc b/chrome/test/chromedriver/session.cc
index ea6da2cac1..3dc1e01f9b 100644
--- a/chrome/test/chromedriver/session.cc
+++ b/chrome/test/chromedriver/session.cc
@@ -20,31 +20,28 @@ FrameInfo::FrameInfo(const std::string& parent_frame_id,
frame_id(frame_id),
chromedriver_frame_id(chromedriver_frame_id) {}
-const int Session::kDefaultPageLoadTimeoutMs = 5 * 60 * 1000;
+const base::TimeDelta Session::kDefaultPageLoadTimeout =
+ base::TimeDelta::FromMinutes(5);
Session::Session(const std::string& id)
: id(id),
quit(false),
detach(false),
+ force_devtools_screenshot(false),
sticky_modifiers(0),
mouse_position(0, 0),
- implicit_wait(0),
- page_load_timeout(kDefaultPageLoadTimeoutMs),
- script_timeout(0) {
-}
+ page_load_timeout(kDefaultPageLoadTimeout) {}
Session::Session(const std::string& id, scoped_ptr<Chrome> chrome)
: id(id),
quit(false),
detach(false),
+ force_devtools_screenshot(false),
chrome(chrome.Pass()),
sticky_modifiers(0),
mouse_position(0, 0),
- implicit_wait(0),
- page_load_timeout(kDefaultPageLoadTimeoutMs),
- script_timeout(0),
- capabilities(CreateCapabilities()) {
-}
+ page_load_timeout(kDefaultPageLoadTimeout),
+ capabilities(CreateCapabilities()) {}
Session::~Session() {}
diff --git a/chrome/test/chromedriver/session.h b/chrome/test/chromedriver/session.h
index 40ec9e9438..a93c10a123 100644
--- a/chrome/test/chromedriver/session.h
+++ b/chrome/test/chromedriver/session.h
@@ -12,6 +12,7 @@
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
+#include "base/time/time.h"
#include "chrome/test/chromedriver/basic_types.h"
#include "chrome/test/chromedriver/chrome/geoposition.h"
@@ -35,7 +36,7 @@ struct FrameInfo {
};
struct Session {
- static const int kDefaultPageLoadTimeoutMs;
+ static const base::TimeDelta kDefaultPageLoadTimeout;
explicit Session(const std::string& id);
Session(const std::string& id, scoped_ptr<Chrome> chrome);
@@ -51,6 +52,7 @@ struct Session {
const std::string id;
bool quit;
bool detach;
+ bool force_devtools_screenshot;
scoped_ptr<Chrome> chrome;
std::string window;
int sticky_modifiers;
@@ -59,9 +61,9 @@ struct Session {
// this list will be empty.
std::list<FrameInfo> frames;
WebPoint mouse_position;
- int implicit_wait;
- int page_load_timeout;
- int script_timeout;
+ base::TimeDelta implicit_wait;
+ base::TimeDelta page_load_timeout;
+ base::TimeDelta script_timeout;
scoped_ptr<std::string> prompt_text;
scoped_ptr<Geoposition> overridden_geoposition;
// Logs that populate from DevTools events.
diff --git a/chrome/test/chromedriver/session_commands.cc b/chrome/test/chromedriver/session_commands.cc
index 23f362baf4..93bb1ada28 100644
--- a/chrome/test/chromedriver/session_commands.cc
+++ b/chrome/test/chromedriver/session_commands.cc
@@ -212,18 +212,21 @@ Status ExecuteSetTimeout(
if (!params.GetString("type", &type))
return Status(kUnknownError, "'type' must be a string");
- int ms = static_cast<int>(ms_double);
+ base::TimeDelta timeout =
+ base::TimeDelta::FromMilliseconds(static_cast<int>(ms_double));
// TODO(frankf): implicit and script timeout should be cleared
// if negative timeout is specified.
- if (type == "implicit")
- session->implicit_wait = ms;
- else if (type == "script")
- session->script_timeout = ms;
- else if (type == "page load")
+ if (type == "implicit") {
+ session->implicit_wait = timeout;
+ } else if (type == "script") {
+ session->script_timeout = timeout;
+ } else if (type == "page load") {
session->page_load_timeout =
- ((ms < 0) ? Session::kDefaultPageLoadTimeoutMs : ms);
- else
+ ((timeout < base::TimeDelta()) ? Session::kDefaultPageLoadTimeout
+ : timeout);
+ } else {
return Status(kUnknownError, "unknown type of timeout:" + type);
+ }
return Status(kOk);
}
@@ -234,7 +237,8 @@ Status ExecuteSetScriptTimeout(
double ms;
if (!params.GetDouble("ms", &ms) || ms < 0)
return Status(kUnknownError, "'ms' must be a non-negative number");
- session->script_timeout = static_cast<int>(ms);
+ session->script_timeout =
+ base::TimeDelta::FromMilliseconds(static_cast<int>(ms));
return Status(kOk);
}
@@ -245,7 +249,8 @@ Status ExecuteImplicitlyWait(
double ms;
if (!params.GetDouble("ms", &ms) || ms < 0)
return Status(kUnknownError, "'ms' must be a non-negative number");
- session->implicit_wait = static_cast<int>(ms);
+ session->implicit_wait =
+ base::TimeDelta::FromMilliseconds(static_cast<int>(ms));
return Status(kOk);
}
diff --git a/chrome/test/chromedriver/test/run_all_tests.py b/chrome/test/chromedriver/test/run_all_tests.py
index d8d6852895..41c37ee1ee 100755
--- a/chrome/test/chromedriver/test/run_all_tests.py
+++ b/chrome/test/chromedriver/test/run_all_tests.py
@@ -41,7 +41,8 @@ def _GenerateTestCommand(script,
ref_chromedriver=None,
chrome=None,
chrome_version=None,
- android_package=None):
+ android_package=None,
+ verbose=False):
cmd = [
sys.executable,
os.path.join(_THIS_DIR, script),
@@ -54,6 +55,9 @@ def _GenerateTestCommand(script,
if chrome_version:
cmd.append('--chrome-version=' + chrome_version)
+ if verbose:
+ cmd.append('--verbose')
+
if android_package:
cmd.insert(0, 'xvfb-run')
cmd.append('--android-package=' + android_package)
@@ -80,7 +84,8 @@ def RunPythonTests(chromedriver, ref_chromedriver,
def RunJavaTests(chromedriver, chrome=None, chrome_version=None,
- chrome_version_name=None, android_package=None):
+ chrome_version_name=None, android_package=None,
+ verbose=False):
version_info = ''
if chrome_version_name:
version_info = '(%s)' % chrome_version_name
@@ -91,7 +96,8 @@ def RunJavaTests(chromedriver, chrome=None, chrome_version=None,
ref_chromedriver=None,
chrome=chrome,
chrome_version=chrome_version,
- android_package=android_package))
+ android_package=android_package,
+ verbose=verbose))
if code:
util.MarkBuildStepError()
return code
@@ -165,7 +171,8 @@ def main():
android_package=package)
code2 = RunJavaTests(chromedriver,
chrome_version_name=package,
- android_package=package)
+ android_package=package,
+ verbose=True)
code = code or code1 or code2
return code
else:
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index c347ce2cf9..2b01b5af67 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -7,9 +7,12 @@
import base64
import optparse
+import subprocess
import os
import sys
+import socket
import tempfile
+import threading
import time
import unittest
@@ -104,6 +107,7 @@ _ANDROID_NEGATIVE_FILTER['com.google.android.apps.chrome'] = (
'ChromeDriverTest.testWindowSize',
'ChromeDriverTest.testWindowMaximize',
'ChromeLogPathCapabilityTest.testChromeLogPath',
+ 'ExistingBrowserTest.*',
# Don't enable perf testing on Android yet.
'PerfTest.testSessionStartTime',
'PerfTest.testSessionStopTime',
@@ -635,14 +639,32 @@ class ChromeSwitchesCapabilityTest(ChromeDriverBaseTest):
class ChromeExtensionsCapabilityTest(ChromeDriverBaseTest):
"""Tests that chromedriver properly processes chromeOptions.extensions."""
+ def _PackExtension(self, ext_path):
+ return base64.b64encode(open(ext_path, 'rb').read())
+
def testExtensionsInstall(self):
"""Checks that chromedriver can take the extensions."""
crx_1 = os.path.join(_TEST_DATA_DIR, 'ext_test_1.crx')
crx_2 = os.path.join(_TEST_DATA_DIR, 'ext_test_2.crx')
- crx_1_encoded = base64.b64encode(open(crx_1, 'rb').read())
- crx_2_encoded = base64.b64encode(open(crx_2, 'rb').read())
- extensions = [crx_1_encoded, crx_2_encoded]
- self.CreateDriver(chrome_extensions=extensions)
+ self.CreateDriver(chrome_extensions=[self._PackExtension(crx_1),
+ self._PackExtension(crx_2)])
+
+ def testWaitsForExtensionToLoad(self):
+ did_load_event = threading.Event()
+ server = webserver.SyncWebServer()
+ def RunServer():
+ time.sleep(5)
+ server.RespondWithContent('<html>iframe</html>')
+ did_load_event.set()
+
+ thread = threading.Thread(target=RunServer)
+ thread.daemon = True
+ thread.start()
+ crx = os.path.join(_TEST_DATA_DIR, 'ext_slow_loader.crx')
+ driver = self.CreateDriver(
+ chrome_switches=['user-agent=' + server.GetUrl()],
+ chrome_extensions=[self._PackExtension(crx)])
+ self.assertTrue(did_load_event.is_set())
class ChromeLogPathCapabilityTest(ChromeDriverBaseTest):
@@ -670,6 +692,36 @@ class SessionHandlingTest(ChromeDriverBaseTest):
driver.Quit()
+class ExistingBrowserTest(ChromeDriverBaseTest):
+ """Tests for ChromeDriver existing browser capability."""
+ def setUp(self):
+ self.assertTrue(_CHROME_BINARY is not None,
+ 'must supply a chrome binary arg')
+
+ def testConnectToExistingBrowser(self):
+ port = self.FindFreePort()
+ temp_dir = util.MakeTempDir()
+ process = subprocess.Popen([_CHROME_BINARY,
+ '--remote-debugging-port=%d' % port,
+ '--user-data-dir=%s' % temp_dir])
+ if process is None:
+ raise RuntimeError('Chrome could not be started with debugging port')
+ try:
+ hostAndPort = '127.0.0.1:%d' % port
+ driver = self.CreateDriver(chrome_existing_browser=hostAndPort)
+ driver.ExecuteScript('console.info("%s")' % 'connecting at %d!' % port)
+ driver.Quit()
+ finally:
+ process.terminate()
+
+ def FindFreePort(self):
+ for port in range(10000, 10100):
+ try:
+ socket.create_connection(('127.0.0.1', port), 0.2).close()
+ except socket.error:
+ return port
+ raise RuntimeError('Cannot find open port')
+
class PerfTest(ChromeDriverBaseTest):
"""Tests for ChromeDriver perf."""
def setUp(self):
diff --git a/chrome/test/chromedriver/test/webserver.py b/chrome/test/chromedriver/test/webserver.py
index fb48cc5bc7..716e0f4a9b 100644
--- a/chrome/test/chromedriver/test/webserver.py
+++ b/chrome/test/chromedriver/test/webserver.py
@@ -117,6 +117,7 @@ class WebServer(object):
self._root_dir = os.path.abspath(root_dir)
self._server = _BaseServer(self._OnRequest, server_cert_and_key_path)
self._thread = threading.Thread(target=self._server.serve_forever)
+ self._thread.daemon = True
self._thread.start()
self._path_data_map = {}
self._path_data_lock = threading.Lock()
diff --git a/chrome/test/chromedriver/util.cc b/chrome/test/chromedriver/util.cc
index 3bde66eb41..454949e79e 100644
--- a/chrome/test/chromedriver/util.cc
+++ b/chrome/test/chromedriver/util.cc
@@ -117,6 +117,8 @@ class DataOutputStream {
}
void WriteBytes(const void* bytes, int size) {
+ if (!size)
+ return;
size_t next = buffer_.length();
buffer_.resize(next + size);
memcpy(&buffer_[next], bytes, size);
@@ -150,6 +152,8 @@ class DataInputStream {
if (iter_ + length > size_)
return false;
data->resize(length);
+ if (length == 0)
+ return true;
return ReadBytes(&(*data)[0], length);
}
diff --git a/chrome/test/chromedriver/window_commands.cc b/chrome/test/chromedriver/window_commands.cc
index ad62a9ef54..cf376da0af 100644
--- a/chrome/test/chromedriver/window_commands.cc
+++ b/chrome/test/chromedriver/window_commands.cc
@@ -14,6 +14,7 @@
#include "base/time/time.h"
#include "base/values.h"
#include "chrome/test/chromedriver/basic_types.h"
+#include "chrome/test/chromedriver/chrome/automation_extension.h"
#include "chrome/test/chromedriver/chrome/chrome.h"
#include "chrome/test/chromedriver/chrome/devtools_client.h"
#include "chrome/test/chromedriver/chrome/geoposition.h"
@@ -215,18 +216,16 @@ Status ExecuteWindowCommand(
else
break;
}
- nav_status =
- web_view->WaitForPendingNavigations(session->GetCurrentFrameId(),
- session->page_load_timeout);
+ nav_status = web_view->WaitForPendingNavigations(
+ session->GetCurrentFrameId(), session->page_load_timeout, true);
if (nav_status.IsError())
return nav_status;
status = command.Run(session, web_view, params, value);
}
- nav_status =
- web_view->WaitForPendingNavigations(session->GetCurrentFrameId(),
- session->page_load_timeout);
+ nav_status = web_view->WaitForPendingNavigations(
+ session->GetCurrentFrameId(), session->page_load_timeout, true);
if (status.IsOk() && nav_status.IsError() &&
nav_status.code() != kDisconnected &&
@@ -278,7 +277,7 @@ Status ExecuteExecuteAsyncScript(
return web_view->CallUserAsyncFunction(
session->GetCurrentFrameId(), "function(){" + script + "}", *args,
- base::TimeDelta::FromMilliseconds(session->script_timeout), value);
+ session->script_timeout, value);
}
Status ExecuteSwitchToFrame(
@@ -732,10 +731,25 @@ Status ExecuteScreenshot(
WebView* web_view,
const base::DictionaryValue& params,
scoped_ptr<base::Value>* value) {
- std::string screenshot;
- Status status = web_view->CaptureScreenshot(&screenshot);
+ Status status = session->chrome->ActivateWebView(web_view->GetId());
if (status.IsError())
return status;
+
+ std::string screenshot;
+ if (session->chrome->GetType() == Chrome::DESKTOP &&
+ !session->force_devtools_screenshot) {
+ AutomationExtension* extension = NULL;
+ Status status = session->chrome->GetAutomationExtension(&extension);
+ if (status.IsError())
+ return status;
+ status = extension->CaptureScreenshot(&screenshot);
+ if (status.IsError())
+ return status;
+ } else {
+ Status status = web_view->CaptureScreenshot(&screenshot);
+ if (status.IsError())
+ return status;
+ }
value->reset(new base::StringValue(screenshot));
return Status(kOk);
}
diff --git a/chrome/test/functional/PYAUTO_TESTS b/chrome/test/functional/PYAUTO_TESTS
index 9cac8a97ec..d80c8e3814 100644
--- a/chrome/test/functional/PYAUTO_TESTS
+++ b/chrome/test/functional/PYAUTO_TESTS
@@ -218,7 +218,6 @@
'chromeos_browser',
'chromeos_crosh',
'chromeos_file_browser',
- 'chromeos_offline',
'chromeos_power',
'chromeos_prefs',
'chromeos_security',
@@ -274,8 +273,6 @@
'-prefs.PrefsTest.testSessionRestore',
# Deal with i18n chars. crosbug.com/12639
'-omnibox.OmniboxTest.testCrazyFilenames',
- # crosbug.com/16977
- '-chromeos_wifi_sanity.ChromeosWifiSanity.testConnectToHiddenWiFiNonExistent',
# crosbug.com/20025
'-chromeos_browser.ChromeosBrowserTest.testFullScreen',
# Chrome driver does not work in Chrome OS.
@@ -380,15 +377,6 @@
'EMPTY': {
},
- 'CHROMEOS_CONNECTIVITY': {
- 'chromeos': [
- 'chromeos_wifi_functional',
- 'chromeos_wifi_compliance',
- 'wifi_downloads',
- 'wifi_notification',
- ],
- },
-
# ChromeOS flash tests.
'CHROMEOS_FLASH': {
'chromeos': [
@@ -396,28 +384,6 @@
],
},
- # ChromeOS login tests.
- 'CHROMEOS_LOGIN': {
- 'chromeos': [
- 'chromeos_login',
- 'chromeos_oobe',
-
- # crosbug.com/32583
- '-chromeos_login.ChromeosLoginCachedCredentialsUserPod.testCachedCredentialsUserPod',
- ],
- },
-
- # ChromeOS policy tests. Some of these are shared with Desktop Chrome tests
- # but require custom setup on ChromeOS. Others are specific to ChromeOS only.
- 'CHROMEOS_POLICY': {
- 'chromeos': [
- 'chromeos_ephemeral',
- 'chromeos_device_policy',
- 'chromeos_onc',
- 'chromeos_retail_mode',
- ],
- },
-
# ChromeOS volume tests.
'CHROMEOS_VOLUME': {
'chromeos': [
diff --git a/chrome/test/functional/chromeos_cellular_sanity.py b/chrome/test/functional/chromeos_cellular_sanity.py
deleted file mode 100755
index 2f06d48933..0000000000
--- a/chrome/test/functional/chromeos_cellular_sanity.py
+++ /dev/null
@@ -1,31 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import logging
-import os
-import sys
-import time
-
-import pyauto_functional
-import pyauto # pyauto_functional must come before pyauto
-
-class ChromeosCellularSanity(pyauto.PyUITest):
- """Tests for ChromeOS network related functions."""
-
- assert os.popen('modem status').read(), 'Device needs modem to run test.'
-
- def testConnectCellularNetwork(self):
- """Connect to the cellular network if present."""
-
- self.ConnectToCellularNetwork()
- self.assertTrue(self.NetworkScan().get('connected_cellular'),
- 'Failed to connect to cellular network.')
- self.DisconnectFromCellularNetwork()
- self.assertFalse(self.NetworkScan().get('connected_cellular'),
- 'Failed to disconnect from cellular network.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_device_policy.py b/chrome/test/functional/chromeos_device_policy.py
deleted file mode 100644
index b801d656f9..0000000000
--- a/chrome/test/functional/chromeos_device_policy.py
+++ /dev/null
@@ -1,216 +0,0 @@
-# Copyright (c) 2012 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.
-
-import pyauto_functional # Must come before pyauto (and thus, policy_base).
-import policy_base
-
-
-class ChromeosDevicePolicy(policy_base.PolicyTestBase):
- """Tests various ChromeOS device policies."""
-
- # Cache user credentials for easy lookup.
- private_info = policy_base.PolicyTestBase.GetPrivateInfo()
- credentials = (private_info['prod_enterprise_test_user'],
- private_info['prod_enterprise_executive_user'],
- private_info['prod_enterprise_sales_user'])
- _usernames = [credential['username'] for credential in credentials]
- _passwords = [credential['password'] for credential in credentials]
-
- def LoginAsGuest(self):
- self.assertFalse(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged out.')
- policy_base.PolicyTestBase.LoginAsGuest(self)
- self.assertTrue(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged in.')
-
- def _Login(self, user_index, expect_success):
- self.assertFalse(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged out.')
- policy_base.PolicyTestBase.Login(self,
- self._usernames[user_index],
- self._passwords[user_index])
- if expect_success:
- self.assertTrue(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged in.')
- else:
- self.assertFalse(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to not be logged in.')
-
- def _CheckGuestModeAvailableInLoginWindow(self):
- return self.ExecuteJavascriptInOOBEWebUI(
- """window.domAutomationController.send(
- !document.getElementById('guestSignin').hidden);
- """)
-
- def _CheckGuestModeAvailableInAccountPicker(self):
- return self.ExecuteJavascriptInOOBEWebUI(
- """window.domAutomationController.send(
- !!document.getElementById('pod-row').getPodWithUsername_(''));
- """)
-
- def _CheckPodVisible(self, username):
- javascript = """
- var pod = document.getElementById('pod-row').getPodWithUsername_('%s');
- window.domAutomationController.send(!!pod && !pod.hidden);
- """
- return self.ExecuteJavascriptInOOBEWebUI(javascript % username)
-
- def _WaitForPodVisibility(self, username, visible):
- self.assertTrue(
- self.WaitUntil(function=lambda: self._CheckPodVisible(username),
- expect_retval=visible),
- msg='Expected pod for user %s to %s be visible.' %
- (username, '' if visible else 'not'))
-
- def testGuestModeEnabled(self):
- """Checks that guest mode login can be enabled/disabled."""
- self.SetDevicePolicy({'guest_mode_enabled': True})
- self.assertTrue(self._CheckGuestModeAvailableInLoginWindow(),
- msg='Expected guest mode to be available.')
- self.LoginAsGuest()
- self.Logout()
-
- self.SetDevicePolicy({'guest_mode_enabled': False})
- self.assertFalse(self._CheckGuestModeAvailableInLoginWindow(),
- msg='Expected guest mode to not be available.')
-
- # Log in as a regular so that the pod row contains at least one pod and the
- # account picker is shown.
- self._Login(user_index=0, expect_success=True)
- self.Logout()
-
- self.SetDevicePolicy({'guest_mode_enabled': True})
- self.assertTrue(self._CheckGuestModeAvailableInAccountPicker(),
- msg='Expected guest mode to be available.')
- self.LoginAsGuest()
- self.Logout()
-
- self.SetDevicePolicy({'guest_mode_enabled': False})
- self.assertFalse(self._CheckGuestModeAvailableInAccountPicker(),
- msg='Expected guest mode to not be available.')
-
- def testShowUserNamesOnSignin(self):
- """Checks that the account picker can be enabled/disabled."""
- # Log in as a regular user so that the pod row contains at least one pod and
- # the account picker can be shown.
- self._Login(user_index=0, expect_success=True)
- self.Logout()
-
- self.SetDevicePolicy({'show_user_names': False})
- self._WaitForLoginScreenId('gaia-signin')
-
- self.SetDevicePolicy({'show_user_names': True})
- self._WaitForLoginScreenId('account-picker')
-
- def testUserWhitelistAndAllowNewUsers(self):
- """Checks that login can be (dis)allowed by whitelist and allow-new-users.
-
- The test verifies that these two interrelated policies behave as documented
- in the chrome/browser/policy/proto/chrome_device_policy.proto file. Cases
- for which the current behavior is marked as "broken" are intentionally
- ommitted since the broken behavior should be fixed rather than protected by
- tests.
- """
- # No whitelist
- self.SetDevicePolicy({'allow_new_users': True})
- self._Login(user_index=0, expect_success=True)
- self.Logout()
-
- # Empty whitelist
- self.SetDevicePolicy({'user_whitelist': []})
- self._Login(user_index=0, expect_success=True)
- self.Logout()
-
- self.SetDevicePolicy({'allow_new_users': True,
- 'user_whitelist': []})
- self._Login(user_index=0, expect_success=True)
- self.Logout()
-
- # Populated whitelist
- self.SetDevicePolicy({'user_whitelist': [self._usernames[0]]})
- self._Login(user_index=0, expect_success=True)
- self.Logout()
- self._Login(user_index=1, expect_success=False)
-
- self.SetDevicePolicy({'allow_new_users': True,
- 'user_whitelist': [self._usernames[0]]})
- self._Login(user_index=0, expect_success=True)
- self.Logout()
- self._Login(user_index=1, expect_success=True)
- self.Logout()
-
- # New users not allowed, populated whitelist
- self.SetDevicePolicy({'allow_new_users': False,
- 'user_whitelist': [self._usernames[0]]})
- self._Login(user_index=0, expect_success=True)
- self.Logout()
- self._Login(user_index=1, expect_success=False)
-
- def testUserWhitelistInAccountPicker(self):
- """Checks that setting a whitelist removes non-whitelisted user pods."""
- # Disable the account picker so that the login form is shown and the Login()
- # automation call can be used.
- self.PrepareToWaitForLoginFormReload()
- self.SetDevicePolicy({'show_user_names': False})
- self.WaitForLoginFormReload()
-
- # Log in to populate the list of existing users.
- self._Login(user_index=0, expect_success=True)
- self.Logout()
- self._Login(user_index=1, expect_success=True)
- self.Logout()
-
- # Enable the account picker.
- self.SetDevicePolicy({'show_user_names': True})
- self._WaitForLoginScreenId('account-picker')
-
- # Check pod visibility with and without a whitelist.
- self._WaitForPodVisibility(username=self._usernames[0], visible=True)
- self._WaitForPodVisibility(username=self._usernames[1], visible=True)
-
- self.SetDevicePolicy({'show_user_names': True,
- 'user_whitelist': [self._usernames[1]]})
- self._WaitForPodVisibility(username=self._usernames[0], visible=False)
- self._WaitForPodVisibility(username=self._usernames[1], visible=True)
-
- self.SetDevicePolicy({'show_user_names': True})
- self._WaitForPodVisibility(username=self._usernames[0], visible=True)
- self._WaitForPodVisibility(username=self._usernames[1], visible=True)
-
- _timezones = ['America/Barbados', 'Europe/Helsinki']
-
- def testTimezoneSettingWithoutPolicy(self):
- """Without timezone policy, timezone changes by user are persistent."""
- self.SetDevicePolicy(refresh=False)
-
- for timezone in self._timezones:
- self._Login(user_index=1, expect_success=True)
- self.SetTimezone(timezone)
- self.assertEqual(timezone, self.GetTimeInfo()['timezone'])
-
- self.Logout()
- self.assertEqual(timezone, self.GetTimeInfo()['timezone'])
-
-
- def testTimezoneSettingWithPolicy(self):
- """With timezone policy, timezone changes by user are reset on logout."""
- self.SetDevicePolicy({'timezone': self._timezones[0]}, refresh=True)
-
- # Timezones are set on startup, i.e. everytime when loading the login
- # screen. Something like a browser restart may work, too.
- self._Login(user_index=1, expect_success=True)
- self.Logout()
-
- self.assertEqual(self._timezones[0], self.GetTimeInfo()['timezone'])
-
- self._Login(user_index=1, expect_success=True)
- self.SetTimezone(self._timezones[1])
- self.assertEqual(self._timezones[1], self.GetTimeInfo()['timezone'])
-
- self.Logout()
- self.assertEqual(self._timezones[0], self.GetTimeInfo()['timezone'])
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_ephemeral.py b/chrome/test/functional/chromeos_ephemeral.py
deleted file mode 100644
index cffd316f79..0000000000
--- a/chrome/test/functional/chromeos_ephemeral.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright (c) 2012 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.
-
-import logging
-import os
-import sys
-
-import pyauto_functional # Must come before pyauto (and thus, policy_base).
-import policy_base
-
-sys.path.append('/usr/local') # Required to import autotest libs.
-from autotest.cros import constants
-from autotest.cros import cryptohome
-
-
-class ChromeosEphemeral(policy_base.PolicyTestBase):
- """Tests a policy that makes users ephemeral.
-
- When this policy is enabled, no persistent information in the form of
- cryptohome shadow directories or local state prefs should be created for
- users. Additionally, any persistent information previously accumulated should
- be cleared when a user first logs in after enabling the policy."""
-
- _usernames = ('alice@example.com', 'bob@example.com')
-
- def _SetEphemeralUsersEnabled(self, enabled):
- """Sets the ephemeral users device policy.
-
- The show_user_names policy is set to False to ensure that even if the local
- state is not being automatically cleared, the login screen never shows user
- pods. This is required by the Login browser automation call.
- """
- self.SetDevicePolicy({'ephemeral_users_enabled': enabled,
- 'show_user_names': False})
-
- def _DoesVaultDirectoryExist(self, user_index):
- user_hash = cryptohome.get_user_hash(self._usernames[user_index])
- return os.path.exists(os.path.join(constants.SHADOW_ROOT, user_hash))
-
- def _AssertLocalStatePrefsSet(self, user_indexes):
- expected = sorted([self._usernames[index] for index in user_indexes])
- # The OAuthTokenStatus pref is populated asynchronously. Checking whether it
- # is set would lead to an ugly race.
- for pref in ['LoggedInUsers', 'UserImages', 'UserDisplayEmail', ]:
- actual = sorted(self.GetLocalStatePrefsInfo().Prefs(pref))
- self.assertEqual(actual, expected,
- msg='Expected to find prefs in local state for users.')
-
- def _AssertLocalStatePrefsEmpty(self):
- for pref in ['LoggedInUsers',
- 'UserImages',
- 'UserDisplayEmail',
- 'OAuthTokenStatus']:
- self.assertFalse(self.GetLocalStatePrefsInfo().Prefs(pref),
- msg='Expected to not find prefs in local state for any user.')
-
- def _AssertVaultDirectoryExists(self, user_index):
- self.assertTrue(self._DoesVaultDirectoryExist(user_index=user_index),
- msg='Expected vault shadow directory to exist.')
-
- def _AssertVaultDirectoryDoesNotExist(self, user_index):
- self.assertFalse(self._DoesVaultDirectoryExist(user_index=user_index),
- msg='Expected vault shadow directory to not exist.')
-
- def _AssertVaultMounted(self, user_index, ephemeral):
- if ephemeral:
- device_regex = constants.CRYPTOHOME_DEV_REGEX_REGULAR_USER_EPHEMERAL
- fs_regex = constants.CRYPTOHOME_FS_REGEX_TMPFS
- else:
- device_regex = constants.CRYPTOHOME_DEV_REGEX_REGULAR_USER_SHADOW
- fs_regex = constants.CRYPTOHOME_FS_REGEX_ANY
- self.assertTrue(
- cryptohome.is_vault_mounted(device_regex=device_regex,
- fs_regex=fs_regex,
- user=self._usernames[user_index],
- allow_fail=True),
- msg='Expected vault backed by %s to be mounted.' %
- 'tmpfs' if ephemeral else 'shadow directory')
-
- def _AssertNoVaultMounted(self):
- self.assertFalse(cryptohome.is_vault_mounted(allow_fail=True),
- msg='Did not expect any vault to be mounted.')
-
- def Login(self, user_index):
- """Convenience method to login to the usr at the given index."""
- self.assertFalse(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged out.')
- policy_base.PolicyTestBase.Login(self,
- self._usernames[user_index],
- 'dummy_password')
- self.assertTrue(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged in.')
-
- def testEnablingBeforeSession(self):
- """Checks that a new session can be made ephemeral."""
- self.PrepareToWaitForLoginFormReload()
- self._SetEphemeralUsersEnabled(True)
- self.WaitForLoginFormReload()
-
- self.Login(user_index=0)
- self._AssertLocalStatePrefsEmpty()
- self._AssertVaultMounted(user_index=0, ephemeral=True)
- self.Logout()
-
- self._AssertLocalStatePrefsEmpty()
- self._AssertNoVaultMounted()
- self._AssertVaultDirectoryDoesNotExist(user_index=0)
-
- def testEnablingDuringSession(self):
- """Checks that an existing non-ephemeral session is not made ephemeral."""
- self.PrepareToWaitForLoginFormReload()
- self._SetEphemeralUsersEnabled(False)
- self.WaitForLoginFormReload()
-
- self.Login(user_index=0)
- self._AssertLocalStatePrefsSet(user_indexes=[0])
- self._AssertVaultMounted(user_index=0, ephemeral=False)
- self._SetEphemeralUsersEnabled(True)
- self._AssertLocalStatePrefsSet(user_indexes=[0])
- self._AssertVaultMounted(user_index=0, ephemeral=False)
- self.Logout()
-
- self._AssertLocalStatePrefsEmpty()
- self._AssertNoVaultMounted()
- self._AssertVaultDirectoryDoesNotExist(user_index=0)
-
- def testDisablingDuringSession(self):
- """Checks that an existing ephemeral session is not made non-ephemeral."""
- self.PrepareToWaitForLoginFormReload()
- self._SetEphemeralUsersEnabled(True)
- self.WaitForLoginFormReload()
-
- self.Login(user_index=0)
- self._AssertVaultMounted(user_index=0, ephemeral=True)
- self._SetEphemeralUsersEnabled(False)
- self._AssertVaultMounted(user_index=0, ephemeral=True)
- self.Logout()
-
- self._AssertLocalStatePrefsEmpty()
- self._AssertNoVaultMounted()
- self._AssertVaultDirectoryDoesNotExist(user_index=0)
-
- def testEnablingEphemeralUsersCleansUp(self):
- """Checks that persistent information is cleared."""
- self.PrepareToWaitForLoginFormReload()
- self._SetEphemeralUsersEnabled(False)
- self.WaitForLoginFormReload()
-
- self.Login(user_index=0)
- self.Logout()
- self._AssertLocalStatePrefsSet(user_indexes=[0])
-
- self.Login(user_index=1)
- self.Logout()
- self._AssertLocalStatePrefsSet(user_indexes=[0, 1])
-
- self._AssertVaultDirectoryExists(user_index=0)
- self._AssertVaultDirectoryExists(user_index=1)
-
- self._SetEphemeralUsersEnabled(True)
-
- self.Login(user_index=0)
- self._AssertVaultMounted(user_index=0, ephemeral=True)
- self.Logout()
-
- self._AssertVaultDirectoryDoesNotExist(user_index=0)
- self._AssertVaultDirectoryDoesNotExist(user_index=1)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_gsm_compliance.py b/chrome/test/functional/chromeos_gsm_compliance.py
deleted file mode 100755
index 5644356654..0000000000
--- a/chrome/test/functional/chromeos_gsm_compliance.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import subprocess as sub
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-
-class ChromeosGSMCompliance(pyauto.PyUITest):
- """Tests for ChromeOS GSM compliance.
-
- Fakes connection to a network and verifies that the network name is correct.
- """
-
- _ethernet = None
-
- def _GetEthernet(self):
- """Get the ethernet to which the device is connected."""
- result = sub.Popen('ifconfig | cut -d\' \' -f 1 | grep eth',
- stdout=sub.PIPE, shell=True).communicate()
- self.assertNotEqual(result[0], '', msg='Not connected to Ethernet.')
- self._ethernet = result[0].rstrip()
-
- def setUp(self):
- pyauto.PyUITest.setUp(self)
- sub.call(['sudo', 'stop', 'cromo'])
- self._GetEthernet()
- sub.call(['sudo', '/bin/sh', '/usr/local/lib/flimflam/test/backchannel',
- 'setup', self._ethernet, 'pseudo-modem0'])
-
- def tearDown(self):
- if self._ethernet:
- sub.call(['sudo', '/bin/sh', '/usr/local/lib/flimflam/test/backchannel',
- 'teardown', self._ethernet, 'pseudo-modem0'])
- pyauto.PyUITest.tearDown(self)
-
- def _IsFakeGSMRunning(self):
- """Check if fake-gsm-modem is running.
-
- Returns:
- True if fake-gsm-modem process is running and False if not.
- """
- ps = sub.Popen('ps -ef | grep fake-gsm-modem | grep -v grep',
- shell=True, stdout=sub.PIPE).communicate()
- return len(ps[0].split('fake-gsm-modem')) > 0
-
- def _VerifyBasicCarrierCompliance(self, carrier_name, cellular_name):
- """Faking the specified carrier and checking the name.
-
- Args:
- carrier_name: The name of the carrier.
- cellular_name: The name in the icon of the cellular network.
- """
- fake_gsm = sub.Popen(['sudo', '/usr/bin/python',
- '/usr/local/lib/flimflam/test/fake-gsm-modem',
- '-c', carrier_name])
- self.assertTrue(self._IsFakeGSMRunning(), msg='Fake GSM is not running.')
- # Wait for the fake GSM to connect.
- cellular = 'cellular_networks'
- try:
- self.assertTrue(self.WaitUntil(lambda: cellular in
- self.NetworkScan().keys(),timeout=10, retry_sleep=1))
- except AssertionError:
- fake_gsm.terminate()
- self.assertTrue(False, msg='No cellular networks appeared on scan.')
- network_info = self.NetworkScan()[cellular]
- result = any([network_info[key]['name'] == cellular_name
- for key in network_info.keys()])
- fake_gsm.terminate()
- self.assertTrue(result, msg='The cellular network name did not match %s.'
- % cellular_name)
-
- def testConnectThree(self):
- """Testing connection to Three."""
- self._VerifyBasicCarrierCompliance('three', '3')
-
- def testConnectSFR(self):
- """Testing connection to SFR."""
- self._VerifyBasicCarrierCompliance('SFR', 'SFR')
-
- def testConnectKPN(self):
- """Testing connection to KPN."""
- self._VerifyBasicCarrierCompliance('KPN', 'KPN NL')
-
- def testConnectSimyo(self):
- """Testing connection to Simyo."""
- self._VerifyBasicCarrierCompliance('Simyo', 'E-Plus')
-
- def testConnectMovistar(self):
- """Testing connection to Movistar."""
- self._VerifyBasicCarrierCompliance('Movistar', 'Movistar')
-
- def testConnectThreeita(self):
- """Testing connection to threeita."""
- self._VerifyBasicCarrierCompliance('threeita', '3ITA')
-
- def testConnectAtt(self):
- """Testing connection to att."""
- self._VerifyBasicCarrierCompliance('att', 'AT&T')
-
- def testConnectTmobile(self):
- """Testing connection to Tmobile."""
- self._VerifyBasicCarrierCompliance('Tmobile', 'T-Mobile')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_login.py b/chrome/test/functional/chromeos_login.py
deleted file mode 100755
index 786b0716f1..0000000000
--- a/chrome/test/functional/chromeos_login.py
+++ /dev/null
@@ -1,371 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-import subprocess
-import sys
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import pyauto_errors
-import test_utils
-
-
-sys.path.append('/usr/local') # To make autotest libs importable.
-from autotest.cros import cros_ui
-from autotest.cros import cryptohome
-
-
-class ChromeosLogin(pyauto.PyUITest):
- """TestCases for Logging into ChromeOS."""
-
- assert os.geteuid() == 0, 'Need to run this test as root'
-
- def ShouldAutoLogin(self):
- return False
-
- def setUp(self):
- # We want a clean session_manager instance for every run,
- # so restart ui now.
- cros_ui.stop(allow_fail=True)
- cryptohome.remove_all_vaults()
- cros_ui.start(wait_for_login_prompt=False)
- pyauto.PyUITest.setUp(self)
-
- def _ValidCredentials(self, account_type='test_google_account'):
- """Obtains a valid username and password from a data file.
-
- Returns:
- A dictionary with the keys 'username' and 'password'
- """
- return self.GetPrivateInfo()[account_type]
-
- def testExecuteJavascriptInOOBEWebUI(self):
- """Test that javascript can be executed at the login page."""
- msg = 'test success'
- ret = self.ExecuteJavascriptInOOBEWebUI(
- 'window.domAutomationController.send("%s");' % msg)
- self.assertEqual(ret, msg)
-
- def testGoodLogin(self):
- """Test that login is successful with valid credentials."""
- credentials = self._ValidCredentials()
- self.Login(credentials['username'], credentials['password'])
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Login failed.')
-
- def testBadUsername(self):
- """Test that login fails when passed an invalid username."""
- self.assertRaises(
- pyauto_errors.JSONInterfaceError,
- lambda: self.Login('doesnotexist@fakedomain.org', 'badpassword'))
- login_info = self.GetLoginInfo()
- self.assertFalse(login_info['is_logged_in'],
- msg='Login succeeded, with bad credentials.')
-
- def testBadPassword(self):
- """Test that login fails when passed an invalid password."""
- credentials = self._ValidCredentials()
- self.assertRaises(
- pyauto_errors.JSONInterfaceError,
- lambda: self.Login(credentials['username'], 'badpassword'))
- login_info = self.GetLoginInfo()
- self.assertFalse(login_info['is_logged_in'],
- msg='Login succeeded, with bad credentials.')
-
- def testLoginAsGuest(self):
- """Test we can login with guest mode."""
- self.LoginAsGuest()
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Not logged in at all.')
- self.assertTrue(login_info['is_guest'], msg='Not logged in as guest.')
-
- def testLockScreenAfterLogin(self):
- """Test after logging in that the screen can be locked."""
- self.testGoodLogin()
- self.assertFalse(self.GetLoginInfo()['is_screen_locked'],
- msg='Screen is locked, but the screen was not locked.')
- self.LockScreen()
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_screen_locked'], msg='The screen is not '
- 'locked after attempting to lock the screen.')
-
- def testLockAndUnlockScreenAfterLogin(self):
- """Test locking and unlocking the screen after logging in."""
- self.testLockScreenAfterLogin()
- self.UnlockScreen(self._ValidCredentials()['password'])
- login_info = self.GetLoginInfo()
- self.assertFalse(login_info['is_screen_locked'],
- msg='Screen is locked, but it should have been unlocked.')
-
- def testLockAndUnlockScreenAfterLoginWithBadPassword(self):
- """Test locking and unlocking the screen with the wrong password."""
- self.testLockScreenAfterLogin()
- self.UnlockScreen('not_the_right_password')
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_screen_locked'],
- msg='Screen is unlock, but it should have been unlocked '
- 'since we attempted to unlock with a bad password')
-
- def testLoginToCreateNewAccount(self):
- """Test we can login as a guest and create a new account."""
- self.ShowCreateAccountUI()
- # The login hook does not wait for the first tab to load, so we wait here.
- self.assertTrue(
- self.WaitUntil(self.GetActiveTabTitle, expect_retval='Google Accounts'),
- msg='Could not verify that the Accounts tab was opened.')
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_guest'], msg='Not logged in as guest.')
-
- def testGoodLoginForTransitionedDomainAccount(self):
- """Test that login is successful with valid credentials for a domain.
-
- ChromeOS only allows GA+ accounts to login, there are also known as
- transitioned accounts.
-
- """
- credentials = self._ValidCredentials(account_type='test_domain_account')
- self.Login(credentials['username'], credentials['password'])
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Login failed.')
-
- def testNavigateAfterLogin(self):
- """Test that page navigation is successful after logging in."""
- self.testGoodLogin()
- self.NavigateToURL("http://www.google.com")
- self.assertEqual(self.GetActiveTabTitle(), 'Google',
- msg='Unable to navigate to Google and verify tab title.')
-
- def testSigningOutFromLockedScreen(self):
- """Test logout can be performed from the lock screen."""
- self.testLockScreenAfterLogin()
- self.SignoutInScreenLocker()
- self.assertFalse(self.GetLoginInfo()['is_logged_in'],
- msg='Still logged in when we should be logged out.')
-
- def testLoginSequenceSanity(self):
- """Test that the interface can maintain a connection after multiple logins.
-
- This test is to verify the stability of the automation interface.
-
- """
- self.testGoodLogin()
- self.Logout()
- self.testBadPassword()
- self.testLoginAsGuest()
- self.Logout()
- self.testLoginToCreateNewAccount()
-
- def testLogoutWithNoWindows(self):
- """Verify logout when no browser windows are present."""
- self.testGoodLogin()
- for i in range(5):
- self.OpenNewBrowserWindow(True)
- for _ in range(self.GetBrowserWindowCount()):
- self.CloseBrowserWindow(0)
- self.assertEqual(0, self.GetBrowserWindowCount(),
- msg='Could not close all browser windows')
- self.Logout()
- self.testGoodLogin()
-
- def testInitialLoginState(self):
- """Verify basic state of browser windows at initial login."""
- self.testGoodLogin()
- # Should have 1 browser window with 1 tab.
- info = self.GetBrowserInfo()
- self.assertEqual(1, len(info['windows']))
- self.assertFalse(info['windows'][0]['incognito'],
- msg='Did not expect incognito window after login')
- self.assertEqual(1, len(info['windows'][0]['tabs']))
-
- self.OpenNewBrowserWindow(True)
- # Should have 2 regular browser windows.
- info = self.GetBrowserInfo()
- self.assertEqual(2, len(info['windows']))
- self.assertFalse(info['windows'][0]['incognito'])
- self.assertFalse(info['windows'][1]['incognito'],
- msg='Expected a regular new window.')
-
- def testProfilePreservedBetweenLogins(self):
- """Verify that profile is preserved between two login sessions.
-
- Also verify Local State.
- """
- self.testGoodLogin()
-
- # Build up some history and setup state in "Local State".
- url = self.GetHttpURLForDataPath('title2.html')
- self.NavigateToURL(url)
- # chromeos often takes a while to register URLs into history.
- self.assertTrue(self.WaitUntil(lambda: self.GetHistoryInfo().History()),
- msg='Could not open %s successfully' % url)
- open('/home/chronos/__magic__', 'w').close()
- open('/home/chronos/user/__magic__', 'w').close()
-
- def _VerifyProfile():
- history = self.GetHistoryInfo().History()
- self.assertEqual(1, len(history))
- self.assertEqual(url, history[0]['url'])
- self.assertTrue(os.path.exists('/home/chronos/__magic__'),
- msg='/home/chronos/__magic__ did not persist across login sessions')
- self.assertTrue(os.path.exists('/home/chronos/user/__magic__'),
- msg='/home/chronos/user/__magic__ did not persist across '
- 'login sessions')
-
- _VerifyProfile()
- self.Logout()
- self.testGoodLogin() # Re-login with same account.
- _VerifyProfile()
-
- def testGuestCrosh(self):
- """Verify we can use crosh in guest mode."""
- self.LoginAsGuest()
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Not logged in at all.')
- self.assertTrue(login_info['is_guest'], msg='Not logged in as guest.')
- for _ in range(self.GetBrowserWindowCount()):
- self.CloseBrowserWindow(0)
- test_utils.OpenCroshVerification(self)
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ',
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Run a crosh command.
- self.SendKeysToHterm('help\\n')
- self.WaitForHtermText(text='help_advanced',
- msg='Could not find "help_advanced" in help output.')
-
- # Exit crosh and close tab.
- self.SendKeysToHterm('exit\\n')
- self.WaitForHtermText(text='command crosh completed with exit code 0',
- msg='Could not exit crosh.')
-
- def testCroshPreservedBetweenLogins(self):
- """Verify user can continue after re-login."""
- self.testGoodLogin()
- self.CloseBrowserWindow(0)
- test_utils.OpenCroshVerification(self)
-
- # Verify crosh prompt.
- self.WaitForHtermText(text='crosh> ',
- msg='Could not find "crosh> " prompt')
- self.assertTrue(
- self.GetHtermRowsText(start=0, end=2).endswith('crosh> '),
- msg='Could not find "crosh> " prompt')
-
- # Open 2 other tabs.
- self.AppendTab(self.GetHttpURLForDataPath('title2.html'))
- self.assertEqual('Title Of Awesomeness', self.GetActiveTabTitle(),
- msg='Unable to naviage to title2.html and '
- 'verify tab title.')
- self.AppendTab(self.GetHttpURLForDataPath('settings', 'image_page.html'))
- self.assertEqual('Show an image', self.GetActiveTabTitle(),
- msg='Unable to navigate to image_page and '
- 'verify tab title.')
- self.Logout()
- self.testGoodLogin() # Re-Login with same account.
-
- # Verify 3 tabs are still open after re-login.
- self.assertEqual(3, len(self.GetBrowserInfo()['windows'][0]['tabs']))
-
-
-class ChromeosLoginCachedCredentialsAddUser(pyauto.PyUITest):
- """TestCase for failing to add a user with invalid proxy settings."""
- assert os.geteuid() == 0, 'Need to run this test as root'
-
- def ShouldAutoLogin(self):
- return False
-
- def setUp(self):
- # We want a clean session_manager instance for every run,
- # so restart ui now.
- cros_ui.stop(allow_fail=True)
- cryptohome.remove_all_vaults()
- cros_ui.start(wait_for_login_prompt=False)
- pyauto.PyUITest.setUp(self)
-
- def tearDown(self):
- self.ResetProxySettingsOnChromeOS()
- pyauto.PyUITest.tearDown(self)
-
- def _ValidCredentials(self, account_type='test_google_account'):
- """Obtains a valid username and password from a data file.
-
- Returns:
- A dictionary with the keys 'username' and 'password'
- """
- return self.GetPrivateInfo()[account_type]
-
- def testCachedCredentialsAddUser(self):
- self.SetSharedProxies(True)
- proxy_config = {
- 'mode': 'fixed_servers',
- 'server': '127.0.0.1'
- }
- self.SetProxySettingOnChromeOS(proxy_config);
-
- """Test that login fails."""
- credentials = self._ValidCredentials()
- self.assertRaises(
- pyauto_errors.JSONInterfaceError,
- lambda: self.Login(credentials['username'],
- credentials['password'])
- )
-
-class ChromeosLoginCachedCredentialsUserPod(ChromeosLogin):
- """TestCase for Logging into ChromeOS with cached credentials and
- invalid proxy settings.
- """
- assert os.geteuid() == 0, 'Need to run this test as root'
-
- def ShouldAutoLogin(self):
- return False
-
- def setUp(self):
- # We want a clean session_manager instance for every run,
- # so restart ui now.
- cros_ui.stop(allow_fail=True)
- cryptohome.remove_all_vaults()
- cros_ui.start(wait_for_login_prompt=False)
- pyauto.PyUITest.setUp(self)
-
- def tearDown(self):
- self.ResetProxySettingsOnChromeOS()
- pyauto.PyUITest.tearDown(self)
-
- def _ValidCredentials(self, account_type='test_google_account'):
- """Obtains a valid username and password from a data file.
-
- Returns:
- A dictionary with the keys 'username' and 'password'
- """
- return self.GetPrivateInfo()[account_type]
-
- def testCachedCredentialsUserPod(self):
- """Test that we can login without connectivity if we have so before.
-
- This test is currently disabled because testGoodLogin tries to
- add a user after setting proxies, which is supposed to fail. To
- make it pass we need a hook that simply calls Login on the delegate
- in webui_login_display.cc ::ShowSigninScreenForCreds.
- """
- self.testGoodLogin()
- self.Logout()
- self.SetSharedProxies(True)
- proxy_config = {
- 'mode': 'fixed_servers',
- 'server': '127.0.0.1'
- }
- self.SetProxySettingOnChromeOS(proxy_config);
- self.testGoodLogin()
- self.ResetProxySettingsOnChromeOS()
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_offline.py b/chrome/test/functional/chromeos_offline.py
deleted file mode 100755
index a4120800cb..0000000000
--- a/chrome/test/functional/chromeos_offline.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import pyauto_functional
-import pyauto
-
-
-class TestOffline(pyauto.PyUITest):
- """Tests the offline detection for ChromeOS."""
-
- assert pyauto.PyUITest.IsChromeOS(), 'Works on ChromeOS only.'
-
- def tearDown(self):
- self.RestoreOnline()
- pyauto.PyUITest.tearDown(self)
-
- def testGoOffline(self):
- """Tests the GoOffline pyauto method."""
-
- self.GoOffline()
- # Device takes a little bit of time to realize it's offline/online.
- self.assertTrue(self.WaitUntil(
- lambda: self.NetworkScan().get('offline_mode')),
- msg='We are not offline.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_onc.py b/chrome/test/functional/chromeos_onc.py
deleted file mode 100755
index 1a7d7e001b..0000000000
--- a/chrome/test/functional/chromeos_onc.py
+++ /dev/null
@@ -1,144 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-
-import pyauto_functional # must come before pyauto.
-import policy_base
-import pyauto
-
-
-class ChromeosONC(policy_base.PolicyTestBase):
- """
- Tests for Open Network Configuration (ONC).
-
- Open Network Configuration (ONC) files is a json dictionary
- that contains network configurations and is pulled via policies.
- These tests verify that ONC files that are formatted correctly
- add the network/certificate to the device.
- """
-
- ONC_PATH = os.path.join(pyauto.PyUITest.ChromeOSDataDir(), 'network')
-
- def setUp(self):
- self.CleanupFlimflamDirsOnChromeOS()
- policy_base.PolicyTestBase.setUp(self)
- self.LoginWithTestAccount()
-
- def _ReadONCFileAndSet(self, filename):
- """Reads the specified ONC file and sends it as a policy.
-
- Inputs:
- filename: The filename of the ONC file. ONC files should
- all be stored in the path defined by ONC_PATH.
- """
- with open(os.path.join(self.ONC_PATH, filename)) as fp:
- self.SetUserPolicy({'OpenNetworkConfiguration': fp.read()})
-
- def _VerifyRememberedWifiNetworks(self, wifi_expect):
- """Verify the list of remembered networks contains those in wifi_expect.
-
- Inputs:
- wifi_expect: A dictionary of wifi networks where the key is the ssid
- and the value is the encryption type of the network.
- """
- # Sometimes there is a race condition where upon restarting chrome
- # NetworkScan has not populated the network lists yet. We should
- # scan until the device is online.
- self.WaitUntil(lambda: not self.NetworkScan().get('offline_mode', True))
- networks = self.NetworkScan()
-
- # Temprorary dictionary to keep track of which wifi networks
- # have been visited by removing them as we see them.
- wifi_expect_temp = dict(wifi_expect)
-
- for service, wifi_dict in networks['remembered_wifi'].iteritems():
- if isinstance(wifi_dict, dict) and \
- 'encryption' in wifi_dict and \
- 'name' in wifi_dict:
-
- msg = ('Wifi network %s was in the remembered_network list but '
- 'shouldn\'t be.' % wifi_dict['name'])
-
- # wifi_dict['encryption'] will always be a string and not None.
- self.assertTrue(wifi_expect.get(wifi_dict['name'], None) ==
- wifi_dict['encryption'], msg)
-
- del wifi_expect_temp[wifi_dict['name']]
-
- # Error if wifi_expect_temp is not empty.
- self.assertFalse(wifi_expect_temp, 'The following networks '
- 'were not remembered: %s' % self.pformat(wifi_expect_temp))
-
- def testONCAddOpenWifi(self):
- """Test adding open network."""
- wifi_networks = {
- 'ssid-none': '',
- }
-
- self._ReadONCFileAndSet('toplevel_wifi_open.onc')
- self._VerifyRememberedWifiNetworks(wifi_networks)
-
- def testONCAddWEPWifi(self):
- """Test adding WEP network."""
- wifi_networks = {
- 'ssid-wep': 'WEP',
- }
-
- self._ReadONCFileAndSet('toplevel_wifi_wep_proxy.onc')
- self._VerifyRememberedWifiNetworks(wifi_networks)
-
- def testONCAddPSKWifi(self):
- """Test adding WPA network."""
- wifi_networks = {
- 'ssid-wpa': 'WPA',
- }
- self._ReadONCFileAndSet('toplevel_wifi_wpa_psk.onc')
- self._VerifyRememberedWifiNetworks(wifi_networks)
-
- def testAddBacktoBackONC(self):
- """Test adding three different ONC files one after the other."""
- test_dict = {
- 'toplevel_wifi_open.onc': { 'ssid-none': '' },
- 'toplevel_wifi_wep_proxy.onc': { 'ssid-wep': 'WEP' },
- 'toplevel_wifi_wpa_psk.onc': { 'ssid-wpa': 'WPA' },
- }
-
- for onc, wifi_networks in test_dict.iteritems():
- self._ReadONCFileAndSet(onc)
- self._VerifyRememberedWifiNetworks(wifi_networks)
-
- def testAddBacktoBackONC2(self):
- """Test adding three different ONC files one after the other.
-
- Due to inconsistent behaviors as addressed in crosbug.com/27862
- this test does not perform a network scan/verification between
- the setting of policies.
- """
-
- wifi_networks = {
- 'ssid-wpa': 'WPA',
- }
-
- self._ReadONCFileAndSet('toplevel_wifi_open.onc')
- self._ReadONCFileAndSet('toplevel_wifi_wep_proxy.onc')
- self._ReadONCFileAndSet('toplevel_wifi_wpa_psk.onc')
-
- # Verify that only the most recent onc is updated.
- self._VerifyRememberedWifiNetworks(wifi_networks)
-
- def testAddONCWithUnknownFields(self):
- """Test adding an ONC file with unknown fields."""
- wifi_networks = {
- 'ssid-none': '',
- 'ssid-wpa': 'WPA'
- }
-
- self._ReadONCFileAndSet('toplevel_with_unknown_fields.onc')
- self._VerifyRememberedWifiNetworks(wifi_networks)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_oobe.py b/chrome/test/functional/chromeos_oobe.py
deleted file mode 100755
index d7804d8ae8..0000000000
--- a/chrome/test/functional/chromeos_oobe.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-import subprocess
-import sys
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-
-
-sys.path.append('/usr/local') # To make autotest libs importable.
-from autotest.cros import cros_ui
-from autotest.cros import cryptohome
-
-
-class ChromeosOOBE(pyauto.PyUITest):
- """TestCases for ChromeOS OOBE wizard flow."""
-
- assert os.geteuid() == 0, 'Need to run this test as root'
-
- def ShouldOOBESkipToLogin(self):
- """Do not skip OOBE."""
- return False
-
- def setUp(self):
- # We want a clean session_manager instance for every run,
- # so restart ui now.
- cros_ui.stop(allow_fail=True)
- cryptohome.remove_all_vaults()
- cros_ui.start(wait_for_login_prompt=False)
- pyauto.PyUITest.setUp(self)
-
- def _AssertCurrentScreen(self, screen_name):
- """Verifies current OOBE screen.
-
- Args:
- screen_name: expected current screen name.
- """
- self.assertEqual(screen_name, self.GetOOBEScreenInfo()['screen_name'])
-
- def testBasicFlow(self):
- """Test that basic OOBE flow works."""
- self._AssertCurrentScreen('network')
- # Network -> EULA (on Google Chrome builds, Update on Chromium).
- ret = self.AcceptOOBENetworkScreen()
- if self.GetBrowserInfo()['properties']['branding'] == 'Google Chrome':
- self.assertEquals('eula', ret['next_screen'])
- self._AssertCurrentScreen('eula')
- # EULA (accepted) -> Update.
- ret = self.AcceptOOBEEula(accepted=True)
- # Update may have already been completed, so don't check for it.
- # Update (canceled) -> Login.
- ret = self.CancelOOBEUpdate()
- self.assertEquals('login', ret['next_screen'])
- self._AssertCurrentScreen('login')
- # Login -> User picker.
- credentials = self.GetPrivateInfo()['test_google_account']
- self.Login(credentials['username'], credentials['password'])
- login_info = self.GetLoginInfo()
- self.assertTrue(login_info['is_logged_in'], msg='Login after OOBE failed.')
- # User Picker -> normal browser session.
- ret = self.PickUserImage(3)
- self.assertEquals('session', ret['next_screen'])
- # Should have 1 browser windows ("Getting started").
- self.assertEqual(1, len(self.GetBrowserInfo()['windows']))
- # Verify user image selection.
- self.assertEqual(3, self.GetLoginInfo()['user_image'])
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_retail_mode.py b/chrome/test/functional/chromeos_retail_mode.py
deleted file mode 100644
index 133e6625b5..0000000000
--- a/chrome/test/functional/chromeos_retail_mode.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (c) 2012 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.
-
-import pyauto_functional # Must come before pyauto (and thus, policy_base).
-import policy_base
-
-
-class ChromeosRetailMode(policy_base.PolicyTestBase):
- """Tests for retail mode."""
-
- # The inherited setUp() method fakes enterprise enrollment. Setting the mode
- # to 'kiosk' causes enrollment into retail mode instead of the default
- # enterprise mode.
- mode = 'kiosk'
- machine_id = 'KIOSK'
-
- def ShouldOOBESkipToLogin(self):
- # There's no OOBE to skip.
- return False
-
- def _CheckOnRetailModeLoginScreen(self):
- """Checks that the retail mode login screen is visible."""
- return self.ExecuteJavascriptInOOBEWebUI(
- """window.domAutomationController.send(
- !!document.getElementById('demo-login-text'));
- """)
-
- def Login(self):
- """Login to retail mode by simulating a mouse click."""
- self.ExecuteJavascriptInOOBEWebUI(
- """var event = document.createEvent("MouseEvent");
- event.initMouseEvent('click', true, true, window, 0, 0, 0, 0, 0,
- false, false, false, false, 0, null);
- window.domAutomationController.send(
- document.getElementById('page').dispatchEvent(event));
- """)
-
- def testLogin(self):
- """Tests retail mode login."""
- self.assertTrue(self._CheckOnRetailModeLoginScreen(),
- msg='Expected to be on the retail mode login screen.')
-
- self.Login()
- self.assertTrue(self.GetLoginInfo()['is_logged_in'],
- msg='Expected to be logged in.')
- self.Logout()
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_txt_msg_functional.py b/chrome/test/functional/chromeos_txt_msg_functional.py
deleted file mode 100755
index 9019e24b7a..0000000000
--- a/chrome/test/functional/chromeos_txt_msg_functional.py
+++ /dev/null
@@ -1,161 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-from email.MIMEText import MIMEText
-import logging
-import os
-import re
-import smtplib
-import sys
-import urllib
-
-import pyauto_functional
-import pyauto
-
-sys.path.append(os.path.join(pyauto.PyUITest.DataDir(), 'pyauto_private',
- 'chromeos', 'network'))
-from gsm_sim_info import SIM, PROVIDER_TXT_SERVER
-
-
-class ChromeosTxtMsgSanity(pyauto.PyUITest):
- """Tests for ChromeOS text message handling"""
-
- def _SendText(self, mail_server, sender, phone_number,
- mobile_provider, msg):
- """Sends a text message to a specific phone
-
- Args:
- mail_server: An SMTP instance.
- sender: Sender's email address.
- phone_number: The phone number the txt message is directed to.
- mobile_provider: A cellular provider defined in
- gsm_sim_info.PROVIDER_TXT_SERVER
- msg: The message to be sent.
-
- """
- recipient = ('%s@%s' % (phone_number,
- PROVIDER_TXT_SERVER[mobile_provider]))
- self._SendMail(mail_server, sender, recipient, None, msg)
-
- def _SendMail(self, mail_server, sender, recipients,
- msg_subject, msg_body):
- """Sends an email using the provided smtp connection
-
- Args:
- mail_server: An SMTP instace.
- sender: Senders email address.
- recipients: Recipients email address.
- msg_subject: The subject line of the email.
- msg_body: The body of the email.
- """
- msg = MIMEText(msg_body)
- msg['To'] = recipients
- msg['From'] = sender
- if msg_subject:
- msg['Subject'] = msg_subject
- mail_server.sendmail(sender, recipients, msg.as_string())
-
- def _GetGmailServerInstance(self, email, password):
- """Creates an SMTP connection with the gmail mail server
-
- Args:
- email: A gmail address.
- password: The password for the gmail address.
-
- Returns:
- An SMTP connection instance.
- """
- mail_server = smtplib.SMTP('smtp.gmail.com', 587)
- mail_server.starttls()
- mail_server.ehlo()
- mail_server.login(email, password)
- return mail_server
-
- def _GetIMSI(self):
- """Obtains the IMSI by running modem status
-
- Returns:
- IMSI of device
- """
- modem_status = os.popen('modem status').read()
- imsi = re.search('IMSI:\s(\d+)', modem_status)
- if not imsi:
- raise Exception('GSM Modem not detected in device')
- return imsi.groups()[0]
-
- def _GetSIMInfo(self):
- """Returns information necessary to send messages
-
- Returns:
- A dictionary with the following format
- {
- 'mdn' : <phone number>,
- 'carrier': <carrier name>
- }
- """
- imsi = self._GetIMSI()
- sim_info = SIM.get(imsi, {})
- if not sim_info:
- raise Exception('Phone number for sim with IMSI=%s is not '
- 'recognized within config file' % imsi)
- return sim_info
-
- def setUp(self):
- # Connect to cellular service if not already connected.
- pyauto.PyUITest.setUp(self)
- connected_cellular = self.NetworkScan().get('connected_cellular')
- if not connected_cellular:
- self.ConnectToCellularNetwork()
- if not self.NetworkScan().get('connected_cellular'):
- raise Exception('Could not connect to cellular service.')
- else:
- logging.debug('Already connected to cellular service %s' %
- connected_cellular)
-
- # Obtain sender, recipient, and SMTP instance.
- self.credentials = self.GetPrivateInfo()['test_account_with_smtp']
- self.sim = self._GetSIMInfo()
- self.mail_server = self._GetGmailServerInstance(
- self.credentials['username'],
- self.credentials['password'])
-
- def tearDown(self):
- self.DisconnectFromCellularNetwork()
- self.mail_server.close()
- for window in range(len(self.GetActiveNotifications())):
- self.CloseNotification(window)
- pyauto.PyUITest.tearDown(self)
-
- def testTxtMsgNotification(self):
- """Notifications are displayed for text messages"""
- msg = 'This is the text message'
- self._SendText(self.mail_server, self.credentials['username'],
- self.sim['mdn'], self.sim['carrier'], msg)
- self.WaitForNotificationCount(1)
- notification_result = self.GetActiveNotifications()[0]['content_url']
- self.assertTrue(re.search(urllib.pathname2url(msg),
- notification_result), 'Invalid message was displayed. '
- 'Expected "%s" but did not find it"' % msg)
-
- def testLongTxtMsgNotification(self):
- """Notifications are displayed for long (>160 char) text messages."""
- long_msg = 'This is a really long message with spaces. Testing to '\
- 'make sure that chromeos is able to catch it and '\
- 'create a notifications for this message.'
- self._SendText(self.mail_server, self.credentials['username'],
- self.sim['mdn'], self.sim['carrier'], long_msg)
- self.WaitForNotificationCount(1)
-
- # GetActiveNotifications throws an exception if the text message never
- # arrives.
- txt_msg = self.GetActiveNotifications()[0]
- txt_msg = txt_windows[0]['content_url']
- self.assertTrue(re.search(urllib.pathname2url(long_msg),
- txt_msg), 'Invalid message was displayed. '
- 'Expected "%s" but did not find it"' % long_msg)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_vpn.py b/chrome/test/functional/chromeos_vpn.py
deleted file mode 100755
index 2cecf727cb..0000000000
--- a/chrome/test/functional/chromeos_vpn.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import os
-import subprocess
-
-import pyauto_functional
-import pyauto
-import chromeos_network
-
-
-class PrivateNetworkTest(chromeos_network.PyNetworkUITest):
- """Tests for VPN.
-
- Expected to be run with access to the lab setup as defined in
- vpn_testbed_config.
- """
-
- def _PingTest(self, hostname, timeout=10):
- """Attempt to ping a remote host.
-
- Returns:
- True if the ping succeeds.
- False otherwise.
- """
- return subprocess.call(['ping', '-c', '1', '-W',
- str(timeout), hostname]) == 0
-
- def testCanAddNetwork(self):
- """Test to add a VPN network, connect and disconnect."""
- # Load VPN config data from file.
- vpn_info_file = os.path.join(pyauto.PyUITest.DataDir(),
- 'pyauto_private/chromeos/network',
- 'vpn_testbed_config')
- self.assertTrue(os.path.exists(vpn_info_file))
- vpn = self.EvalDataFrom(vpn_info_file)
-
- # Connect to wifi.
- self.NetworkScan()
- self.WaitUntilWifiNetworkAvailable(vpn['wifi'])
- wifi_vpn = self.GetServicePath(vpn['wifi'])
- self.assertTrue(wifi_vpn)
- self.assertTrue(self.ConnectToWifiNetwork(wifi_vpn) is None)
- self.assertFalse(self._PingTest(vpn['ping']),
- msg='VPN ping succeeded when not connected.')
-
- # Connect to the VPN.
- self.AddPrivateNetwork(hostname=vpn['hostname'],
- service_name=vpn['service_name'],
- provider_type=vpn['provider_type'],
- username=vpn['username'],
- password=vpn['password'],
- key=vpn['key'])
-
- # Get private network info.
- result = self.GetPrivateNetworkInfo()
- self.assertTrue('connected' in result, msg='Could not connect to VPN')
- connected = result['connected']
- self.assertTrue(self._PingTest(vpn['ping']), msg='VPN ping failed.')
- self.DisconnectFromPrivateNetwork()
- self.assertFalse(self._PingTest(vpn['ping']),
- msg='VPN ping succeeded when not connected.')
- # Connect to the remembered private network.
- self.ConnectToPrivateNetwork(connected)
- self.assertTrue(self._PingTest(vpn['ping']), msg='VPN ping failed.')
- self.DisconnectFromPrivateNetwork()
- self.assertFalse(self._PingTest(vpn['ping']),
- msg='VPN ping succeeded when not connected.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_wifi_compliance.py b/chrome/test/functional/chromeos_wifi_compliance.py
deleted file mode 100755
index 9e6d04b7a8..0000000000
--- a/chrome/test/functional/chromeos_wifi_compliance.py
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import pyauto_functional
-import chromeos_network # pyauto_functional must come before chromeos_network
-
-
-class ChromeosWifiCompliance(chromeos_network.PyNetworkUITest):
- """Tests for ChromeOS wifi complaince.
-
- These tests should be run within vacinity of the power strip where the wifi
- routers are attached.
- """
-
- def _BasicConnectRouterCompliance(self, router_name):
- """Generic basic test routine for connecting to a router.
-
- Args:
- router_name: The name of the router.
- """
- self.InitWifiPowerStrip()
- router = self.GetRouterConfig(router_name)
- self.RouterPower(router_name, True)
-
- # If the wifi network is expected to be invisible, the following
- # line should timeout which is expected.
- wifi_visible = self.WaitUntilWifiNetworkAvailable(router['ssid'],
- is_hidden=router.get('hidden'))
-
- # Note, we expect wifi_visible and 'hidden' status to be opposites.
- # The test fails if the network visibility is not as expected.
- if wifi_visible == router.get('hidden', False):
- self.fail('We expected wifi network "%s" to be %s, but it was not.' %
- (router['ssid'],
- {True: 'hidden', False: 'visible'}[router.get('hidden',
- False)]))
-
- # Verify connect did not have any errors.
- error = self.ConnectToWifiRouter(router_name)
- self.assertFalse(error, 'Failed to connect to wifi network %s. '
- 'Reason: %s.' % (router['ssid'], error))
-
- # Verify the network we connected to.
- ssid = self.GetConnectedWifi()
- self.assertEqual(ssid, router['ssid'],
- 'Did not successfully connect to wifi network %s.' % ssid)
-
- self.DisconnectFromWifiNetwork()
-
- def testConnectBelkinG(self):
- """Test connecting to the Belkin G router."""
- self._BasicConnectRouterCompliance('Belkin_G')
-
- def testConnectBelkinNPlus(self):
- """Test connecting to the Belkin N+ router."""
- self._BasicConnectRouterCompliance('Belkin_N+')
-
- def testConnectDLinkN150(self):
- """Test connecting to the D-Link N150 router."""
- self._BasicConnectRouterCompliance('D-Link_N150')
-
- def testConnectLinksysE3000(self):
- """Test connecting to the Linksys E3000 router.
-
- The LinksysE3000 supports broadcasting of up to 2 SSID's.
- This test will try connecting to each of them one at a time.
- """
- self._BasicConnectRouterCompliance('LinksysE3000')
- self._BasicConnectRouterCompliance('LinksysE3000_2')
-
- def testConnectLinksysWRT54G2(self):
- """Test connecting to the Linksys WRT54G2 router."""
- self._BasicConnectRouterCompliance('Linksys_WRT54G2')
-
- def testConnectLinksysWRT54GL(self):
- """Test connecting to the LinksysWRT54GL router."""
- self._BasicConnectRouterCompliance('Linksys_WRT54GL')
-
- def testConnectNetgearN300(self):
- """Test connecting to the Netgear N300 router."""
- self._BasicConnectRouterCompliance('Netgear_N300')
-
- def testConnectNetgearWGR614(self):
- """Test connecting to the Netgear WGR 614 router."""
- self._BasicConnectRouterCompliance('Netgear_WGR614')
-
- def testConnectNfiniti(self):
- """Test connecting to the Nfiniti router."""
- self._BasicConnectRouterCompliance('Nfiniti')
-
- def testConnectSMCWBR145(self):
- """Test connecting to the SMC WBR 145 router."""
- self._BasicConnectRouterCompliance('SMC_WBR145')
-
- def testConnectTrendnet_639gr(self):
- """Test connecting to the Trendnet 639gr router.
-
- The LinksysE3000 supports broadcasting of up to 4 SSID's.
- This test will try connecting to each of them one at a time.
- """
- self._BasicConnectRouterCompliance('Trendnet_639gr')
- self._BasicConnectRouterCompliance('Trendnet_639gr_2')
- self._BasicConnectRouterCompliance('Trendnet_639gr_3')
- self._BasicConnectRouterCompliance('Trendnet_639gr_4')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/chromeos_wifi_functional.py b/chrome/test/functional/chromeos_wifi_functional.py
deleted file mode 100755
index 0cd941f759..0000000000
--- a/chrome/test/functional/chromeos_wifi_functional.py
+++ /dev/null
@@ -1,191 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import os
-import test_utils
-
-import pyauto_functional
-import chromeos_network # pyauto_functional must come before chromeos_network
-import pyauto_utils
-
-
-class ChromeosWifiFunctional(chromeos_network.PyNetworkUITest):
- """Tests for ChromeOS wifi functionality.
-
- These tests should be run within vacinity of the power strip where the wifi
- routers are attached.
- """
-
- def setUp(self):
- chromeos_network.PyNetworkUITest.setUp(self)
- if self.GetLoginInfo().get('is_logged_in'):
- self.Logout()
-
- def _SetupRouter(self, router_name):
- """Turn on the router and wait for it to come on.
-
- Args:
- router_name: The name of the router as defined in wifi_testbed_config.
-
- Returns:
- A dictionary of the router and its attributes. The format is same as
- the definition in wifi_testbed_config
- """
- self.InitWifiPowerStrip()
- router = self.GetRouterConfig(router_name)
- self.RouterPower(router_name, True)
-
- # When we connect to a wifi service, it should be added to the
- # remembered_wifi list.
- self.WaitUntilWifiNetworkAvailable(router['ssid'],
- is_hidden=router.get('hidden'))
- return router
-
- def _VerifyIfConnectedToNetwork(self, network_ssid, status='Online state'):
- """Verify if we are connected to the network.
-
- The test calling this function will fail for one of these three reasons:
- 1. The server path for the SSID is not found.
- 2. If we are not connected to the network.
- 3. If we did not find the network in the wifi_networks list.
-
- Args:
- newtork_ssid: The network to which we are supposed to be connected to.
- status: The status that we expect the network to have, by default it
- would be 'Online state'.
- """
- service_path = self.GetServicePath(network_ssid)
- self.assertTrue(service_path is not None,
- msg='Could not find a service path for the given ssid %s.' %
- network_ssid)
- wifi_network = self.NetworkScan()['wifi_networks']
- for path in wifi_network:
- if path == service_path:
- self.assertTrue(
- wifi_network[path]['status'] == status,
- msg='Unexpected network status %s, Network %s should have '
- 'status %s.' % (wifi_network[path]['status'],
- network_ssid, status))
- break;
- else:
- self.fail(msg='Did not find the network %s in the '
- 'wifi_networks list.' % network_ssid)
-
- def testConnectShareEncryptedNetwork(self):
- """A shared encrypted network can connect and is remembered.
-
- Note: This test does not verify that the network is added to the public
- profile
- """
- router_name = 'D-Link_N150'
- test_utils.LoginToDevice(self)
- router = self._SetupRouter(router_name)
- error = self.ConnectToWifiRouter(router_name, shared=True)
- self.assertFalse(error, 'Failed to connect to wifi network %s. '
- 'Reason: %s.' % (router['ssid'], error))
- service_path = self.GetServicePath(router['ssid'])
- self.assertTrue(service_path in self.GetNetworkInfo()['remembered_wifi'],
- 'Connected wifi was not added to the remembered list.')
- self.ForgetWifiNetwork(service_path)
- self.assertFalse(service_path in self.GetNetworkInfo()['remembered_wifi'],
- 'Connected wifi was not removed from the remembered list.')
-
- def testConnectNoShareEncryptedNetwork(self):
- """A non-shared encrypted network can connect and is remembered.
-
- Note: This test does not verify that the network is added to the private
- profile
- """
- router_name = 'D-Link_N150'
- test_utils.LoginToDevice(self)
- router = self._SetupRouter(router_name)
- error = self.ConnectToWifiRouter(router_name, shared=False)
- self.assertFalse(error, 'Failed to connect to wifi network %s. '
- 'Reason: %s.' % (router['ssid'], error))
- service_path = self.GetServicePath(router['ssid'])
- self.assertTrue(service_path in self.GetNetworkInfo()['remembered_wifi'],
- 'Connected wifi was not added to the remembered list.')
- self.ForgetWifiNetwork(service_path)
- self.assertFalse(service_path in self.GetNetworkInfo()['remembered_wifi'],
- 'Connected wifi was not removed from the remembered list.')
-
- def testConnectToSharedOpenNetwork(self):
- """Can connect to a shared open network.
-
- Verify that the connected network is in the remembered network list
- for all the users.
- """
- router_name = 'Trendnet_639gr_4'
- test_utils.LoginToDevice(self)
- router = self._SetupRouter(router_name)
- error = self.ConnectToWifiRouter(router_name)
- self.assertFalse(error, msg='Failed to connect to wifi network %s. '
- 'Reason: %s.' % (router['ssid'], error))
- service_path = self.GetServicePath(router['ssid'])
- self.assertTrue(service_path in self.GetNetworkInfo()['remembered_wifi'],
- msg='Open wifi is not remembered for the current user.')
- self.Logout()
- test_utils.LoginToDevice(self, test_account='test_google_account_2')
- self.assertTrue(service_path in self.NetworkScan()['remembered_wifi'],
- msg='Open network is not shared with other users.')
-
- def testConnectToSharedHiddenNetwork(self):
- """Can connect to shared hidden network and verify that it's shared."""
- router_name = 'Netgear_WGR614'
- test_utils.LoginToDevice(self)
- router = self._SetupRouter(router_name)
- error = self.ConnectToWifiRouter(router_name)
- self.assertFalse(error, msg='Failed to connect to hidden network %s. '
- 'Reason: %s.' % (router['ssid'], error))
- service_path = self.GetServicePath(router['ssid'])
- self.assertTrue(service_path in self.NetworkScan()['remembered_wifi'],
- msg='Hidden network is not added to the remembered list.')
- self.Logout()
- test_utils.LoginToDevice(self, test_account='test_google_account_2')
- self.assertTrue(service_path in self.NetworkScan()['remembered_wifi'],
- msg='Shared hidden network is not in other user\'s '
- 'remembered list.')
-
- def testConnectToNonSharedHiddenNetwork(self):
- """Can connect to a non-shared hidden network.
-
- Verify that it is not shared with other users.
- """
- router_name = 'Linksys_WRT54GL'
- test_utils.LoginToDevice(self)
- router = self._SetupRouter(router_name)
- error = self.ConnectToWifiRouter(router_name, shared=False)
- self.assertFalse(error, msg='Failed to connect to hidden network %s. '
- 'Reason: %s.' % (router['ssid'], error))
- service_path = self.GetServicePath(router['ssid'])
- self.assertTrue(service_path in self.NetworkScan()['remembered_wifi'],
- msg='Hidden network is not added to the remembered list.')
- self.Logout()
- test_utils.LoginToDevice(self, test_account='test_google_account_2')
- self.assertFalse(service_path in self.NetworkScan()['remembered_wifi'],
- msg='Non-shared hidden network %s is shared.'
- % router['ssid'])
-
- def testConnectToEncryptedNetworkInLoginScreen(self):
- """Can connect to encrypted network in login screen.
-
- Verify that this network is in the remembered list after login.
- """
- router_name = 'Belkin_G'
- if self.GetLoginInfo()['is_logged_in']:
- self.Logout()
- router = self._SetupRouter(router_name)
- error = self.ConnectToWifiRouter(router_name)
- self.assertFalse(error, 'Failed to connect to wifi network %s. '
- 'Reason: %s.' % (router['ssid'], error))
- service_path = self.GetServicePath(router['ssid'])
- self._VerifyIfConnectedToNetwork(router['ssid'], 'Connected')
- test_utils.LoginToDevice(self)
- self.assertTrue(service_path in self.NetworkScan()['remembered_wifi'],
- msg='Network is not added to the remembered list.')
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/webpagereplay.py b/chrome/test/functional/webpagereplay.py
index 6d2dc5ca74..0cfba58cf5 100755
--- a/chrome/test/functional/webpagereplay.py
+++ b/chrome/test/functional/webpagereplay.py
@@ -35,6 +35,7 @@ def GetChromeFlags(replay_host, http_port, https_port):
'--ignore-certificate-errors',
]
+
# Signal masks on Linux are inherited from parent processes. If anything
# invoking us accidentally masks SIGINT (e.g. by putting a process in the
# background from a shell script), sending a SIGINT to the child will fail
@@ -43,10 +44,12 @@ def GetChromeFlags(replay_host, http_port, https_port):
def ResetInterruptHandler():
signal.signal(signal.SIGINT, signal.SIG_DFL)
+
class ReplayError(Exception):
"""Catch-all exception for the module."""
pass
+
class ReplayNotFoundError(ReplayError):
def __init__(self, label, path):
self.args = (label, path)
@@ -55,6 +58,7 @@ class ReplayNotFoundError(ReplayError):
label, path = self.args
return 'Path does not exist for %s: %s' % (label, path)
+
class ReplayNotStartedError(ReplayError):
pass
@@ -78,6 +82,7 @@ class ReplayServer(object):
WPR_RECORD: if set, puts Web Page Replay in record mode instead of replay.
WPR_REPLAY_DIR: path to alternate Web Page Replay source.
"""
+
def __init__(self, archive_path, replay_host, http_port, https_port,
replay_options=None, replay_dir=None,
log_path=None):
@@ -88,7 +93,7 @@ class ReplayServer(object):
replay_options: an iterable of options strings to forward to replay.py.
replay_dir: directory that has replay.py and related modules.
log_path: a path to a log file.
- """
+ """
self.archive_path = os.environ.get('WPR_ARCHIVE_PATH', archive_path)
self.replay_options = list(replay_options or ())
self.replay_dir = os.environ.get('WPR_REPLAY_DIR', replay_dir or REPLAY_DIR)
@@ -116,6 +121,7 @@ class ReplayServer(object):
def _AddDefaultReplayOptions(self):
"""Set WPR command-line options. Can be overridden if needed."""
self.replay_options += [
+ '--host', str(self._replay_host),
'--port', str(self._http_port),
'--ssl_port', str(self._https_port),
'--use_closest_match',
@@ -140,9 +146,9 @@ class ReplayServer(object):
# The process has exited.
break
try:
- up_url = '%s://localhost:%s/web-page-replay-generate-200'
- http_up_url = up_url % ('http', self._http_port)
- https_up_url = up_url % ('https', self._https_port)
+ up_url = '%s://%s:%s/web-page-replay-generate-200'
+ http_up_url = up_url % ('http', self._replay_host, self._http_port)
+ https_up_url = up_url % ('https', self._replay_host, self._https_port)
if (200 == urllib.urlopen(http_up_url, None, {}).getcode() and
200 == urllib.urlopen(https_up_url, None, {}).getcode()):
return True
@@ -154,14 +160,14 @@ class ReplayServer(object):
"""Start Web Page Replay and verify that it started.
Raises:
- ReplayNotStartedError if Replay start-up fails.
+ ReplayNotStartedError: if Replay start-up fails.
"""
cmd_line = [sys.executable, self.replay_py]
cmd_line.extend(self.replay_options)
cmd_line.append(self.archive_path)
self.log_fh = self._OpenLogFile()
logging.debug('Starting Web-Page-Replay: %s', cmd_line)
- kwargs = { 'stdout': self.log_fh, 'stderr': subprocess.STDOUT }
+ kwargs = {'stdout': self.log_fh, 'stderr': subprocess.STDOUT}
if sys.platform.startswith('linux') or sys.platform == 'darwin':
kwargs['preexec_fn'] = ResetInterruptHandler
self.replay_process = subprocess.Popen(cmd_line, **kwargs)
@@ -173,14 +179,32 @@ class ReplayServer(object):
def StopServer(self):
"""Stop Web Page Replay."""
if self.replay_process:
- logging.debug('Stopping Web-Page-Replay')
- # Use a SIGINT so that it can do graceful cleanup. On Windows, we are left
- # with no other option than terminate().
+ logging.debug('Trying to stop Web-Page-Replay gracefully')
try:
- self.replay_process.send_signal(signal.SIGINT)
- except:
- self.replay_process.terminate()
- self.replay_process.wait()
+ url = 'http://localhost:%s/web-page-replay-command-exit'
+ urllib.urlopen(url % self._http_port, None, {})
+ except IOError:
+ # IOError is possible because the server might exit without response.
+ pass
+
+ start_time = time.time()
+ while time.time() - start_time < 10: # Timeout after 10 seconds.
+ if self.replay_process.poll() is not None:
+ break
+ time.sleep(1)
+ else:
+ try:
+ # Use a SIGINT so that it can do graceful cleanup.
+ self.replay_process.send_signal(signal.SIGINT)
+ except: # pylint: disable=W0702
+ # On Windows, we are left with no other option than terminate().
+ if 'no-dns_forwarding' not in self.replay_options:
+ logging.warning('DNS configuration might not be restored!')
+ try:
+ self.replay_process.terminate()
+ except: # pylint: disable=W0702
+ pass
+ self.replay_process.wait()
if self.log_fh:
self.log_fh.close()
diff --git a/chrome/test/functional/wifi_downloads.py b/chrome/test/functional/wifi_downloads.py
deleted file mode 100755
index f998934c1b..0000000000
--- a/chrome/test/functional/wifi_downloads.py
+++ /dev/null
@@ -1,201 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 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.
-
-import hashlib
-import logging
-import os
-import time
-import urllib2
-
-import pyauto_functional # Must be imported before pyauto
-import pyauto
-import pyauto_utils
-import chromeos_network
-
-
-MAX_WAIT_TIME_IN_MSEC = 15 * 60 * 1000
-
-
-class WifiDownloadsTest(chromeos_network.PyNetworkUITest):
- """TestCase for ChromeOS Wifi Downloads
-
- This test makes a few assumptions. It needs to have access to the power
- strip used in pyautolib/chromeos/wifi_downloads.py. It also assumes access
- to the server 172.22.12.98:8080. If the server is passed a filname in the
- format <integer>.lf, it will generate a file of size <integer> in KB. In
- addition the name of the file returned is the md5 checksum of the file.
-
- In addition the download times are written to a file in
- /tmp/wifi_download_time.csv. All times are appended to the file if it
- already exists.
- """
-
- def setUp(self):
- chromeos_network.PyNetworkUITest.setUp(self)
- self.InitWifiPowerStrip()
- # The power strip is a shared resource and if we every crash in the middle
- # of a test we will be in an unknown state. This returns us to 'all off'.
- self.TurnOffAllRouters()
- # Downloading files of a large size, can take a while, bump the timeout
- self.changer = pyauto.PyUITest.ActionTimeoutChanger(self, 4 * 1000 * 60)
- self.log_file_path = '/tmp/wifi_download_time.csv'
-
- def _WriteTimeToFile(self, output_file, router_name, file_size, dl_time):
- """Write or append a time into a csv file.
-
- This method will create or append the amount of time a download took for a
- given filesize and router to a file at the given path.
-
- The format of the output file is as follows:
- <router name A>,<file size A>,time,time,time,time,time,time,time,time
- <router name A>,<file size B>,time,time,time,time,time,time,time,time
- <router name B>,<file size C>,time,time,time,time,time,time,time,time
-
- Args:
- output_file: the complete path of the file to write to
- file_size: the size of the file, this is the row header
- dl_time: the amount of time in seconds
- """
- file_data = []
- if os.path.exists(output_file):
- file_handle = open(output_file)
- lines = file_handle.readlines()
- file_handle.close()
- # Convert the file to a full data structure.
- for line in lines:
- values = line.strip().split(',')
- file_data.append(values)
- for values in file_data:
- found_existing_time = False
- if values[0] == router_name and values[1] == file_size:
- values.append('%2.2f' % dl_time)
- found_existing_time = True
- break
- if not found_existing_time:
- new_line = [router_name, file_size, ('%2.2f' % dl_time)]
- file_data.append(new_line)
- else:
- file_data = [[router_name, file_size, ('%2.2f' % dl_time)]]
- # Write the data back out
- file_handle = open(output_file, 'w')
- for line in file_data:
- if len(line) > 2:
- file_handle.write(','.join(line))
- file_handle.write('\n')
- file_handle.close()
-
- def _Md5Checksum(self, file_path):
- """Returns the md5 checksum of a file at a given path.
-
- Args:
- file_path: The complete path of the file to generate the md5 checksum for.
- """
- file_handle = open(file_path, 'rb')
- m = hashlib.md5()
- while True:
- data = file_handle.read(8192)
- if not data:
- break
- m.update(data)
- file_handle.close()
- return m.hexdigest()
-
- def _ConnectToRouterAndVerify(self, router_name):
- """Generic routine for connecting to a router.
-
- Args:
- router_name: The name of the router to connect to.
- """
- router = self.GetRouterConfig(router_name)
- self.RouterPower(router_name, True)
-
- self.assertTrue(self.WaitUntilWifiNetworkAvailable(router['ssid']),
- 'Wifi network %s never showed up.' % router['ssid'])
-
- # Verify connect did not have any errors.
- error = self.ConnectToWifiRouter(router_name)
- self.assertFalse(error, 'Failed to connect to wifi network %s. '
- 'Reason: %s.' % (router['ssid'], error))
-
- # Verify the network we connected to.
- ssid = self.GetConnectedWifi()
- self.assertEqual(ssid, router['ssid'],
- 'Did not successfully connect to wifi network %s.' % ssid)
-
- def _DownloadAndVerifyFile(self, download_url):
- """Downloads a file at a given URL and validates it
-
- This method downloads a file from a server whose filename matches the md5
- checksum. Then we manually generate the md5 and check it against the
- filename.
-
- Args:
- download_url: URL of the file to download.
-
- Returns:
- The download time in seconds.
- """
- start = time.time()
- # Make a copy of the download directory now to work around segfault
- downloads_dir = self.GetDownloadDirectory().value()
- try:
- self.DownloadAndWaitForStart(download_url)
- except AssertionError:
- # We need to redo this since the external server may not respond the
- # first time.
- logging.info('Could not start download. Retrying ...')
- self.DownloadAndWaitForStart(download_url)
- # Maximum wait time is set as 15 mins as an 100MB file may take somewhere
- # between 8-12 mins to download.
- self.WaitForAllDownloadsToComplete(timeout=MAX_WAIT_TIME_IN_MSEC)
- end = time.time()
- logging.info('Download took %2.2f seconds to complete' % (end - start))
- downloaded_files = os.listdir(downloads_dir)
- self.assertEquals(len(downloaded_files), 1,
- msg='Expected only one file in the Downloads folder. '
- 'but got this instead: %s' % ', '.join(downloaded_files))
- filename = os.path.splitext(downloaded_files[0])[0]
- file_path = os.path.join(self.GetDownloadDirectory().value(),
- downloaded_files[0])
- md5_sum = self._Md5Checksum(file_path)
- md5_url = download_url[:-4] + '.md5' # replacing .slf with .md5
- md5_file = urllib2.urlopen(md5_url).readlines()[0]
- self.assertTrue(md5_file.rstrip().endswith(md5_sum.encode()),
- msg='Unexpected checksum. The download is incomplete.')
- return end - start
-
- def testDownload1MBFile(self):
- """Test downloading a 1MB file from a wireless router."""
- download_url = 'http://172.22.12.98:80/downloads/1M.slf'
- router_name = 'Nfiniti'
- self._ConnectToRouterAndVerify(router_name)
- download_time = self._DownloadAndVerifyFile(download_url)
- self._WriteTimeToFile(self.log_file_path, router_name, '1MB',
- download_time)
- self.DisconnectFromWifiNetwork()
-
- def testDownload10MBFile(self):
- """Test downloading a 10MB file from a wireless router."""
- download_url = 'http://172.22.12.98:80/downloads/10M.slf'
- router_name = 'Linksys_WRT54G2'
- self._ConnectToRouterAndVerify(router_name)
- download_time = self._DownloadAndVerifyFile(download_url)
- self._WriteTimeToFile(self.log_file_path, router_name, '10MB',
- download_time)
- self.DisconnectFromWifiNetwork()
-
- def testDownload100MBFile(self):
- """Test downloading a 100MB file from a wireless router."""
- download_url = 'http://172.22.12.98:80/downloads/100M.slf'
- router_name = 'Trendnet_639gr_4'
- self._ConnectToRouterAndVerify(router_name)
- download_time = self._DownloadAndVerifyFile(download_url)
- self._WriteTimeToFile(self.log_file_path, router_name, '100MB',
- download_time)
- self.DisconnectFromWifiNetwork()
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/functional/wifi_notification.py b/chrome/test/functional/wifi_notification.py
deleted file mode 100755
index 316d4a6325..0000000000
--- a/chrome/test/functional/wifi_notification.py
+++ /dev/null
@@ -1,92 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 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.
-
-import re
-
-import pyauto_functional
-import chromeos_network # pyauto_functional must come before chromeos_network
-
-
-class WifiNotification(chromeos_network.PyNetworkUITest):
- """Test for ChromeOS wifi Network Disconnected Notification.
-
- These tests will be testing Network Disconnected Notification on
- various network encryptions (WEP,RSN, WPA) and various password lengths.
- """
-
- password1 = 'wrongpasswor'
- password5 = 'tente'
- password10 = 'tententent'
- password13 = 'thirteenthirt'
- password26 = 'twentysixtwentysixtwentysi'
- password64 = \
- 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl'
-
- def _WifiNotification(self, router_name, password):
- """Basic test for wifi notification.
-
- Args:
- router_name: The name of the router.
- password: invalid password.
- """
- self.InitWifiPowerStrip()
- router_config = self.GetRouterConfig(router_name)
- self.RouterPower(router_name, True)
-
- self.assertTrue(self.WaitUntilWifiNetworkAvailable(router_config['ssid']),
- 'Wifi network %s never showed up.' % router_config['ssid'])
-
- service_path = self.GetServicePath(router_config['ssid'])
- self.ConnectToWifiNetwork(service_path, password=password)
- self.WaitForNotificationCount(1)
-
- notification_result = self.GetActiveNotifications()[0]['content_url']
- result_error = re.search('Error|Failed', notification_result)
- self.assertTrue(result_error, 'Expected to find Error/Failed in '
- 'notification, not found as expected.')
- result_ssid = re.search(router_config['ssid'], notification_result)
- self.assertTrue(result_ssid,
- 'SSID is not found. Notification text is: "%s"'
- % notification_result)
-
- def testWifiNotificationWEP_Linksys_WRT54G2_wrongpassword(self):
- """wifi disconnect notification-Linksys_WRT54G2.(WEP)-invalid password"""
- self._WifiNotification('Linksys_WRT54G2', WifiNotification.password1)
-
- def testWifiNotificationWEP_Linksys_WRT54G2_five_char(self):
- """wifi disconnect notification for Linksys_WRT54G2.(WEP)-5 password """
- self._WifiNotification('Linksys_WRT54G2', WifiNotification.password5)
-
- def testWifiNotificationWEP_Linksys_WRT54G2_ten_char(self):
- """wifi disconnect notification for Linksys_WRT54G2.(WEP)-10 password"""
- self._WifiNotification('Linksys_WRT54G2', WifiNotification.password10)
-
- def testWifiNotificationWEP_Linksys_WRT54G2_thirteen_char(self):
- """wifi disconnect notification for Linksys_WRT54G2.(WEP)-13 password"""
- self._WifiNotification('Linksys_WRT54G2', WifiNotification.password13)
-
- def testWifiNotificationWEP_Linksys_WRT54G2_twentysix_char(self):
- """wifi disconnect notification for Linksys_WRT54G2.(WEP)-26 password"""
- self._WifiNotification('Linksys_WRT54G2', WifiNotification.password26)
-
- def testWifiNotificationRSN_Belkin_G_wrongpassword(self):
- """wifi disconnect notification for Belkin_G (rsn)-wrong password"""
- self._WifiNotification('Belkin_G', WifiNotification.password1)
-
- def testWifiNotificationWPA_Trendnet_639gr_wrongpassword(self):
- """wifi disconnect notification for Trendnet_639gr (WPA)-wrong password"""
- self._WifiNotification('Trendnet_639gr', WifiNotification.password1)
-
- def testWifiNotificationWPA_Trendnet_639gr_five_char(self):
- """wifi disconnect notification for Trendnet_639gr (WPA)-5 password"""
- self._WifiNotification('Trendnet_639gr', WifiNotification.password5)
-
- def testWifiNotificationWPA_Trendnet_639gr_sixtyfour_char(self):
- """wifi disconnect notification for Trendnet_639gr (WPA)-64 password"""
- self._WifiNotification('Trendnet_639gr', WifiNotification.password64)
-
-
-if __name__ == '__main__':
- pyauto_functional.Main()
diff --git a/chrome/test/mini_installer/chrome_helper.py b/chrome/test/mini_installer/chrome_helper.py
new file mode 100644
index 0000000000..00e892ab04
--- /dev/null
+++ b/chrome/test/mini_installer/chrome_helper.py
@@ -0,0 +1,82 @@
+# Copyright 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.
+
+"""Common helper module for working with Chrome's processes and windows."""
+
+import psutil
+import re
+import win32gui
+import win32process
+
+import path_resolver
+
+
+def GetProcessIDs(process_path):
+ """Returns a list of IDs of processes whose path is |process_path|.
+
+ Args:
+ process_path: The path to the process.
+
+ Returns:
+ A list of process IDs.
+ """
+ process_ids = []
+ for process in psutil.process_iter():
+ try:
+ found_process_path = process.exe
+ if found_process_path == process_path:
+ process_ids.append(process.pid)
+ except psutil.AccessDenied:
+ # It's normal that some processes are not accessible.
+ pass
+ return process_ids
+
+
+def GetWindowHandles(process_ids):
+ """Returns a list of handles of windows owned by processes in |process_ids|.
+
+ Args:
+ process_ids: A list of process IDs.
+
+ Returns:
+ A list of handles of windows owned by processes in |process_ids|.
+ """
+ hwnds = []
+ def EnumerateWindowCallback(hwnd, _):
+ _, found_process_id = win32process.GetWindowThreadProcessId(hwnd)
+ if found_process_id in process_ids and win32gui.IsWindowVisible(hwnd):
+ hwnds.append(hwnd)
+ # Enumerate all the top-level windows and call the callback with the hwnd as
+ # the first parameter.
+ win32gui.EnumWindows(EnumerateWindowCallback, None)
+ return hwnds
+
+
+def WindowExists(process_ids, class_pattern):
+ """Returns whether there exists a window with the specified criteria.
+
+ This method returns whether there exists a window that is owned by a process
+ in |process_ids| and has a class name that matches |class_pattern|.
+
+ Args:
+ process_ids: A list of process IDs.
+ class_pattern: The regular expression pattern of the window class name.
+
+ Returns:
+ A boolean indicating whether such window exists.
+ """
+ for hwnd in GetWindowHandles(process_ids):
+ if re.match(class_pattern, win32gui.GetClassName(hwnd)):
+ return True
+ return False
+
+
+def GetChromePath(system_level):
+ """Returns the path to Chrome, at the |system_level| or user level."""
+ chrome_path = None
+ if system_level:
+ chrome_path = '$PROGRAM_FILES\\$CHROME_DIR\\Application\\chrome.exe'
+ else:
+ chrome_path = '$LOCAL_APPDATA\\$CHROME_DIR\\Application\\chrome.exe'
+ return path_resolver.ResolvePath(chrome_path)
diff --git a/chrome/test/mini_installer/config/chrome_installed.prop b/chrome/test/mini_installer/config/chrome_installed.prop
index 1b95385a76..6fe8aca009 100644
--- a/chrome/test/mini_installer/config/chrome_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_installed.prop
@@ -1,15 +1,19 @@
{
"Files": {
- "$LOCAL_APPDATA\\Google\\Chrome\\Application\\chrome.exe": {"exists": true},
- "$LOCAL_APPDATA\\Google\\Chrome\\Application\\$MINI_INSTALLER_FILE_VERSION\\chrome.dll":
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\chrome.exe": {"exists": true},
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\$MINI_INSTALLER_FILE_VERSION\\chrome.dll":
{"exists": true},
- "$LOCAL_APPDATA\\Google\\Chrome\\Application\\$MINI_INSTALLER_FILE_VERSION\\Installer\\chrome.7z":
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\$MINI_INSTALLER_FILE_VERSION\\Installer\\chrome.7z":
{"exists": true},
- "$LOCAL_APPDATA\\Google\\Chrome\\Application\\$MINI_INSTALLER_FILE_VERSION\\Installer\\setup.exe":
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\$MINI_INSTALLER_FILE_VERSION\\Installer\\setup.exe":
{"exists": true}
},
"RegistryEntries": {
- "HKEY_CURRENT_USER\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}":
- {"exists": true}
+ "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY": {
+ "exists": true,
+ "values": {
+ "pv": {"type": "SZ", "data": "$MINI_INSTALLER_FILE_VERSION"}
+ }
+ }
}
}
diff --git a/chrome/test/mini_installer/config/chrome_inuse.prop b/chrome/test/mini_installer/config/chrome_inuse.prop
new file mode 100644
index 0000000000..ef2ee63c15
--- /dev/null
+++ b/chrome/test/mini_installer/config/chrome_inuse.prop
@@ -0,0 +1,5 @@
+{
+ "Processes": {
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\chrome.exe": {"running": true}
+ }
+}
diff --git a/chrome/test/mini_installer/config/chrome_not_installed.prop b/chrome/test/mini_installer/config/chrome_not_installed.prop
index dfa4ffd84b..26987a72f6 100644
--- a/chrome/test/mini_installer/config/chrome_not_installed.prop
+++ b/chrome/test/mini_installer/config/chrome_not_installed.prop
@@ -1,9 +1,8 @@
{
"Files": {
- "$LOCAL_APPDATA\\Google\\Chrome\\Application": {"exists": false}
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application": {"exists": false}
},
"RegistryEntries": {
- "HKEY_CURRENT_USER\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}":
- {"exists": false}
+ "HKEY_CURRENT_USER\\$CHROME_UPDATE_REGISTRY_SUBKEY": {"exists": false}
}
}
diff --git a/chrome/test/mini_installer/config/chrome_not_inuse.prop b/chrome/test/mini_installer/config/chrome_not_inuse.prop
new file mode 100644
index 0000000000..1439478532
--- /dev/null
+++ b/chrome/test/mini_installer/config/chrome_not_inuse.prop
@@ -0,0 +1,5 @@
+{
+ "Processes": {
+ "$LOCAL_APPDATA\\$CHROME_DIR\\Application\\chrome.exe": {"running": false}
+ }
+}
diff --git a/chrome/test/mini_installer/config/config.config b/chrome/test/mini_installer/config/config.config
index 94725f6d59..88ac92a15c 100644
--- a/chrome/test/mini_installer/config/config.config
+++ b/chrome/test/mini_installer/config/config.config
@@ -1,14 +1,22 @@
{
"states": [
- ["clean", ["chrome_not_installed.prop"]],
- ["chrome_installed", ["chrome_installed.prop"]]
+ ["clean", ["chrome_not_installed.prop", "chrome_not_inuse.prop"]],
+ ["chrome_installed_not_inuse", ["chrome_installed.prop",
+ "chrome_not_inuse.prop"]],
+ ["chrome_installed_inuse", ["chrome_installed.prop", "chrome_inuse.prop"]]
],
"actions": [
- ["install chrome",
- "\"$MINI_INSTALLER\" --chrome --multi-install --do-not-launch-chrome"],
- ["uninstall chrome", "python uninstall_chrome.py"]
+ ["install_chrome_at_user_level",
+ "mini_installer.exe --chrome --multi-install --do-not-launch-chrome"],
+ ["launch_chrome_at_user_level", "python launch_chrome.py"],
+ ["quit_chrome_at_user_level", "python quit_chrome.py"],
+ ["uninstall_chrome", "python uninstall_chrome.py"]
],
"tests": [
- ["clean", "install chrome", "chrome_installed", "uninstall chrome", "clean"]
+ ["clean",
+ "install_chrome_at_user_level", "chrome_installed_not_inuse",
+ "launch_chrome_at_user_level", "chrome_installed_inuse",
+ "quit_chrome_at_user_level", "chrome_installed_not_inuse",
+ "uninstall_chrome", "clean"]
]
}
diff --git a/chrome/test/mini_installer/launch_chrome.py b/chrome/test/mini_installer/launch_chrome.py
new file mode 100644
index 0000000000..7440d47a94
--- /dev/null
+++ b/chrome/test/mini_installer/launch_chrome.py
@@ -0,0 +1,50 @@
+# Copyright 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.
+
+"""Launches Chrome.
+
+This script launches Chrome and waits until its window shows up.
+"""
+
+import optparse
+import subprocess
+import sys
+import time
+
+import chrome_helper
+
+
+def WaitForWindow(process_id, class_pattern):
+ """Waits until a window specified by |process_id| and class name shows up.
+
+ Args:
+ process_id: The ID of the process that owns the window.
+ class_pattern: The regular expression pattern of the window class name.
+
+ Returns:
+ A boolean value indicating whether the specified window shows up within
+ 30 seconds.
+ """
+ start_time = time.time()
+ while time.time() - start_time < 30:
+ if chrome_helper.WindowExists([process_id], class_pattern):
+ return True
+ time.sleep(0)
+ return False
+
+
+def main():
+ parser = optparse.OptionParser(description='Launch Chrome.')
+ parser.add_option('--system-level', action='store_true', dest='system_level',
+ default=False, help='Launch Chrome at system level.')
+ options, _ = parser.parse_args()
+ chrome_path = chrome_helper.GetChromePath(options.system_level)
+ process = subprocess.Popen(chrome_path)
+ if not WaitForWindow(process.pid, 'Chrome_WidgetWin_'):
+ raise Exception('Could not launch Chrome.')
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chrome/test/mini_installer/path_resolver.py b/chrome/test/mini_installer/path_resolver.py
index 570a584c11..3cc178deec 100644
--- a/chrome/test/mini_installer/path_resolver.py
+++ b/chrome/test/mini_installer/path_resolver.py
@@ -9,8 +9,27 @@ import win32com.client
from win32com.shell import shell, shellcon
+def _GetProductName(file_path):
+ """Returns the product name of the given file.
+
+ Args:
+ file_path: The absolute or relative path to the file.
+
+ Returns:
+ A string representing the product name of the file, or None if the product
+ name was not found.
+ """
+ language_and_codepage_pairs = win32api.GetFileVersionInfo(
+ file_path, '\\VarFileInfo\\Translation')
+ if not language_and_codepage_pairs:
+ return None
+ product_name_entry = ('\\StringFileInfo\\%04x%04x\\ProductName' %
+ language_and_codepage_pairs[0])
+ return win32api.GetFileVersionInfo(file_path, product_name_entry)
+
+
def ResolvePath(path):
- """Resolve variables in a file path, and return the resolved path.
+ """Resolves variables in a file path, and returns the resolved path.
This method resolves only variables defined below. It does not resolve
environment variables. Any dollar signs that are not part of variables must be
@@ -23,23 +42,48 @@ def ResolvePath(path):
A new path created by replacing
* $PROGRAM_FILES with the path to the Program Files folder,
* $LOCAL_APPDATA with the path to the Local Application Data folder,
- * $MINI_INSTALLER with the path to the mini_installer, and
+ * $MINI_INSTALLER with the path to the mini_installer,
* $MINI_INSTALLER_FILE_VERSION with the file version of the
- mini_installer.
+ mini_installer,
+ * $CHROME_SHORT_NAME with 'Chrome' (or 'Chromium'),
+ * $CHROME_LONG_NAME with 'Google Chrome' (or 'Chromium'),
+ * $CHROME_DIR with the directory of Chrome (or Chromium) from the base
+ installation directory, and
+ * $CHROME_UPDATE_REGISTRY_SUBKEY with the registry key, excluding the
+ root key, of Chrome for Google Update.
"""
program_files_path = shell.SHGetFolderPath(0, shellcon.CSIDL_PROGRAM_FILES,
None, 0)
local_appdata_path = shell.SHGetFolderPath(0, shellcon.CSIDL_LOCAL_APPDATA,
None, 0)
- #TODO(sukolsak): Copy the mini_installer.exe from the build output into here.
+ # TODO(sukolsak): Copy the mini_installer.exe from the build output into here.
mini_installer_path = os.path.abspath('mini_installer.exe')
mini_installer_file_version = win32com.client.Dispatch(
'Scripting.FileSystemObject').GetFileVersion(mini_installer_path)
+ mini_installer_product_name = _GetProductName(mini_installer_path)
+ if mini_installer_product_name == 'Google Chrome':
+ chrome_short_name = 'Chrome'
+ chrome_long_name = 'Google Chrome'
+ chrome_dir = 'Google\\Chrome'
+ chrome_update_registry_subkey = ('Software\\Google\\Update\\Clients\\'
+ '{8A69D345-D564-463c-AFF1-A69D9E530F96}')
+ elif mini_installer_product_name == 'Chromium':
+ chrome_short_name = 'Chromium'
+ chrome_long_name = 'Chromium'
+ chrome_dir = 'Chromium'
+ chrome_update_registry_subkey = 'Software\\Chromium'
+ else:
+ raise KeyError("Unknown mini_installer product name '%s'" %
+ mini_installer_product_name)
variable_mapping = {
'PROGRAM_FILES': program_files_path,
'LOCAL_APPDATA': local_appdata_path,
'MINI_INSTALLER': mini_installer_path,
'MINI_INSTALLER_FILE_VERSION': mini_installer_file_version,
+ 'CHROME_SHORT_NAME': chrome_short_name,
+ 'CHROME_LONG_NAME': chrome_long_name,
+ 'CHROME_DIR': chrome_dir,
+ 'CHROME_UPDATE_REGISTRY_SUBKEY': chrome_update_registry_subkey,
}
return string.Template(path).substitute(variable_mapping)
diff --git a/chrome/test/mini_installer/process_verifier.py b/chrome/test/mini_installer/process_verifier.py
new file mode 100644
index 0000000000..a23605619b
--- /dev/null
+++ b/chrome/test/mini_installer/process_verifier.py
@@ -0,0 +1,36 @@
+# Copyright 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.
+
+import psutil
+
+import path_resolver
+
+
+def VerifyProcesses(processes):
+ """Verifies that the running processes match the expectation dictionaries.
+
+ This method will throw an AssertionError if process state doesn't match the
+ provided expectation.
+
+ Args:
+ processes: A dictionary whose keys are paths to processes and values are
+ expectation dictionaries. An expectation dictionary is a dictionary with
+ the following key and value:
+ 'running' a boolean indicating whether the process should be
+ running.
+ """
+ # Create a list of paths of all running processes.
+ running_process_paths = []
+ for process in psutil.process_iter():
+ try:
+ running_process_paths.append(process.exe)
+ except psutil.AccessDenied:
+ pass
+
+ for process_path, expectation in processes.iteritems():
+ process_resolved_path = path_resolver.ResolvePath(process_path)
+ is_running = process_resolved_path in running_process_paths
+ assert expectation['running'] == is_running, \
+ ('Process %s is running' % process_path) if is_running else \
+ ('Process %s is not running' % process_path)
diff --git a/chrome/test/mini_installer/quit_chrome.py b/chrome/test/mini_installer/quit_chrome.py
new file mode 100644
index 0000000000..1725104ea7
--- /dev/null
+++ b/chrome/test/mini_installer/quit_chrome.py
@@ -0,0 +1,54 @@
+# Copyright 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.
+
+"""Quits Chrome.
+
+This script sends a WM_CLOSE message to each window of Chrome and waits until
+the process terminates.
+"""
+
+import optparse
+import sys
+import time
+import win32con
+import win32gui
+
+import chrome_helper
+
+
+def CloseWindows(process_path):
+ """Closes all windows owned by processes whose path is |process_path|.
+
+ Args:
+ process_path: The path to the process.
+
+ Returns:
+ A boolean indicating whether the processes successfully terminate within
+ 30 seconds.
+ """
+ start_time = time.time()
+ while time.time() - start_time < 30:
+ process_ids = chrome_helper.GetProcessIDs(process_path)
+ if not process_ids:
+ return True
+
+ for hwnd in chrome_helper.GetWindowHandles(process_ids):
+ win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
+ time.sleep(0)
+ return False
+
+
+def main():
+ parser = optparse.OptionParser(description='Quit Chrome.')
+ parser.add_option('--system-level', action='store_true', dest='system_level',
+ default=False, help='Quit Chrome at system level.')
+ options, _ = parser.parse_args()
+ chrome_path = chrome_helper.GetChromePath(options.system_level)
+ if not CloseWindows(chrome_path):
+ raise Exception('Could not quit Chrome.')
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/chrome/test/mini_installer/registry_verifier.py b/chrome/test/mini_installer/registry_verifier.py
index da7909e59f..55941dd87b 100644
--- a/chrome/test/mini_installer/registry_verifier.py
+++ b/chrome/test/mini_installer/registry_verifier.py
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import _winreg
+import path_resolver
def VerifyRegistryEntries(entries):
@@ -16,41 +17,91 @@ def VerifyRegistryEntries(entries):
VerifyRegistryEntry(key, expectation)
-def RootKeyConstant(key):
+def RootKeyConstant(root_key):
"""Converts a root registry key string into a _winreg.HKEY_* constant."""
- if key == 'HKEY_CLASSES_ROOT':
- return _winreg.HKEY_CLASSES_ROOT
- if key == 'HKEY_CURRENT_USER':
- return _winreg.HKEY_CURRENT_USER
- if key == 'HKEY_LOCAL_MACHINE':
- return _winreg.HKEY_LOCAL_MACHINE
- if key == 'HKEY_USERS':
- return _winreg.HKEY_USERS
- raise KeyError("Unknown root registry key '%s'" % key)
+ root_key_mapping = {
+ 'HKEY_CLASSES_ROOT': _winreg.HKEY_CLASSES_ROOT,
+ 'HKEY_CURRENT_USER': _winreg.HKEY_CURRENT_USER,
+ 'HKEY_LOCAL_MACHINE': _winreg.HKEY_LOCAL_MACHINE,
+ 'HKEY_USERS': _winreg.HKEY_USERS,
+ }
+ if root_key not in root_key_mapping:
+ raise KeyError("Unknown root registry key '%s'" % root_key)
+ return root_key_mapping[root_key]
+
+
+def ValueTypeConstant(value_type):
+ """Converts a registry value type string into a _winreg.REG_* constant."""
+ value_type_mapping = {
+ 'BINARY': _winreg.REG_BINARY,
+ 'DWORD': _winreg.REG_DWORD,
+ 'DWORD_LITTLE_ENDIAN': _winreg.REG_DWORD_LITTLE_ENDIAN,
+ 'DWORD_BIG_ENDIAN': _winreg.REG_DWORD_BIG_ENDIAN,
+ 'EXPAND_SZ': _winreg.REG_EXPAND_SZ,
+ 'LINK': _winreg.REG_LINK,
+ 'MULTI_SZ': _winreg.REG_MULTI_SZ,
+ 'NONE': _winreg.REG_NONE,
+ 'SZ': _winreg.REG_SZ,
+ }
+ if value_type not in value_type_mapping:
+ raise KeyError("Unknown registry value type '%s'" % value_type)
+ return value_type_mapping[value_type]
def VerifyRegistryEntry(key, expectation):
"""Verifies a registry key according to the |expectation|.
The |expectation| specifies whether or not the registry key should exist
- (under 'exists') and optionally specifies an expected 'value' for the key.
+ (under 'exists') and optionally specifies expected 'values' for the key.
Args:
- key: Name of the registry key.
+ key: Name of the registry key. It is expanded using ResolvePath.
expectation: A dictionary with the following keys and values:
- 'exists' a boolean indicating whether the registry entry should exist.
- 'value' (optional) a string representing the expected value for
- the key.
+ 'exists' a boolean indicating whether the registry key should exist.
+ 'values' (optional) a dictionary where each key is a registry value and
+ its associated value is a dictionary with the following key and
+ values:
+ 'type' a string indicating the type of the registry value.
+ 'data' the associated data of the registry value. If it is a
+ string, it is expanded using ResolvePath.
"""
- root_key, sub_key = key.split('\\', 1)
+ resolved_key = path_resolver.ResolvePath(key)
+ root_key, sub_key = resolved_key.split('\\', 1)
try:
# Query the Windows registry for the registry key. It will throw a
# WindowsError if the key doesn't exist.
- _ = _winreg.OpenKey(RootKeyConstant(root_key), sub_key, 0, _winreg.KEY_READ)
+ key_handle = _winreg.OpenKey(RootKeyConstant(root_key), sub_key, 0,
+ _winreg.KEY_QUERY_VALUE)
except WindowsError:
# Key doesn't exist. See that it matches the expectation.
- assert not expectation['exists'], 'Registry entry %s is missing' % key
+ assert not expectation['exists'], ('Registry key %s is missing' %
+ resolved_key)
return
# The key exists, see that it matches the expectation.
- assert expectation['exists'], 'Registry entry %s exists' % key
- # TODO(sukolsak): Verify the expected value.
+ assert expectation['exists'], ('Registry key %s exists' % resolved_key)
+
+ # Verify the expected values.
+ if 'values' not in expectation:
+ return
+ for value, value_expectation in expectation['values'].iteritems():
+ # Query the value. It will throw a WindowsError if the value doesn't exist.
+ try:
+ data, value_type = _winreg.QueryValueEx(key_handle, value)
+ except WindowsError:
+ raise KeyError("Value '%s' of registry key %s is missing" % (
+ value, resolved_key))
+
+ # Verify the type of the value.
+ expected_value_type = value_expectation['type']
+ assert ValueTypeConstant(expected_value_type) == value_type, \
+ "Value '%s' of registry key %s has unexpected type '%s'" % (
+ value, resolved_key, expected_value_type)
+
+ # Verify the associated data of the value.
+ expected_data = value_expectation['data']
+ if isinstance(expected_data, basestring):
+ expected_data = path_resolver.ResolvePath(expected_data)
+ assert expected_data == data, \
+ ("Value '%s' of registry key %s has unexpected data.\n"
+ " Expected: %s\n"
+ " Actual: %s" % (value, resolved_key, expected_data, data))
diff --git a/chrome/test/mini_installer/test_installer.py b/chrome/test/mini_installer/test_installer.py
index 8f5d9af182..0b842e876c 100644
--- a/chrome/test/mini_installer/test_installer.py
+++ b/chrome/test/mini_installer/test_installer.py
@@ -9,10 +9,11 @@ each command match the expected machine states. For more details, take a look at
the design documentation at http://goo.gl/Q0rGM6
"""
-import argparse
import json
+import optparse
import os
import subprocess
+import sys
import unittest
import path_resolver
@@ -189,14 +190,16 @@ def RunTests(config):
def main():
- parser = argparse.ArgumentParser(description='Test the installer.')
- parser.add_argument('config_filename',
- help='The relative/absolute path to the config file.')
- args = parser.parse_args()
+ usage = 'usage: %prog config_filename'
+ parser = optparse.OptionParser(usage, description='Test the installer.')
+ _, args = parser.parse_args()
+ if len(args) != 1:
+ parser.error('Incorrect number of arguments.')
- config = ParseConfigFile(args.config_filename)
+ config = ParseConfigFile(args[0])
RunTests(config)
+ return 0
if __name__ == '__main__':
- main()
+ sys.exit(main())
diff --git a/chrome/test/mini_installer/uninstall_chrome.py b/chrome/test/mini_installer/uninstall_chrome.py
index 3680940870..c7b8996de1 100644
--- a/chrome/test/mini_installer/uninstall_chrome.py
+++ b/chrome/test/mini_installer/uninstall_chrome.py
@@ -2,34 +2,36 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Uninstall Chrome.
+"""Uninstalls Chrome.
This script reads the uninstall command from registry, calls it, and verifies
the output status code.
"""
import _winreg
-import argparse
+import optparse
import subprocess
import sys
+import path_resolver
+
def main():
- parser = argparse.ArgumentParser(description='Uninstall Chrome.')
- parser.add_argument('--system-level', dest='system_level',
- action='store_const', const=True, default=False,
- help='Uninstall Chrome at system level.')
- args = parser.parse_args()
+ parser = optparse.OptionParser(description='Uninstall Chrome.')
+ parser.add_option('--system-level', action='store_true', dest='system_level',
+ default=False, help='Uninstall Chrome at system level.')
+ options, _ = parser.parse_args()
# TODO(sukolsak): Add support for uninstalling MSI-based Chrome installs when
# we support testing MSIs.
- if args.system_level:
+ if options.system_level:
root_key = _winreg.HKEY_LOCAL_MACHINE
else:
root_key = _winreg.HKEY_CURRENT_USER
sub_key = ('SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\'
- 'Google Chrome')
- key = _winreg.OpenKey(root_key, sub_key, 0, _winreg.KEY_QUERY_VALUE)
+ '$CHROME_LONG_NAME')
+ resolved_sub_key = path_resolver.ResolvePath(sub_key)
+ key = _winreg.OpenKey(root_key, resolved_sub_key, 0, _winreg.KEY_QUERY_VALUE)
uninstall_string, _ = _winreg.QueryValueEx(key, 'UninstallString')
exit_status = subprocess.call(uninstall_string, shell=True)
# The exit status for successful uninstallation of Chrome is 19 (see
diff --git a/chrome/test/mini_installer/verifier.py b/chrome/test/mini_installer/verifier.py
index 1436040e36..e6b466e025 100644
--- a/chrome/test/mini_installer/verifier.py
+++ b/chrome/test/mini_installer/verifier.py
@@ -3,6 +3,7 @@
# found in the LICENSE file.
import file_verifier
+import process_verifier
import registry_verifier
@@ -19,6 +20,8 @@ def Verify(property):
for verifier_name, value in property.iteritems():
if verifier_name == 'Files':
file_verifier.VerifyFiles(value)
+ elif verifier_name == 'Processes':
+ process_verifier.VerifyProcesses(value)
elif verifier_name == 'RegistryEntries':
registry_verifier.VerifyRegistryEntries(value)
else:
diff --git a/chrome/test/perf/feature_startup_test.cc b/chrome/test/perf/feature_startup_test.cc
index d75e4d2d63..73b4fa31cf 100644
--- a/chrome/test/perf/feature_startup_test.cc
+++ b/chrome/test/perf/feature_startup_test.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "base/path_service.h"
-#include "base/perftimer.h"
#include "base/strings/stringprintf.h"
+#include "base/test/perftimer.h"
#include "base/time/time.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/common/chrome_paths.h"
diff --git a/chrome/test/perf/rendering/throughput_tests.cc b/chrome/test/perf/rendering/throughput_tests.cc
index a21c6857ad..b2fc89239c 100644
--- a/chrome/test/perf/rendering/throughput_tests.cc
+++ b/chrome/test/perf/rendering/throughput_tests.cc
@@ -543,7 +543,9 @@ IN_PROC_BROWSER_TEST_F(ThroughputTestGPU, DrawImageShadowGPU) {
RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest | kIsFlaky);
}
-IN_PROC_BROWSER_TEST_F(ThroughputTestThread, DrawImageShadowGPU) {
+// Intermittent failure, should be fixed by converting to telemetry.
+// See crbug.com/276500 for more details.
+IN_PROC_BROWSER_TEST_F(ThroughputTestThread, DISABLED_DrawImageShadowGPU) {
// TODO(junov): Fix test flakiness crbug.com/272383
RunTest("canvas2d_balls_with_shadow", kNone | kIsGpuCanvasTest | kIsFlaky);
}
diff --git a/chrome/test/perf/url_parse_perftest.cc b/chrome/test/perf/url_parse_perftest.cc
index 20662f76ba..3aadd06792 100644
--- a/chrome/test/perf/url_parse_perftest.cc
+++ b/chrome/test/perf/url_parse_perftest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/perftimer.h"
+#include "base/test/perftimer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/url_canon.h"
@@ -18,8 +18,8 @@
#include "webkit/third_party/WebCore/platform/CString.h"
#define KURL WebKitKURL
-#include "KURL.h"
#include "KURL.cpp"
+#include "KURL.h"
#pragma warning(pop)
TEST(URLParse, FullURL) {
@@ -45,7 +45,7 @@ int typical_url2_len = static_cast<int>(strlen(typical_url2));
const char typical_url3[] = "http://store.apple.com/1-800-MY-APPLE/WebObjects/AppleStore.woa/wa/RSLID?nnmm=browse&mco=578E9744&node=home/desktop/mac_pro";
int typical_url3_len = static_cast<int>(strlen(typical_url3));
-}
+} // namespace
TEST(URLParse, TypicalURLParse) {
url_parse::Parsed parsed1;
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 5952b08e8f..e7e0260d71 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -286,15 +286,27 @@ TEST_PPAPI_NACL(Graphics2D_Flush)
TEST_PPAPI_NACL(Graphics2D_FlushOffscreenUpdate)
TEST_PPAPI_NACL(Graphics2D_BindNull)
-#if defined(OS_WIN) && !defined(USE_AURA)
+#if defined(OS_WIN)
+// In-process and NaCl tests are having flaky failures on Win: crbug.com/242252
+#define MAYBE_IN_Graphics3D DISABLED_Graphics3D
+#define MAYBE_OUT_Graphics3D Graphics3D
+#define MAYBE_NACL_Graphics3D DISABLED_Graphics3D
+#elif defined(OS_WIN) && defined(USE_AURA)
// These tests fail with the test compositor which is what's used by default for
// browser tests on Windows Aura. Renable when the software compositor is
// available.
-// In-process and NaCl tests are having flaky failures on Win: crbug.com/242252
-TEST_PPAPI_IN_PROCESS(DISABLED_Graphics3D)
-TEST_PPAPI_OUT_OF_PROCESS(Graphics3D)
-TEST_PPAPI_NACL(DISABLED_Graphics3D)
+#define MAYBE_IN_Graphics3D DISABLED_Graphics3D
+#define MAYBE_OUT_Graphics3D DISABLED_Graphics3D
+#define MAYBE_NACL_Graphics3D DISABLED_Graphics3D
+#else
+// The tests are failing in-process. crbug.com/280282
+#define MAYBE_IN_Graphics3D DISABLED_Graphics3D
+#define MAYBE_OUT_Graphics3D Graphics3D
+#define MAYBE_NACL_Graphics3D Graphics3D
#endif
+TEST_PPAPI_IN_PROCESS(MAYBE_IN_Graphics3D)
+TEST_PPAPI_OUT_OF_PROCESS(MAYBE_OUT_Graphics3D)
+TEST_PPAPI_NACL(MAYBE_NACL_Graphics3D)
TEST_PPAPI_IN_PROCESS(ImageData)
TEST_PPAPI_OUT_OF_PROCESS(ImageData)
@@ -337,11 +349,9 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, TCPSocket) {
}
TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate)
-TEST_PPAPI_IN_PROCESS_WITH_SSL_SERVER(TCPSocketPrivate)
TEST_PPAPI_NACL_WITH_SSL_SERVER(TCPSocketPrivate)
TEST_PPAPI_OUT_OF_PROCESS_WITH_SSL_SERVER(TCPSocketPrivateTrusted)
-TEST_PPAPI_IN_PROCESS_WITH_SSL_SERVER(TCPSocketPrivateTrusted)
// UDPSocket tests.
// UDPSocket_Broadcast is disabled for OSX because it requires root permissions
@@ -620,7 +630,9 @@ TEST_PPAPI_IN_PROCESS_VIA_HTTP(URLRequest_AppendDataToBody)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(URLRequest_AppendDataToBody)
TEST_PPAPI_NACL(URLRequest_AppendDataToBody)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(URLRequest_AppendFileToBody)
+#if !defined(OS_MACOSX) // TODO(teravest): http://crbug.com/280570
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(URLRequest_AppendFileToBody)
+#endif
TEST_PPAPI_NACL(URLRequest_AppendFileToBody)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(URLRequest_Stress)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(URLRequest_Stress)
@@ -762,7 +774,9 @@ IN_PROC_BROWSER_TEST_F(PPAPITest, FileIO) {
LIST_TEST(FileIO_NotAllowMixedReadWrite)
LIST_TEST(FileIO_ReadWriteSetLength)
LIST_TEST(FileIO_ReadToArrayWriteSetLength)
+#if !defined(OS_MACOSX) // TODO(teravest): http://crbug.com/280570
LIST_TEST(FileIO_TouchQuery)
+#endif
LIST_TEST(FileIO_WillWriteWillSetLength)
LIST_TEST(FileIO_RequestOSFileHandle)
LIST_TEST(FileIO_RequestOSFileHandleWithOpenExclusive)
diff --git a/chrome/test/pyautolib/chromeos_network.py b/chrome/test/pyautolib/chromeos_network.py
index 5e8b9ef144..32c86cd794 100644
--- a/chrome/test/pyautolib/chromeos_network.py
+++ b/chrome/test/pyautolib/chromeos_network.py
@@ -12,112 +12,6 @@ from chromeos.power_strip import PowerStrip
import pyauto
import pyauto_errors
-class WifiPowerStrip(PowerStrip):
- """Manages the power state of wifi routers connected to a power strip.
-
- This class provides additional functionality over PowerStrip by providing
- a timeout feature for wifi routers connected to the strip. This is to prevent
- repeated on/off calls to the same router which may put the router in an
- undesired state.
- """
-
- def __init__ (self, host, routers):
- """Initializes a WifiPowerStrip object.
-
- Args:
- host: IP of the switch that the routers are attached to.
- routers: Dictionary of wifi routers in the following format:
- {
- '< router name >': {
- 'strip_id' : '.aX' # where X is the port number
- < additional fields may be added here for each router >
- }
- }
- """
- self._router_dict = routers
-
- # Each router will have a timestamp associated to it regarding whether
- # or not an action can be performed on it yet. This is to prevent
- # the spamming of power on/off calls on a particular router.
- # The WifiPowerStrip_UsableTime field specifies the earliest time
- # after which the router may be used. We will initialize it to now
- # since they should all be usable at init.
- for router_info in self._router_dict.values():
- router_info['WifiPowerStrip_UsableTime'] = time.time()
-
- # _routers_used keeps track of which routers were used during the lifetime
- # of the WifiPowerStrip instance. Adding used routers occurs when
- # a wifi router has been turned on. Otherwise, it get clears upon
- # the TurnOffUsedRouters call.
- self._routers_used = set()
- PowerStrip.__init__(self, host)
-
- def GetRouterConfig(self, router_name):
- """Returns the configuration for the specified router.
-
- Args:
- router_name: A string specifying the router.
-
- Returns:
- The config dictionary for the given router if the router is defined.
- None otherwise.
- """
- return copy.deepcopy(self._router_dict.get(router_name))
-
- def RouterPower(self, router_name, power_state, pause_after=5):
- """Executes PowerStrip commands.
-
- Args:
- router_name: The name of the router to perform the action on.
- power_state: A boolean value where True represents turning the router on
- and False represents turning the router off.
- pause_after: Specified in seconds, and specifies the time to sleep
- after a command is run. This is to prevent spamming of
- power on/off of the same router which has put the router
- in an undesirable state.
-
- Raises:
- Exception if router_name is not a valid router.
- """
- router = self.GetRouterConfig(router_name)
- if not router: raise Exception('Invalid router name \'%s\'.' % router_name)
-
- # Hidden routers will always be on. Don't allow controlling of the power
- # for these networks.
- if router.get('hidden'):
- return
-
- sleep_time = router['WifiPowerStrip_UsableTime'] - time.time()
- if sleep_time > 0:
- time.sleep(sleep_time)
-
- if power_state:
- self._routers_used |= set([router_name])
- logging.debug('Turning on router %s:%s.' %
- (router['strip_id'], router_name))
- self.PowerOn(router['strip_id'])
- else:
- logging.debug('Turning off router %s:%s.' %
- (router['strip_id'], router_name))
- self.PowerOff(router['strip_id'])
-
- # Set the Usable time of the particular router to pause_after
- # seconds after the current time.
- router['WifiPowerStrip_UsableTime'] = time.time() + pause_after
-
- def TurnOffAllRouters(self):
- """Turns off all the routers."""
- for router in self._router_dict:
- self.RouterPower(router, False, pause_after=0)
-
- def TurnOffUsedRouters(self):
- """Turns off the routers that were once turned on."""
- for router in self._routers_used:
- self.RouterPower(router, False, pause_after=0)
-
- self._routers_used = set()
-
-
class PyNetworkUITest(pyauto.PyUITest):
"""A subclass of PyUITest for Chrome OS network tests.
@@ -139,14 +33,11 @@ class PyNetworkUITest(pyauto.PyUITest):
self._ParseDefaultRoutingTable()
pyauto.PyUITest.setUp(self)
self.ForgetAllRememberedNetworks()
- self._wifi_power_strip = None
def tearDown(self):
self.ForgetAllRememberedNetworks()
pyauto.PyUITest.tearDown(self)
self._PopServiceOrder()
- if self._wifi_power_strip:
- self._wifi_power_strip.TurnOffUsedRouters()
# Remove the route entry for the power strip.
if hasattr(self, 'ps_route_entry'):
os.system('route del -net %(ipaddress)s gateway %(gateway)s netmask '
@@ -209,74 +100,3 @@ class PyNetworkUITest(pyauto.PyUITest):
assert old_service_order == set_service_order, \
'Flimflam service order not set properly. %s != %s' % \
(old_service_order, set_service_order)
-
- def _SetupRouteForPowerStrip(self, ipaddress, iface='eth'):
- """Create a route table entry for the power strip."""
-
- # Assume device has only one interface that is prepended with
- # $iface and use that one.
- try:
- iface = [ key for key in self.default_routes.keys() if iface in key ][0]
- except:
- assert 'Unable to find interface of type %s.' % iface
-
- self.ps_route_entry = {
- 'iface' : iface,
- 'gateway' : self.default_routes[iface]['gateway'],
- 'netmask' : '255.255.255.255',
- 'ipaddress' : ipaddress
- }
-
- os.system('route add -net %(ipaddress)s gateway %(gateway)s netmask '
- '%(netmask)s dev %(iface)s' % self.ps_route_entry)
-
- # Verify the route was added.
- assert os.system('route -n | egrep "^%(ipaddress)s[[:space:]]+%(gateway)s'
- '[[:space:]]+%(netmask)s"' % self.ps_route_entry) == 0, \
- 'Failed to create default route for powerstrip.'
-
- def InitWifiPowerStrip(self):
- """Initializes the router controller using the specified config file."""
-
- assert os.path.exists(PyNetworkUITest._ROUTER_CONFIG_FILE), \
- 'Router configuration file does not exist.'
-
- config = pyauto.PyUITest.EvalDataFrom(self._ROUTER_CONFIG_FILE)
- strip_ip, routers = config['strip_ip'], config['routers']
-
- self._SetupRouteForPowerStrip(strip_ip)
- self._wifi_power_strip = WifiPowerStrip(strip_ip, routers)
-
- self.RouterPower = self._wifi_power_strip.RouterPower
- self.TurnOffAllRouters = self._wifi_power_strip.TurnOffAllRouters
- self.GetRouterConfig = self._wifi_power_strip.GetRouterConfig
-
- def ConnectToWifiRouter(self, router_name, shared=True):
- """Connects to a router by name.
-
- Args:
- router_name: The name of the router that is specified in the
- configuration file.
- """
- router = self._wifi_power_strip.GetRouterConfig(router_name)
- assert router, 'Router with name %s is not defined ' \
- 'in the router configuration.' % router_name
- security = router.get('security', 'SECURITY_NONE')
- passphrase = router.get('passphrase', '')
-
- # Branch off the connect calls depending on if the wifi network is hidden
- # or not.
- error_string = None
- if router.get('hidden'):
- error_string = self.ConnectToHiddenWifiNetwork(router['ssid'], security,
- passphrase)
- else:
- service_path = self.GetServicePath(router['ssid'])
- assert service_path, 'Service with SSID %s is not present.' % \
- router['ssid']
-
- logging.debug('Connecting to router %s.' % router_name)
- error_string = self.ConnectToWifiNetwork(service_path,
- password=passphrase,
- shared=shared)
- return error_string
diff --git a/chrome/test/pyautolib/pyauto.py b/chrome/test/pyautolib/pyauto.py
index 7d81e0a550..83bc88f02e 100755
--- a/chrome/test/pyautolib/pyauto.py
+++ b/chrome/test/pyautolib/pyauto.py
@@ -4496,42 +4496,6 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
return panels
- def RestoreOnline(self):
- """Returns the device from offline mode if GoOffline was used."""
-
- assert PyUITest.IsChromeOS()
-
- # Restores etherent connection
- stdout, stderr = self.RunSuperuserActionOnChromeOS('TeardownBackchannel')
-
- if hasattr(self, 'bc_cellular_enabled') and self.bc_cellular_enabled:
- self.ToggleNetworkDevice('cellular', True)
- if hasattr(self, 'bc_wifi_enabled') and self.bc_wifi_enabled:
- self.ToggleNetworkDevice('wifi', True)
-
- assert 'RuntimeError' not in stderr, stderr
-
- def GoOffline(self):
- """Puts device in offline mode.
-
- The device is put into offline mode by disabling all network interfaces
- but keeping the the wired ethernet interface up and faking shill/flimflam
- into thinking there is no ethernet interface by renaming the interface.
- This is so we can keep ssh connections over the wired connection alive.
- """
- assert PyUITest.IsChromeOS()
- net_info = self.GetNetworkInfo()
- self.bc_wifi_enabled = net_info.get('wifi_enabled')
- self.bc_cellular_enabled = net_info.get('cellular_enabled')
-
- if self.bc_cellular_enabled:
- self.ToggleNetworkDevice('cellular', False)
- if self.bc_wifi_enabled:
- self.ToggleNetworkDevice('wifi', False)
-
- stdout, stderr = self.RunSuperuserActionOnChromeOS('SetupBackchannel')
- assert 'RuntimeError' not in stderr, stderr
-
def GetNetworkInfo(self):
"""Get details about ethernet, wifi, and cellular networks on chromeos.
@@ -4596,52 +4560,6 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
return network_info
- def GetConnectedWifi(self):
- """Returns the SSID of the currently connected wifi network.
-
- Returns:
- The SSID of the connected network or None if we're not connected.
- """
- service_list = self.GetNetworkInfo()
- connected_service_path = service_list.get('connected_wifi')
- if 'wifi_networks' in service_list and \
- connected_service_path in service_list['wifi_networks']:
- return service_list['wifi_networks'][connected_service_path]['name']
-
- def GetServicePath(self, ssid, encryption=None, timeout=30):
- """Waits until the SSID is observed and returns its service path.
-
- Args:
- ssid: String defining the SSID we are searching for.
- encryption: Encryption type of the network; either None to return the
- first instance of network that matches the ssid, '' for
- an empty network, 'PSK', 'WEP' or '8021X'.
- timeout: Duration to wait for ssid to appear.
-
- Returns:
- The service path or None if SSID does not exist after timeout period.
- """
- def _GetServicePath():
- service_list = self.GetNetworkInfo().get('wifi_networks', [])
- for service_path, service_obj in service_list.iteritems():
- if not (isinstance(service_obj, dict) and
- 'encryption' in service_obj and
- 'name' in service_obj):
- continue
-
- service_encr = 'PSK' if service_obj['encryption'] in ['WPA', 'RSN']\
- else service_obj['encryption']
-
- if service_obj['name'] == ssid and \
- (encryption == None or service_encr == encryption):
- return service_path
- self.NetworkScan()
- return None
-
- service_path = self.WaitUntil(_GetServicePath, timeout=timeout,
- retry_sleep=1, return_retval=True)
- return service_path or None
-
def NetworkScan(self):
"""Causes ChromeOS to scan for available wifi networks.
@@ -4672,90 +4590,6 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
}
return self._GetResultFromJSONRequest(cmd_dict, windex=None)
- PROXY_TYPE_DIRECT = 1
- PROXY_TYPE_MANUAL = 2
- PROXY_TYPE_PAC = 3
-
- def WaitUntilWifiNetworkAvailable(self, ssid, timeout=60, is_hidden=False):
- """Waits until the given network is available.
-
- Routers that are just turned on may take up to 1 minute upon turning them
- on to broadcast their SSID.
-
- Args:
- ssid: SSID of the service we want to connect to.
- timeout: timeout (in seconds)
-
- Raises:
- Exception if timeout duration has been hit before wifi router is seen.
-
- Returns:
- True, when the wifi network is seen within the timout period.
- False, otherwise.
- """
- def _GotWifiNetwork():
- # Returns non-empty array if desired SSID is available.
- try:
- return [wifi for wifi in
- self.NetworkScan().get('wifi_networks', {}).values()
- if wifi.get('name') == ssid]
- except pyauto_errors.JSONInterfaceError:
- # Temporary fix until crosbug.com/14174 is fixed.
- # NetworkScan is only used in updating the list of networks so errors
- # thrown by it are not critical to the results of wifi tests that use
- # this method.
- return False
-
- # The hidden AP's will always be on, thus we will assume it is ready to
- # connect to.
- if is_hidden:
- return bool(_GotWifiNetwork())
-
- return self.WaitUntil(_GotWifiNetwork, timeout=timeout, retry_sleep=1)
-
- def ResetProxySettingsOnChromeOS(self):
- """Public wrapper around proxysettings teardown functions."""
- self.SetSharedProxies(False)
- proxy_dict = {
- 'mode': 'direct'
- }
- self.SetProxySettingOnChromeOS(proxy_dict)
-
- def SetProxySettingOnChromeOS(self, proxy_config):
- """Set the proxy config of the current network.
-
- Owner must be logged in for these to persist.
- If user is not logged in or is logged in as non-owner or guest,
- proxy settings do not persist across browser restarts or login/logout.
-
- Args:
- proxy_config: A dictionary following the format described in
- prefs/proxy_config_dictionary.h.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'SetProxySettings',
- 'proxy_config': json.dumps(proxy_config)
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def SetSharedProxies(self, value):
- """Allows proxies on the shared networks.
-
- Args:
- value: True/False to set and clear respectively.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'SetSharedProxies',
- 'value': value,
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
def ForgetAllRememberedNetworks(self):
"""Forgets all networks that the device has marked as remembered."""
for service in self.GetNetworkInfo()['remembered_wifi']:
@@ -4786,72 +4620,6 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
}
self._GetResultFromJSONRequest(cmd_dict, windex=None, timeout=50000)
- def ConnectToCellularNetwork(self):
- """Connects to the available cellular network.
-
- Blocks until connection succeeds or fails.
-
- Returns:
- An error string if an error occured.
- None otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- # Every device should only have one cellular network present, so we can
- # scan for it.
- cellular_networks = self.NetworkScan().get('cellular_networks', {}).keys()
- self.assertTrue(cellular_networks, 'Could not find cellular service.')
- service_path = cellular_networks[0]
-
- cmd_dict = {
- 'command': 'ConnectToCellularNetwork',
- 'service_path': service_path,
- }
- result = self._GetResultFromJSONRequest(
- cmd_dict, windex=None, timeout=50000)
- return result.get('error_string')
-
- def DisconnectFromCellularNetwork(self):
- """Disconnect from the connected cellular network.
-
- Blocks until disconnect is complete.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'DisconnectFromCellularNetwork',
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def ConnectToWifiNetwork(self, service_path, password='', shared=True):
- """Connect to a wifi network by its service path.
-
- Blocks until connection succeeds or fails.
-
- Args:
- service_path: Flimflam path that defines the wifi network.
- password: Passphrase for connecting to the wifi network.
- shared: Boolean value specifying whether the network should be shared.
-
- Returns:
- An error string if an error occured.
- None otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ConnectToWifiNetwork',
- 'service_path': service_path,
- 'password': password,
- 'shared': shared,
- }
- result = self._GetResultFromJSONRequest(
- cmd_dict, windex=None, timeout=50000)
- return result.get('error_string')
-
def ConnectToHiddenWifiNetwork(self, ssid, security, password='',
shared=True, save_credentials=False):
"""Connect to a wifi network by its service path.
@@ -4888,134 +4656,6 @@ class PyUITest(pyautolib.PyUITestBase, unittest.TestCase):
cmd_dict, windex=None, timeout=50000)
return result.get('error_string')
- def DisconnectFromWifiNetwork(self):
- """Disconnect from the connected wifi network.
-
- Blocks until disconnect is complete.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'DisconnectFromWifiNetwork',
- }
- self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def AddPrivateNetwork(self,
- hostname,
- service_name,
- provider_type,
- username,
- password,
- cert_id='',
- key=''):
- """Add and connect to a private network.
-
- Blocks until connection succeeds or fails. This is equivalent to
- 'Add Private Network' in the network menu UI.
-
- Args:
- hostname: Server hostname for the private network.
- service_name: Service name that defines the private network. Do not
- add multiple services with the same name.
- provider_type: Types are L2TP_IPSEC_PSK and L2TP_IPSEC_USER_CERT.
- Provider type OPEN_VPN is not yet supported.
- Type names returned by GetPrivateNetworkInfo will
- also work.
- username: Username for connecting to the virtual network.
- password: Passphrase for connecting to the virtual network.
- cert_id: Certificate id for a L2TP_IPSEC_USER_CERT network.
- key: Pre-shared key for a L2TP_IPSEC_PSK network.
-
- Returns:
- An error string if an error occured.
- None otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'AddPrivateNetwork',
- 'hostname': hostname,
- 'service_name': service_name,
- 'provider_type': provider_type,
- 'username': username,
- 'password': password,
- 'cert_id': cert_id,
- 'key': key,
- }
- result = self._GetResultFromJSONRequest(
- cmd_dict, windex=None, timeout=50000)
- return result.get('error_string')
-
- def GetPrivateNetworkInfo(self):
- """Get details about private networks on chromeos.
-
- Returns:
- A dictionary including information about all remembered virtual networks
- as well as the currently connected virtual network, if any.
- Sample:
- { u'connected': u'/service/vpn_123_45_67_89_test_vpn'}
- u'/service/vpn_123_45_67_89_test_vpn':
- { u'username': u'vpn_user',
- u'name': u'test_vpn',
- u'hostname': u'123.45.67.89',
- u'key': u'abcde',
- u'cert_id': u'',
- u'password': u'zyxw123',
- u'provider_type': u'L2TP_IPSEC_PSK'},
- u'/service/vpn_111_11_11_11_test_vpn2':
- { u'username': u'testerman',
- u'name': u'test_vpn2',
- u'hostname': u'111.11.11.11',
- u'key': u'fghijklm',
- u'cert_id': u'',
- u'password': u'789mnop',
- u'provider_type': u'L2TP_IPSEC_PSK'},
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = { 'command': 'GetPrivateNetworkInfo' }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
- def ConnectToPrivateNetwork(self, service_path):
- """Connect to a remembered private network by its service path.
-
- Blocks until connection succeeds or fails. The network must have been
- previously added with all necessary connection details.
-
- Args:
- service_path: Service name that defines the private network.
-
- Returns:
- An error string if an error occured.
- None otherwise.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'ConnectToPrivateNetwork',
- 'service_path': service_path,
- }
- result = self._GetResultFromJSONRequest(
- cmd_dict, windex=None, timeout=50000)
- return result.get('error_string')
-
- def DisconnectFromPrivateNetwork(self):
- """Disconnect from the active private network.
-
- Expects a private network to be active.
-
- Raises:
- pyauto_errors.JSONInterfaceError if the automation call returns an error.
- """
- cmd_dict = {
- 'command': 'DisconnectFromPrivateNetwork',
- }
- return self._GetResultFromJSONRequest(cmd_dict, windex=None)
-
def EnableSpokenFeedback(self, enabled):
"""Enables or disables spoken feedback accessibility mode.
diff --git a/chrome/test/telemetry/chromeos/login_unittest.py b/chrome/test/telemetry/chromeos/login_unittest.py
index da293b0bbd..92b3b55632 100644
--- a/chrome/test/telemetry/chromeos/login_unittest.py
+++ b/chrome/test/telemetry/chromeos/login_unittest.py
@@ -10,8 +10,7 @@ from telemetry.core import exceptions
from telemetry.core import extension_to_load
from telemetry.core import util
from telemetry.core.chrome import cros_interface
-from telemetry.core.chrome import cros_util
-from telemetry.test import options_for_unittests
+from telemetry.unittest import options_for_unittests
class CrOSAutoTest(unittest.TestCase):
def setUp(self):
@@ -36,13 +35,17 @@ class CrOSAutoTest(unittest.TestCase):
if with_autotest_ext:
extension_path = os.path.join(os.path.dirname(__file__), 'autotest_ext')
- self._load_extension = extension_to_load.ExtensionToLoad(extension_path,
- True)
+ self._load_extension = extension_to_load.ExtensionToLoad(
+ path=extension_path,
+ browser_type=options.browser_type,
+ is_component=True)
options.extensions_to_load = [self._load_extension]
browser_to_create = browser_finder.FindBrowser(options)
self.assertTrue(browser_to_create)
- return browser_to_create.Create()
+ b = browser_to_create.Create()
+ b.Start()
+ return b
def _GetAutotestExtension(self, browser):
"""Returns the autotest extension instance"""