summaryrefslogtreecommitdiffstats
path: root/tools/chrome_remote_control
diff options
context:
space:
mode:
authornduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-05 00:58:53 +0000
committernduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-05 00:58:53 +0000
commit953d04a25a27bc6a81e4420b04d2b21c738db506 (patch)
treeb6dfeea7200735e58303f409adedd4ad5ab718d6 /tools/chrome_remote_control
parent41c444da42aa6ad0f10b69826058322100157ad7 (diff)
downloadchromium_src-953d04a25a27bc6a81e4420b04d2b21c738db506.zip
chromium_src-953d04a25a27bc6a81e4420b04d2b21c738db506.tar.gz
chromium_src-953d04a25a27bc6a81e4420b04d2b21c738db506.tar.bz2
Polish to chrome_remote_control to reduce flake and improve modularity.
- Make android work - Overhaul tools/gpu to be more component-y - Fix error where pexpect missing breaks all browser discovery - Use page.navigate and get rid of the strange timeout logic in InspectorBackend - Make browser selection explicit. You have to select browsers explicitly. - Add --repeat-count to run_tests - Move sleep-after-each-load to gpu_tools.url_test - Make timeouts explicit - Fix handling of optparse defaults and counters - Add is_content_shell property on backends - Set up content-shell command line on android - Override user-data-dir only for non-content-shell backends - If browser fails to die on sigterm, send it a sigkill - Move gpu tools browser creation to toplevel test - Make non-jsonizable evaluate test independent of window for perf reasons - Add runtime.execute to avoid hacks of runtime.evaluate TBR=dtu@chromium.org BUG=144483 Review URL: https://chromiumcodereview.appspot.com/10909067 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154874 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'tools/chrome_remote_control')
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/adb_commands.py (renamed from tools/chrome_remote_control/chrome_remote_control/android_commands.py)22
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/android_browser_backend.py31
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/android_browser_finder.py17
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/android_browser_finder_unittest.py31
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser.py4
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_backend.py9
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_finder.py70
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_options.py42
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_options_unittest.py47
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/browser_unittest.py27
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py35
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder.py29
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder_unittest.py1
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/inspector_backend.py46
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/run_tests.py68
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab.py35
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab_page.py67
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab_page_unittest.py43
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab_runtime.py8
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab_runtime_unittest.py21
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/tab_unittest.py10
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/util.py19
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/util_unittest.py17
-rw-r--r--tools/chrome_remote_control/chrome_remote_control/websocket.py2
-rwxr-xr-xtools/chrome_remote_control/examples/rendering_microbenchmark_test.py7
-rw-r--r--tools/chrome_remote_control/examples/top1k4
-rwxr-xr-xtools/chrome_remote_control/run_tests15
27 files changed, 514 insertions, 213 deletions
diff --git a/tools/chrome_remote_control/chrome_remote_control/android_commands.py b/tools/chrome_remote_control/chrome_remote_control/adb_commands.py
index db67a43..908a5a3 100644
--- a/tools/chrome_remote_control/chrome_remote_control/android_commands.py
+++ b/tools/chrome_remote_control/chrome_remote_control/adb_commands.py
@@ -14,11 +14,18 @@ import sys
# Get build/android scripts into our path.
sys.path.append(
- os.path.join(os.path.dirname(__file__),
- "../../../build/android"))
-from pylib import android_commands as real_android_commands
-from pylib import cmd_helper as real_cmd_helper
-
+ os.path.abspath(
+ os.path.join(os.path.dirname(__file__),
+ "../../../build/android")))
+try:
+ from pylib import android_commands as real_android_commands
+ from pylib import cmd_helper as real_cmd_helper
+except:
+ import traceback; traceback.print_exc()
+ real_android_commands = None
+
+def IsAndroidSupported():
+ return real_android_commands
def GetAttachedDevices():
"""Returns a list of attached, online android devices.
@@ -27,7 +34,7 @@ def GetAttachedDevices():
the returned list."""
return real_android_commands.GetAttachedDevices()
-class AndroidCommands(object):
+class ADBCommands(object):
"""A thin wrapper around ADB"""
def __init__(self, device):
@@ -98,3 +105,6 @@ class AndroidCommands(object):
action,
category, data,
extras, trace_file_name)
+
+ def Push(self, local, remote):
+ return self._adb.Adb().Push(local, remote)
diff --git a/tools/chrome_remote_control/chrome_remote_control/android_browser_backend.py b/tools/chrome_remote_control/chrome_remote_control/android_browser_backend.py
index 5f0e25d2..58249cb 100644
--- a/tools/chrome_remote_control/chrome_remote_control/android_browser_backend.py
+++ b/tools/chrome_remote_control/chrome_remote_control/android_browser_backend.py
@@ -18,9 +18,9 @@ class AndroidBrowserBackend(browser_backend.BrowserBackend):
"""The backend for controlling a browser instance running on Android.
"""
def __init__(self, type, options, adb,
- package, cmdline_file, activity,
+ package, is_content_shell, cmdline_file, activity,
devtools_remote_port):
- super(AndroidBrowserBackend, self).__init__()
+ super(AndroidBrowserBackend, self).__init__(is_content_shell)
# Initialize fields so that an explosion during init doesn't break in Close.
self._options = options
self._adb = adb
@@ -30,18 +30,33 @@ class AndroidBrowserBackend(browser_backend.BrowserBackend):
self._port = 9222
self._devtools_remote_port = devtools_remote_port
- args = [type,
- "--disable-fre",
- "--remote-debugging-port=%i" % 9222]
- if not options.dont_override_profile:
- logging.warning("Overriding of profile is not yet supported on android.")
- args.extend(options.extra_browser_args)
+ # Beginnings of a basic command line.
+ if is_content_shell:
+ pseudo_exec_name = "content_shell"
+ else:
+ pseudo_exec_name = "chrome"
+ args = [pseudo_exec_name,
+ "--disable-fre", "--no-first-run"]
# Kill old broser.
self._adb.KillAll(self._package)
self._adb.KillAll('forawrder')
self._adb.Forward('tcp:9222', self._devtools_remote_port)
+ # Set up temporary dir if needed. As far as we can tell, content_shell
+ # doesn't have persisted data, so --user-data-dir isn't needed.
+ if not is_content_shell and not options.dont_override_profile:
+ self._tmpdir = "/sdcard/chrome_remote_control_data"
+ self._adb.RunShellCommand('rm -r %s' % self._tmpdir)
+ args.append("--user-data-dir=%s" % self._tmpdir)
+
+ # Set up the command line.
+ args.extend(options.extra_browser_args)
+ with tempfile.NamedTemporaryFile() as f:
+ f.write(" ".join(args))
+ f.flush()
+ self._adb.Push(f.name, cmdline_file)
+
# Start it up!
self._adb.StartActivity(self._package,
self._activity,
diff --git a/tools/chrome_remote_control/chrome_remote_control/android_browser_finder.py b/tools/chrome_remote_control/chrome_remote_control/android_browser_finder.py
index 6c24202..8889883 100644
--- a/tools/chrome_remote_control/chrome_remote_control/android_browser_finder.py
+++ b/tools/chrome_remote_control/chrome_remote_control/android_browser_finder.py
@@ -6,8 +6,8 @@ import sys as real_sys
import subprocess as real_subprocess
import logging
-import android_browser_backend
-import android_commands as real_android_commands
+import chrome_remote_control.android_browser_backend as android_browser_backend
+import chrome_remote_control.adb_commands as real_adb_commands
import browser
import possible_browser
@@ -15,7 +15,6 @@ import possible_browser
"""Finds android browsers that can be controlled by chrome_remote_control."""
ALL_BROWSER_TYPES = 'android-content-shell'
-DEFAULT_BROWSER_TYPES_TO_RUN = 'android-content-shell'
# Commmand line
# content-shell: /data/local/tmp/content-shell-command-line
@@ -40,7 +39,7 @@ CHROME_DEVTOOLS_REMOTE_PORT = 'localabstract:chrome_devtools-remote'
CONTENT_SHELL_PACKAGE = 'org.chromium.content_shell'
CONTENT_SHELL_ACTIVITY = '.ContentShellActivity'
-CONTENT_SHELL_COMMAND_LINE = '/data/local/chrome-command-line'
+CONTENT_SHELL_COMMAND_LINE = '/data/local/tmp/content-shell-command-line'
CONTENT_SHELL_DEVTOOLS_REMOTE_PORT = (
'localabstract:content_shell_devtools_remote')
@@ -67,8 +66,10 @@ class PossibleAndroidBrowser(possible_browser.PossibleBrowser):
def FindAllAvailableBrowsers(options,
subprocess = real_subprocess,
- android_commands = real_android_commands):
+ adb_commands = real_adb_commands):
"""Finds all the desktop browsers available on this machine."""
+ if not adb_commands.IsAndroidSupported():
+ return []
browsers = []
# See if adb even works.
@@ -82,7 +83,7 @@ def FindAllAvailableBrowsers(options,
device = None
if not options.android_device:
- devices = android_commands.GetAttachedDevices()
+ devices = adb_commands.GetAttachedDevices()
else:
devices = []
@@ -97,13 +98,13 @@ def FindAllAvailableBrowsers(options,
device = devices[0]
- adb = android_commands.AndroidCommands(device=device)
+ adb = adb_commands.ADBCommands(device=device)
packages = adb.RunShellCommand('pm list packages')
if 'package:' + CONTENT_SHELL_PACKAGE in packages:
b = PossibleAndroidBrowser('android-content-shell',
options, adb,
- CONTENT_SHELL_PACKAGE,
+ CONTENT_SHELL_PACKAGE, True,
CONTENT_SHELL_COMMAND_LINE,
CONTENT_SHELL_ACTIVITY,
CONTENT_SHELL_DEVTOOLS_REMOTE_PORT)
diff --git a/tools/chrome_remote_control/chrome_remote_control/android_browser_finder_unittest.py b/tools/chrome_remote_control/chrome_remote_control/android_browser_finder_unittest.py
index bcef902..be0c6e3 100644
--- a/tools/chrome_remote_control/chrome_remote_control/android_browser_finder_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/android_browser_finder_unittest.py
@@ -19,7 +19,7 @@ class StubSubprocess(object):
raise Exception('Should not be reached.')
return self.call_hook(*args, **kwargs)
-class StubAndroidCommands(object):
+class StubADBCommands(object):
def __init__(self, module, device):
self._module = module
self._device = device
@@ -31,14 +31,17 @@ class StubAndroidCommands(object):
handler = self._module.shell_command_handlers[args[0]]
return handler(args)
-class StubAndroidCommandsModule(object):
+class StubADBCommandsModule(object):
def __init__(self):
self.attached_devices = []
self.shell_command_handlers = {}
- def StubAndroidCommandsConstructor(device=None):
- return StubAndroidCommands(self, device)
- self.AndroidCommands = StubAndroidCommandsConstructor
+ def StubADBCommandsConstructor(device=None):
+ return StubADBCommands(self, device)
+ self.ADBCommands = StubADBCommandsConstructor
+
+ def IsAndroidSupported(self):
+ return True
def GetAttachedDevices(self):
return self.attached_devices
@@ -60,9 +63,9 @@ class AndroidBrowserFinderTest(unittest.TestCase):
subprocess_stub = StubSubprocess()
subprocess_stub.call_hook = lambda *args, **kargs: 0
- android_commands_module_stub = StubAndroidCommandsModule()
+ adb_commands_module_stub = StubADBCommandsModule()
browsers = android_browser_finder.FindAllAvailableBrowsers(
- options, subprocess_stub, android_commands_module_stub)
+ options, subprocess_stub, adb_commands_module_stub)
self.assertEquals(0, len(browsers))
def test_adb_two_devices(self):
@@ -70,8 +73,8 @@ class AndroidBrowserFinderTest(unittest.TestCase):
subprocess_stub = StubSubprocess()
subprocess_stub.call_hook = lambda *args, **kargs: 0
- android_commands_module_stub = StubAndroidCommandsModule()
- android_commands_module_stub.attached_devices = ['015d14fec128220c',
+ adb_commands_module_stub = StubADBCommandsModule()
+ adb_commands_module_stub.attached_devices = ['015d14fec128220c',
'015d14fec128220d']
warnings = []
@@ -86,7 +89,7 @@ class AndroidBrowserFinderTest(unittest.TestCase):
logger.addFilter(temp_filter)
browsers = android_browser_finder.FindAllAvailableBrowsers(
- options, subprocess_stub, android_commands_module_stub)
+ options, subprocess_stub, adb_commands_module_stub)
finally:
logger.removeFilter(temp_filter)
self.assertEquals(1, len(warnings))
@@ -97,8 +100,8 @@ class AndroidBrowserFinderTest(unittest.TestCase):
subprocess_stub = StubSubprocess()
subprocess_stub.call_hook = lambda *args, **kargs: 0
- android_commands_module_stub = StubAndroidCommandsModule()
- android_commands_module_stub.attached_devices = ['015d14fec128220c']
+ adb_commands_module_stub = StubADBCommandsModule()
+ adb_commands_module_stub.attached_devices = ['015d14fec128220c']
def OnPM(args):
assert args[0] == 'pm'
@@ -107,8 +110,8 @@ class AndroidBrowserFinderTest(unittest.TestCase):
return ['package:org.chromium.content_shell',
'package.com.google.android.setupwizard']
- android_commands_module_stub.shell_command_handlers['pm'] = OnPM
+ adb_commands_module_stub.shell_command_handlers['pm'] = OnPM
browsers = android_browser_finder.FindAllAvailableBrowsers(
- options, subprocess_stub, android_commands_module_stub)
+ options, subprocess_stub, adb_commands_module_stub)
self.assertEquals(1, len(browsers))
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser.py b/tools/chrome_remote_control/chrome_remote_control/browser.py
index 925cec9..eb033ed 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser.py
@@ -13,11 +13,11 @@ import browser_finder
class Browser(object):
"""A running browser instance that can be controled in a limited way.
- To create a browser instance, use browser_finder.FindBestPossibleBrowser.
+ To create a browser instance, use browser_finder.FindBrowser.
Be sure to clean up after yourself by calling Close() when you are done with
the browser. Or better yet:
- browser_to_create = FindBestPossibleBrowser(options)
+ browser_to_create = FindBrowser(options)
with browser_to_create.Create() as browser:
... do all your operations on browser here
"""
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_backend.py b/tools/chrome_remote_control/chrome_remote_control/browser_backend.py
index bfe01a9..e041690 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_backend.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_backend.py
@@ -15,8 +15,8 @@ class BrowserGoneException(Exception):
class BrowserBackend(object):
"""A base class for broser backends. Provides basic functionality
once a remote-debugger port has been established."""
- def __init__(self):
- pass
+ def __init__(self, is_content_shell):
+ self.is_content_shell = is_content_shell
def __del__(self):
self.Close()
@@ -31,7 +31,10 @@ class BrowserBackend(object):
return False
else:
return True
- util.WaitFor(IsBrowserUp)
+ try:
+ util.WaitFor(IsBrowserUp, timeout=15)
+ except util.TimeoutException:
+ raise BrowserGoneException()
def _ListTabs(self, timeout=None):
if timeout:
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_finder.py b/tools/chrome_remote_control/chrome_remote_control/browser_finder.py
index e22635d..b0151e0 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_finder.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_finder.py
@@ -1,6 +1,8 @@
# 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 android_browser_finder
import desktop_browser_finder
@@ -10,42 +12,56 @@ ALL_BROWSER_TYPES = (
desktop_browser_finder.ALL_BROWSER_TYPES + "," +
android_browser_finder.ALL_BROWSER_TYPES)
-DEFAULT_BROWSER_TYPES_TO_RUN = (
- desktop_browser_finder.DEFAULT_BROWSER_TYPES_TO_RUN + "," +
- android_browser_finder.DEFAULT_BROWSER_TYPES_TO_RUN)
+class BrowserTypeRequiredException(Exception):
+ pass
-def FindBestPossibleBrowser(options):
+def FindBrowser(options):
"""Finds the best PossibleBrowser object to run given the provided
BrowserOptions object. The returned possiblity object can then be used to
connect to and control the located browser."""
+ if options.browser_type == 'exact' and options.browser_executable == None:
+ raise Exception("browser_type=exact requires browser_executable be set.")
+
+ if options.browser_type != 'exact' and options.browser_executable != None:
+ raise Exception("browser_executable requires browser_executable=exact.")
+
+ if options.browser_type == None:
+ raise BrowserTypeRequiredException("browser_type must be specified")
+
+ browsers = []
+ browsers.extend(desktop_browser_finder.FindAllAvailableBrowsers(options))
+ browsers.extend(android_browser_finder.FindAllAvailableBrowsers(options))
+
+ if options.browser_type == 'any':
+ types = ALL_BROWSER_TYPES.split(',')
+ def compare_browsers_on_type_priority(x, y):
+ x_idx = types.index(x.type)
+ y_idx = types.index(y.type)
+ return x_idx - y_idx
+ browsers.sort(compare_browsers_on_type_priority)
+ if len(browsers) >= 1:
+ return browsers[0]
+ else:
+ return None
- browsers = FindAllPossibleBrowsers(options)
- if len(browsers):
- return browsers[0]
- return None
+ matching_browsers = [b for b in browsers if b.type == options.browser_type]
+
+ if len(matching_browsers) == 1:
+ return matching_browsers[0]
+ elif len(matching_browsers) > 1:
+ logging.warning('Multiple browsers of the same type found: %s' % (
+ repr(matching_browsers)))
+ return matching_browsers[0]
+ else:
+ return None
def GetAllAvailableBrowserTypes(options):
"""Returns an array of browser types supported on this system."""
- browsers = FindAllPossibleBrowsers(options)
- type_set = set([browser.type for browser in browsers])
- type_list = list(type_list)
- type_list.sort()
- return type_list
-
-def FindAllPossibleBrowsers(options):
- """Finds all browsers that can be created given the options. Returns an array
- of PossibleBrowser objects, sorted and filtered by
- options.browser_types_to_use."""
browsers = []
browsers.extend(desktop_browser_finder.FindAllAvailableBrowsers(options))
browsers.extend(android_browser_finder.FindAllAvailableBrowsers(options))
- selected_browsers = [browser
- for browser in browsers
- if browser.type in options.browser_types_to_use]
- def compare_browsers_on_priority(x, y):
- x_idx = options.browser_types_to_use.index(x.type)
- y_idx = options.browser_types_to_use.index(y.type)
- return x_idx - y_idx
- selected_browsers.sort(compare_browsers_on_priority)
- return selected_browsers
+ type_list = set([browser.type for browser in browsers])
+ type_list = list(type_list)
+ type_list.sort()
+ return type_list
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_options.py b/tools/chrome_remote_control/chrome_remote_control/browser_options.py
index 55c90ba..793e4b2 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_options.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_options.py
@@ -2,34 +2,37 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import optparse
+import sys
+
import browser_finder
-class BrowserOptions(object):
+class BrowserOptions(optparse.Values):
"""Options to be used for disocvering and launching browsers."""
def __init__(self):
+ optparse.Values.__init__(self)
self.dont_override_profile = False
self.hide_stdout = True
self.browser_executable = None
- self._browser_types_to_use = (
- browser_finder.DEFAULT_BROWSER_TYPES_TO_RUN.split(","))
+ self._browser_type = None
self.chrome_root = None
self.android_device = None
self.extra_browser_args = []
def CreateParser(self, *args, **kwargs):
parser = optparse.OptionParser(*args, **kwargs)
+ parser.add_option('--browser',
+ dest='browser_type',
+ default=None,
+ help='Browser type to run, '
+ 'in order of priority. Supported values: list,%s' %
+ browser_finder.ALL_BROWSER_TYPES)
parser.add_option('--dont-override-profile', action='store_true',
dest='dont_override_profile',
help='Uses the regular user profile instead of a clean one')
parser.add_option('--browser-executable',
dest='browser_executable',
help='The exact browser to run.')
- parser.add_option('--browser-types-to-use',
- dest='browser_types_to_use',
- help='Comma-separated list of browsers to run, '
- 'in order of priority. Possible values: %s' %
- browser_finder.DEFAULT_BROWSER_TYPES_TO_RUN)
parser.add_option('--chrome-root',
dest='chrome_root',
help='Where to look for chrome builds.'
@@ -40,18 +43,27 @@ class BrowserOptions(object):
'If not specified, only 0 or 1 connected devcies are supported.')
real_parse = parser.parse_args
def ParseArgs(args=None):
+ defaults = parser.get_default_values()
+ for k, v in defaults.__dict__.items():
+ if k in self.__dict__:
+ continue
+ self.__dict__[k] = v
ret = real_parse(args, self)
+ if self.browser_executable and not self.browser_type:
+ self.browser_type = 'exact'
+ if not self.browser_executable and not self.browser_type:
+ sys.stderr.write("Must provide --browser=<type>\n")
+ sys.exit(1)
+ if self.browser_type == 'list':
+ import browser_finder
+ types = browser_finder.GetAllAvailableBrowserTypes(self)
+ sys.stderr.write("Available browsers:\n");
+ sys.stdout.write(" %s\n" % "\n ".join(types))
+ sys.exit(1)
return ret
parser.parse_args = ParseArgs
return parser
- def __getattr__(self, name):
- return None
-
- def __setattr__(self, name, value):
- object.__setattr__(self, name, value)
- return value
-
@property
def browser_types_to_use(self):
return self._browser_types_to_use
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_options_unittest.py b/tools/chrome_remote_control/chrome_remote_control/browser_options_unittest.py
index 520122e..d8e3d62 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_options_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_options_unittest.py
@@ -6,20 +6,47 @@ import unittest
import browser_options
class BrowserOptionsTest(unittest.TestCase):
- def testDirectMutability(self):
+ def testDefaults(self):
options = browser_options.BrowserOptions()
- # Should be possible to add new fields to the options object.
- options.x = 3
- self.assertEquals(3, options.x)
+ parser = options.CreateParser()
+ parser.add_option('-x', action='store', default=3)
+ parser.parse_args(['--browser', 'any'])
+ self.assertEquals(options.x, 3)
+
+ def testDefaultsPlusOverride(self):
+ options = browser_options.BrowserOptions()
+ parser = options.CreateParser()
+ parser.add_option('-x', action='store', default=3)
+ parser.parse_args(['--browser', 'any', '-x', 10])
+ self.assertEquals(options.x, 10)
+
+ def testDefaultsDontClobberPresetValue(self):
+ options = browser_options.BrowserOptions()
+ setattr(options, 'x', 7)
+ parser = options.CreateParser()
+ parser.add_option('-x', action='store', default=3)
+ parser.parse_args(['--browser', 'any'])
+ self.assertEquals(options.x, 7)
+
+ def testCount0(self):
+ options = browser_options.BrowserOptions()
+ parser = options.CreateParser()
+ parser.add_option('-v', action='count', dest='v')
+ parser.parse_args(['--browser', 'any'])
+ self.assertEquals(options.v, None)
- # Unset fields on the options object should default to None.
- self.assertEquals(None, options.y)
+ def testCount2(self):
+ options = browser_options.BrowserOptions()
+ parser = options.CreateParser()
+ parser.add_option('-v', action='count', dest='v')
+ parser.parse_args(['--browser', 'any', '-vv'])
+ self.assertEquals(options.v, 2)
def testOptparseMutabilityWhenSpecified(self):
options = browser_options.BrowserOptions()
parser = options.CreateParser()
- parser.add_option("-v", dest="verbosity", action="store_true")
- options_ret, args = parser.parse_args(["-v"])
+ parser.add_option('-v', dest='verbosity', action='store_true')
+ options_ret, args = parser.parse_args(['--browser', 'any', '-v'])
self.assertEquals(options_ret, options)
self.assertTrue(options.verbosity)
@@ -27,7 +54,7 @@ class BrowserOptionsTest(unittest.TestCase):
options = browser_options.BrowserOptions()
parser = options.CreateParser()
- parser.add_option("-v", dest="verbosity", action="store_true")
- options_ret, args = parser.parse_args([])
+ parser.add_option('-v', dest='verbosity', action='store_true')
+ options_ret, args = parser.parse_args(['--browser', 'any'])
self.assertEquals(options_ret, options)
self.assertFalse(options.verbosity)
diff --git a/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py b/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py
index c193059..24f856e 100644
--- a/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/browser_unittest.py
@@ -10,7 +10,7 @@ class BrowserTest(unittest.TestCase):
def testBasic(self):
options = browser_options.options_for_unittests
options.browser_to_use = browser_finder.ALL_BROWSER_TYPES
- browser_to_create = browser_finder.FindBestPossibleBrowser(options)
+ browser_to_create = browser_finder.FindBrowser(options)
if not browser_to_create:
raise Exception('No browser found, cannot continue test.')
with browser_to_create.Create() as b:
@@ -18,3 +18,28 @@ class BrowserTest(unittest.TestCase):
# Different browsers boot up to different things
assert b.GetNthTabUrl(0)
+
+ def testCommandLineOverriding(self):
+ # This test starts the browser with --enable-benchmarking, which should
+ # create a chrome.Interval namespace. This tests whether the command line is
+ # being set.
+ options = browser_options.options_for_unittests
+ options.browser_to_use = browser_finder.ALL_BROWSER_TYPES
+ testJS = ("window.chrome.gpuBenchmarking !== undefined ||" +
+ "chrome.Interval !== undefined")
+
+ flag1 = "--enable-benchmarking"
+ flag2 = "--enable-gpu-benchmarking"
+ options.extra_browser_args.append(flag1)
+ options.extra_browser_args.append(flag2)
+ try:
+ browser_to_create = browser_finder.FindBrowser(options)
+ with browser_to_create.Create() as b:
+ with b.ConnectToNthTab(0) as t:
+ t.page.Navigate("http://www.google.com/")
+ t.WaitForDocumentReadyStateToBeInteractiveOrBetter()
+ self.assertTrue(t.runtime.Evaluate(testJS))
+
+ finally:
+ options.extra_browser_args.remove(flag2)
+ options.extra_browser_args.remove(flag1)
diff --git a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py
index d52f0c0..712dc07 100644
--- a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py
+++ b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_backend.py
@@ -11,6 +11,7 @@ import browser_backend
import browser_finder
import inspector_backend
import tab
+import util
DEFAULT_PORT = 9273
@@ -18,8 +19,8 @@ class DesktopBrowserBackend(browser_backend.BrowserBackend):
"""The backend for controlling a locally-executed browser instance, on Linux,
Mac or Windows.
"""
- def __init__(self, options, executable):
- super(DesktopBrowserBackend, self).__init__()
+ def __init__(self, options, executable, is_content_shell):
+ super(DesktopBrowserBackend, self).__init__(is_content_shell)
# Initialize fields so that an explosion during init doesn't break in Close.
self._proc = None
@@ -30,12 +31,12 @@ class DesktopBrowserBackend(browser_backend.BrowserBackend):
if not self._executable:
raise Exception("Cannot create browser, no executable found!")
- self._tmpdir = tempfile.mkdtemp()
self._port = DEFAULT_PORT
args = [self._executable,
"--no-first-run",
"--remote-debugging-port=%i" % self._port]
if not options.dont_override_profile:
+ self._tmpdir = tempfile.mkdtemp()
args.append("--user-data-dir=%s" % self._tmpdir)
args.extend(options.extra_browser_args)
if options.hide_stdout:
@@ -60,12 +61,34 @@ class DesktopBrowserBackend(browser_backend.BrowserBackend):
def Close(self):
if self._proc:
+
+ def IsClosed():
+ if not self._proc:
+ return True
+ return self._proc.poll() != None
+
+ # Try to politely shutdown, first.
self._proc.terminate()
- self._proc.wait()
- self._proc = None
+ try:
+ util.WaitFor(IsClosed, timeout=1)
+ self._proc = None
+ except util.TimeoutException:
+ pass
- if os.path.exists(self._tmpdir):
+ # Kill it.
+ if not IsClosed():
+ self._proc.kill()
+ try:
+ util.WaitFor(IsClosed, timeout=5)
+ self._proc = None
+ except util.TimeoutException:
+ self._proc = None
+ raise Exception("Could not shutdown the browser.")
+
+ if self._tmpdir and os.path.exists(self._tmpdir):
shutil.rmtree(self._tmpdir, ignore_errors=True)
+ self._tmpdir = None
if self._devnull:
self._devnull.close()
+ self._devnull = None
diff --git a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder.py b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder.py
index 76cbbc3..b4ca1a2 100644
--- a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder.py
+++ b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder.py
@@ -13,21 +13,21 @@ import possible_browser
"""Finds desktop browsers that can be controlled by chrome_remote_control."""
ALL_BROWSER_TYPES = "exact,release,debug,canary,system"
-DEFAULT_BROWSER_TYPES_TO_RUN = "exact,release,canary,system"
class PossibleDesktopBrowser(possible_browser.PossibleBrowser):
"""A desktop browser that can be controlled."""
- def __init__(self, type, options, executable):
+ def __init__(self, type, options, executable, is_content_shell):
super(PossibleDesktopBrowser, self).__init__(type, options)
self._local_executable = executable
+ self._is_content_shell = is_content_shell
def __repr__(self):
return "PossibleDesktopBrowser(type=%s)" % self.type
def Create(self):
backend = desktop_browser_backend.DesktopBrowserBackend(
- self._options, self._local_executable)
+ self._options, self._local_executable, self._is_content_shell)
return browser.Browser(backend)
def FindAllAvailableBrowsers(options,
@@ -46,7 +46,7 @@ def FindAllAvailableBrowsers(options,
if options.browser_executable:
if os.path.exists(options.browser_executable):
browsers.append(PossibleDesktopBrowser("exact", options,
- options.browser_executable))
+ options.browser_executable, False))
# Look for a browser in the standard chrome build locations.
if options.chrome_root:
@@ -70,11 +70,13 @@ def FindAllAvailableBrowsers(options,
debug_app = os.path.join(chrome_root, build_dir, "Debug", app_name)
if os.path.exists(debug_app):
- browsers.append(PossibleDesktopBrowser("debug", options, debug_app))
+ browsers.append(PossibleDesktopBrowser("debug", options,
+ debug_app, False))
release_app = os.path.join(chrome_root, build_dir, "Release", app_name)
if os.path.exists(release_app):
- browsers.append(PossibleDesktopBrowser("release", options, release_app))
+ browsers.append(PossibleDesktopBrowser("release", options,
+ release_app, False))
# Mac-specific options.
if sys.platform == 'darwin':
@@ -82,10 +84,12 @@ def FindAllAvailableBrowsers(options,
"Contents/MacOS/Google Chrome Canary")
mac_system = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
if os.path.exists(mac_canary):
- browsers.append(PossibleDesktopBrowser("canary", options, mac_canary))
+ browsers.append(PossibleDesktopBrowser("canary", options,
+ mac_canary, False))
if os.path.exists(mac_system):
- browsers.append(PossibleDesktopBrowser("system", options, mac_system))
+ browsers.append(PossibleDesktopBrowser("system", options,
+ mac_system, False))
# Linux specific options.
if sys.platform.startswith('linux'):
@@ -99,7 +103,8 @@ def FindAllAvailableBrowsers(options,
pass
if found:
browsers.append(
- PossibleDesktopBrowser("system", options, 'google-chrome'))
+ PossibleDesktopBrowser("system", options,
+ 'google-chrome', False))
# Win32-specific options.
if sys.platform.startswith('win') and os.getenv('LOCALAPPDATA'):
@@ -109,10 +114,12 @@ def FindAllAvailableBrowsers(options,
win_system = os.path.join(local_app_data,
'Google\\Chrome\\Application\\chrome.exe')
if os.path.exists(win_canary):
- browsers.append(PossibleDesktopBrowser("canary", options, win_canary))
+ browsers.append(PossibleDesktopBrowser("canary", options,
+ win_canary, False))
if os.path.exists(win_system):
- browsers.append(PossibleDesktopBrowser("system", options, win_system))
+ browsers.append(PossibleDesktopBrowser("system", options,
+ win_system, False))
if len(browsers) and not has_display:
logging.warning('Found (%s), but you have a DISPLAY environment set.' %
diff --git a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder_unittest.py b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder_unittest.py
index 9eed53f..8cb8ea8 100644
--- a/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/desktop_browser_finder_unittest.py
@@ -145,7 +145,6 @@ class LinuxFindTest(FindTestBase):
self.assertEquals([], self.DoFindAllTypes())
def testFindUsingRelease(self):
- self._options.browser_types_to_use.append("debug")
self.assertTrue("release" in self.DoFindAllTypes())
class WinFindTest(FindTestBase):
diff --git a/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py b/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py
index e7889e5..ea85910 100644
--- a/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py
+++ b/tools/chrome_remote_control/chrome_remote_control/inspector_backend.py
@@ -2,9 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
+import logging
+import socket
import time
import websocket
-import socket
class InspectorException(Exception):
pass
@@ -15,7 +16,6 @@ class InspectorBackend(object):
self._descriptor = descriptor
self._socket = websocket.create_connection(
descriptor["webSocketDebuggerUrl"]);
- self._socket.settimeout(0.5)
self._next_request_id = 0
self._domain_handlers = {}
@@ -28,19 +28,44 @@ class InspectorBackend(object):
self._socket = None
self._backend = None
- def SyncRequest(self, req):
+ def DispatchNotifications(self):
+ try:
+ data = self._socket.recv()
+ except socket.error:
+ return None
+
+ res = json.loads(data)
+ logging.debug("got [%s]", data)
+ if "method" not in res:
+ return
+
+ mname = res["method"]
+ dot_pos = mname.find(".")
+ domain_name = mname[:dot_pos]
+ if domain_name in self._domain_handlers:
+ try:
+ self._domain_handlers[domain_name][0](res)
+ except:
+ import traceback
+ traceback.print_exc()
+
+ def SendAndIgnoreResponse(self, req):
+ req["id"] = self._next_request_id
+ self._next_request_id += 1
+ self._socket.send(json.dumps(req))
+
+ def SyncRequest(self, req, timeout=60):
+ # TODO(nduca): Listen to the timeout argument
+ # self._socket.settimeout(timeout)
req["id"] = self._next_request_id
self._next_request_id += 1
self._socket.send(json.dumps(req))
+
while True:
- try:
- data = self._socket.recv()
- except socket.error:
- req["id"] = self._next_request_id
- self._next_request_id += 1
- self._socket.send(json.dumps(req))
- continue
+ data = self._socket.recv()
+
res = json.loads(data)
+ logging.debug("got [%s]", data)
if "method" in res:
mname = res["method"]
dot_pos = mname.find(".")
@@ -54,6 +79,7 @@ class InspectorBackend(object):
continue
if res["id"] != req["id"]:
+ logging.debug("Dropped reply: %s", json.dumps(res))
continue
return res
diff --git a/tools/chrome_remote_control/chrome_remote_control/run_tests.py b/tools/chrome_remote_control/chrome_remote_control/run_tests.py
index 7f68ee9..40505dd 100644
--- a/tools/chrome_remote_control/chrome_remote_control/run_tests.py
+++ b/tools/chrome_remote_control/chrome_remote_control/run_tests.py
@@ -2,6 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import fnmatch
+import logging
import os
import sys
import traceback
@@ -15,7 +16,6 @@ def Discover(start_dir, pattern = "test*.py", top_level_dir = None):
pattern,
top_level_dir)
- # TODO(nduca): Do something with top_level_dir non-None
modules = []
for (dirpath, dirnames, filenames) in os.walk(start_dir):
for filename in filenames:
@@ -28,7 +28,9 @@ def Discover(start_dir, pattern = "test*.py", top_level_dir = None):
if filename.startswith('.') or filename.startswith('_'):
continue
name,ext = os.path.splitext(filename)
- fqn = dirpath.replace('/', '.') + '.' + name
+
+ relpath = os.path.relpath(dirpath, top_level_dir)
+ fqn = relpath.replace('/', '.') + '.' + name
# load the module
try:
@@ -67,43 +69,53 @@ def FilterSuite(suite, predicate):
return new_suite
-def DiscoverAndRunTests(args):
- dir_name = os.path.join(os.path.dirname(__file__), "..")
- olddir = os.getcwd()
- try:
- os.chdir(dir_name)
- suite = Discover("chrome_remote_control", "*_unittest.py", ".")
+def DiscoverAndRunTests(dir_name, args, top_level_dir):
+ suite = Discover(dir_name, "*_unittest.py", top_level_dir)
- def IsTestSelected(test):
- if len(args) == 0:
+ def IsTestSelected(test):
+ if len(args) == 0:
+ return True
+ for name in args:
+ if str(test).find(name) != -1:
return True
- for name in args:
- if str(test).find(name) != -1:
- return True
- return False
+ return False
- filtered_suite = FilterSuite(suite, IsTestSelected)
- runner = unittest.TextTestRunner(verbosity = 2)
- test_result = runner.run(filtered_suite)
- return len(test_result.errors) + len(test_result.failures)
+ filtered_suite = FilterSuite(suite, IsTestSelected)
+ runner = unittest.TextTestRunner(verbosity = 2)
+ test_result = runner.run(filtered_suite)
+ return len(test_result.errors) + len(test_result.failures)
- finally:
- os.chdir(olddir)
- return 1
-
-def Main(args):
+def Main(args, start_dir, top_level_dir):
"""Unit test suite that collects all test cases for chrome_remote_control."""
default_options = browser_options.BrowserOptions()
+ default_options.browser_type = 'any'
+
parser = default_options.CreateParser("run_tests [options] [test names]")
+ parser.add_option(
+ '-v', '--verbose', action='count', dest="verbosity",
+ help='Increase verbosity level (repeat as needed)')
+ parser.add_option('--repeat-count', dest='run_test_repeat_count',
+ type='int', default=1,
+ help="Repeats each a provided number of times.")
+
_, args = parser.parse_args(args)
+ if default_options.verbosity >= 2:
+ logging.basicConfig(level=logging.DEBUG)
+ elif default_options.verbosity:
+ logging.basicConfig(level=logging.INFO)
+ else:
+ logging.basicConfig(level=logging.WARNING)
+
browser_options.options_for_unittests = default_options
+ olddir = os.getcwd()
+ num_errors = 0
try:
- DiscoverAndRunTests(args)
+ os.chdir(top_level_dir)
+ for i in range(default_options.run_test_repeat_count):
+ num_errors += DiscoverAndRunTests(start_dir, args, top_level_dir)
finally:
+ os.chdir(olddir)
browser_options.options_for_unittests = None
-
-
-if __name__ == "__main__":
- sys.exit(Main(sys.argv[1:]))
+ return num_errors
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab.py b/tools/chrome_remote_control/chrome_remote_control/tab.py
index d4766f6..976eee0 100644
--- a/tools/chrome_remote_control/chrome_remote_control/tab.py
+++ b/tools/chrome_remote_control/chrome_remote_control/tab.py
@@ -6,18 +6,25 @@ import websocket
import socket
import time
+import tab_page
import tab_runtime
import util
+DEFAULT_TAB_TIMEOUT=60
+
class Tab(object):
def __init__(self, inspector_backend):
self._inspector_backend = inspector_backend
+ self.page = tab_page.TabPage(self._inspector_backend)
self.runtime = tab_runtime.TabRuntime(self._inspector_backend)
+
def __del__(self):
self.Close()
def Close(self):
+ self.page = None
+ self.runtime = None
if self._inspector_backend:
self._inspector_backend.Close()
self._inspector_backend = None
@@ -28,31 +35,13 @@ class Tab(object):
def __exit__(self, *args):
self.Close()
- def BeginToLoadUrl(self, url):
- # In order to tell when the document has actually changed,
- # we go to about:blank first and wait. When that has happened, we
- # to go the new URL and detect the document being non-about:blank as
- # indication that the new document is loading.
- self.runtime.Evaluate('document.location = "about:blank";')
- util.WaitFor(lambda:
- self.runtime.Evaluate('document.location.href') == 'about:blank')
-
- self.runtime.Evaluate('document.location = "%s";' % url)
- util.WaitFor(lambda:
- self.runtime.Evaluate('document.location.href') != 'about:blank')
-
- def LoadUrl(self, url):
- self.BeginToLoadUrl(url)
- # TODO(dtu): Detect HTTP redirects.
- time.sleep(2) # Wait for unpredictable redirects.
- self.WaitForDocumentReadyStateToBeInteractiveOrBetter()
-
- def WaitForDocumentReadyStateToBeComplete(self):
+ def WaitForDocumentReadyStateToBeComplete(self, timeout=60):
util.WaitFor(
- lambda: self.runtime.Evaluate('document.readyState') == 'complete')
+ lambda: self.runtime.Evaluate('document.readyState') == 'complete',
+ timeout)
- def WaitForDocumentReadyStateToBeInteractiveOrBetter(self):
+ def WaitForDocumentReadyStateToBeInteractiveOrBetter(self, timeout=60):
def IsReadyStateInteractiveOrBetter():
rs = self.runtime.Evaluate('document.readyState')
return rs == 'complete' or rs == 'interactive'
- util.WaitFor(IsReadyStateInteractiveOrBetter)
+ util.WaitFor(IsReadyStateInteractiveOrBetter, timeout)
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab_page.py b/tools/chrome_remote_control/chrome_remote_control/tab_page.py
new file mode 100644
index 0000000..fbf7dea
--- /dev/null
+++ b/tools/chrome_remote_control/chrome_remote_control/tab_page.py
@@ -0,0 +1,67 @@
+# 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 json
+import logging
+import urlparse
+
+import inspector_backend
+import util
+
+class TabPage(object):
+ def __init__(self, inspector_backend):
+ self._inspector_backend = inspector_backend
+ self._inspector_backend.RegisterDomain(
+ 'Page',
+ self._OnNotification,
+ self._OnClose)
+ self._pending_navigate_url = None
+
+ def _OnNotification(self, msg):
+ logging.debug("Notification: %s", json.dumps(msg, indent=2))
+ if msg["method"] == "Page.frameNavigated" and self._pending_navigate_url:
+ url = msg["params"]["frame"]["url"]
+ if not url == "chrome://newtab/":
+ # Marks the navigation as complete and unblocks the navigate call.
+ self._pending_navigate_url = None
+
+ def _OnClose(self):
+ pass
+
+ def Navigate(self, url, timeout=60):
+ """Navigates to url"""
+ # Turn on notifications. We need them to get the Page.frameNavigated event.
+ request = {
+ "method": "Page.enable"
+ }
+ res = self._inspector_backend.SyncRequest(request, timeout)
+ assert len(res["result"].keys()) == 0
+
+ # Navigate the page. However, there seems to be a bug in chrome devtools
+ # protocol where the request id for this event gets held on the browser side
+ # pretty much indefinitely.
+ #
+ # So, instead of waiting for the event to actually complete, wait for the
+ # Page.frameNavigated event.
+ request = {
+ "method": "Page.navigate",
+ "params": {
+ "url": url,
+ }
+ }
+ res = self._inspector_backend.SendAndIgnoreResponse(request)
+
+ self._pending_navigate_url = url
+ def IsNavigationDone():
+ self._inspector_backend.DispatchNotifications()
+ return self._pending_navigate_url == None
+
+ util.WaitFor(IsNavigationDone, timeout)
+
+ # Turn off notifications.
+ request = {
+ "method": "Page.disable"
+ }
+ res = self._inspector_backend.SyncRequest(request, timeout)
+ assert len(res["result"].keys()) == 0
+
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab_page_unittest.py b/tools/chrome_remote_control/chrome_remote_control/tab_page_unittest.py
new file mode 100644
index 0000000..3586c06
--- /dev/null
+++ b/tools/chrome_remote_control/chrome_remote_control/tab_page_unittest.py
@@ -0,0 +1,43 @@
+# 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 browser
+import browser_finder
+import browser_options
+import tab_page
+import unittest
+
+class TabPageTest(unittest.TestCase):
+ def setUp(self):
+ self._browser = None
+ self._tab = None
+ options = browser_options.options_for_unittests
+ browser_to_create = browser_finder.FindBrowser(options)
+ if not browser_to_create:
+ raise Exception('No browser found, cannot continue test.')
+ try:
+ self._browser = browser_to_create.Create()
+ self._tab = self._browser.ConnectToNthTab(0)
+ except:
+ self.tearDown()
+ raise
+
+ def tearDown(self):
+ if self._tab:
+ self._tab.Close()
+ if self._browser:
+ self._browser.Close()
+
+ def testPageNavigateToNormalUrl(self):
+ res = self._tab.page.Navigate("http://www.google.com")
+ self._tab.WaitForDocumentReadyStateToBeComplete()
+
+ def testPageNavigateToUrlChanger(self):
+ # The Url that we actually load is http://www.youtube.com/.
+ res = self._tab.page.Navigate("http://youtube.com/")
+
+ self._tab.WaitForDocumentReadyStateToBeComplete()
+
+ def testPageNavigateToImpossibleURL(self):
+ res = self._tab.page.Navigate("http://23f09f0f9fsdflajsfaldfkj2f3f.com")
+ self._tab.WaitForDocumentReadyStateToBeComplete()
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py b/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py
index de73892..827e1c28 100644
--- a/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py
+++ b/tools/chrome_remote_control/chrome_remote_control/tab_runtime.py
@@ -20,14 +20,14 @@ class TabRuntime(object):
def _OnClose(self):
pass
- def Execute(self, expr):
+ def Execute(self, expr, timeout=60):
"""Executes expr
If the expression failed to evaluate, EvaluateException will be raised.
"""
- self.Evaluate(expr + "; 0;");
+ self.Evaluate(expr + "; 0;", timeout=60);
- def Evaluate(self, expr):
+ def Evaluate(self, expr, timeout=60):
"""Evalutes expr and returns the JSONized result.
Consider using Execute for cases where the result of the expression is not
@@ -46,7 +46,7 @@ class TabRuntime(object):
"returnByValue": True
}
}
- res = self._inspector_backend.SyncRequest(request)
+ res = self._inspector_backend.SyncRequest(request, timeout)
if "error" in res:
raise EvaluateException(res["error"]["message"])
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab_runtime_unittest.py b/tools/chrome_remote_control/chrome_remote_control/tab_runtime_unittest.py
index a43a327..65f3a3a 100644
--- a/tools/chrome_remote_control/chrome_remote_control/tab_runtime_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/tab_runtime_unittest.py
@@ -12,7 +12,7 @@ class TabRuntimeTest(unittest.TestCase):
self._browser = None
self._tab = None
options = browser_options.options_for_unittests
- browser_to_create = browser_finder.FindBestPossibleBrowser(options)
+ browser_to_create = browser_finder.FindBrowser(options)
if not browser_to_create:
raise Exception('No browser found, cannot continue test.')
try:
@@ -37,13 +37,18 @@ class TabRuntimeTest(unittest.TestCase):
lambda: self._tab.runtime.Evaluate("fsdfsdfsf"))
def testRuntimeEvaluateOfSomethingThatCantJSONize(self):
- # TODO(nduca): This fails on Android. I wonder why?
- self.assertRaises(tab_runtime.EvaluateException,
- lambda: self._tab.runtime.Evaluate("window"))
- pass
+
+ def test():
+ self._tab.runtime.Evaluate("""
+ var cur = {}
+ var root = {next:cur};
+ for(var i = 0; i < 1000; i++) {
+ next = {};
+ cur.next = next;
+ cur = next;
+ }
+ root;""")
+ self.assertRaises(tab_runtime.EvaluateException, test)
def testRuntimeExecuteOfSomethingThatCantJSONize(self):
self._tab.runtime.Execute("window");
-
- def testRuntimeLoadUrl(self):
- self._tab.BeginToLoadUrl("http://www.google.com")
diff --git a/tools/chrome_remote_control/chrome_remote_control/tab_unittest.py b/tools/chrome_remote_control/chrome_remote_control/tab_unittest.py
index c5e1bef..289efe0 100644
--- a/tools/chrome_remote_control/chrome_remote_control/tab_unittest.py
+++ b/tools/chrome_remote_control/chrome_remote_control/tab_unittest.py
@@ -12,7 +12,7 @@ class TabTest(unittest.TestCase):
self._browser = None
self._tab = None
options = browser_options.options_for_unittests
- browser_to_create = browser_finder.FindBestPossibleBrowser(options)
+ browser_to_create = browser_finder.FindBrowser(options)
if not browser_to_create:
raise Exception('No browser found, cannot continue test.')
try:
@@ -28,10 +28,10 @@ class TabTest(unittest.TestCase):
if self._browser:
self._browser.Close()
- def testLoadUrlAndWaitToForCompleteState(self):
- self._tab.BeginToLoadUrl("http://www.google.com")
+ def testNavigateAndWaitToForCompleteState(self):
+ self._tab.page.Navigate("http://www.google.com")
self._tab.WaitForDocumentReadyStateToBeComplete()
- def testLoadUrlAndWaitToForInteractiveState(self):
- self._tab.BeginToLoadUrl("http://www.google.com")
+ def testNavigateAndWaitToForInteractiveState(self):
+ self._tab.page.Navigate("http://www.google.com")
self._tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
diff --git a/tools/chrome_remote_control/chrome_remote_control/util.py b/tools/chrome_remote_control/chrome_remote_control/util.py
index ec2df2b..5ea4fbd 100644
--- a/tools/chrome_remote_control/chrome_remote_control/util.py
+++ b/tools/chrome_remote_control/chrome_remote_control/util.py
@@ -4,31 +4,18 @@
import inspect
import time
-_timeout = 60
-
class TimeoutException(Exception):
pass
-class TimeoutChanger(object):
- def __init__(self, new_timeout):
- self._timeout = new_timeout
-
- def __enter__(self):
- _timeout, self._timeout = self._timeout, _timeout
- return self
-
- def __exit__(self, *args):
- _timeout = self._timeout
-
-def WaitFor(condition):
+def WaitFor(condition, timeout):
assert isinstance(condition, type(lambda: None)) # is function
start_time = time.time()
while not condition():
- if time.time() - start_time > _timeout:
+ if time.time() - start_time > timeout:
if condition.__name__ == '<lambda>':
condition_string = inspect.getsource(condition).strip()
else:
condition_string = condition.__name__
raise TimeoutException('Timed out while waiting %ds for %s.' %
- (_timeout, condition_string))
+ (timeout, condition_string))
time.sleep(0.01)
diff --git a/tools/chrome_remote_control/chrome_remote_control/util_unittest.py b/tools/chrome_remote_control/chrome_remote_control/util_unittest.py
new file mode 100644
index 0000000..7050975
--- /dev/null
+++ b/tools/chrome_remote_control/chrome_remote_control/util_unittest.py
@@ -0,0 +1,17 @@
+# 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 unittest
+
+import util
+
+class TestWait(unittest.TestCase):
+ def testNonTimeout(self):
+ def test():
+ return True
+ util.WaitFor(test, 0.1)
+
+ def testTimeout(self):
+ def test():
+ return False
+ self.assertRaises(util.TimeoutException, lambda: util.WaitFor(test, 0.1))
diff --git a/tools/chrome_remote_control/chrome_remote_control/websocket.py b/tools/chrome_remote_control/chrome_remote_control/websocket.py
index 6f31fb9..99c5b84 100644
--- a/tools/chrome_remote_control/chrome_remote_control/websocket.py
+++ b/tools/chrome_remote_control/chrome_remote_control/websocket.py
@@ -12,4 +12,6 @@ def __init__():
sys.path.append(ws_path)
__init__()
+
from websocket import *
+
diff --git a/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py b/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py
index 000032c..3fa7976 100755
--- a/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py
+++ b/tools/chrome_remote_control/examples/rendering_microbenchmark_test.py
@@ -29,7 +29,7 @@ def Main(args):
urls.append(url)
options.extra_browser_args.append("--enable-gpu-benchmarking")
- browser_to_create = chrome_remote_control.FindBestPossibleBrowser(options)
+ browser_to_create = chrome_remote_control.FindBrowser(options)
if not browser_to_create:
sys.stderr.write("No browser found! Supported types: %s" %
chrome_remote_control.GetAllAvailableBrowserTypes())
@@ -37,7 +37,8 @@ def Main(args):
with browser_to_create.Create() as b:
with b.ConnectToNthTab(0) as tab:
# Check browser for benchmark API. Can only be done on non-chrome URLs.
- tab.BeginToLoadUrl("http://www.google.com")
+ tab.page.Navigate("http://www.google.com")
+ import time; time.sleep(2)
tab.WaitForDocumentReadyStateToBeComplete()
if tab.runtime.Evaluate("window.chrome.gpuBenchmarking === undefined"):
print "Browser does not support gpu benchmarks API."
@@ -63,7 +64,7 @@ def Main(args):
print ",".join(cols)
for u in urls:
- tab.BeginToLoadUrl(u)
+ tab.page.Navigate(u)
tab.WaitForDocumentReadyStateToBeInteractiveOrBetter()
results = tab.runtime.Evaluate(
"window.chrome.gpuBenchmarking.runRenderingBenchmarks();")
diff --git a/tools/chrome_remote_control/examples/top1k b/tools/chrome_remote_control/examples/top1k
index a11f26e..f32a38c 100644
--- a/tools/chrome_remote_control/examples/top1k
+++ b/tools/chrome_remote_control/examples/top1k
@@ -1,12 +1,12 @@
youtube.com
-yahoo.com
-baidu.com
wikipedia.org
live.com
twitter.com
+baidu.com
qq.com
amazon.com
blogspot.com
+yahoo.com
linkedin.com
taobao.com
yahoo.co.jp
diff --git a/tools/chrome_remote_control/run_tests b/tools/chrome_remote_control/run_tests
index 4775c69..36b4198 100755
--- a/tools/chrome_remote_control/run_tests
+++ b/tools/chrome_remote_control/run_tests
@@ -1,5 +1,16 @@
-#!/bin/sh
+#!/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.
-/usr/bin/env python -m chrome_remote_control.run_tests $*
+import os
+import sys
+
+import chrome_remote_control.run_tests
+
+if __name__ == "__main__":
+ top_level_dir = os.path.abspath(
+ os.path.dirname(__file__))
+ start_dir = "chrome_remote_control"
+ ret = chrome_remote_control.run_tests.Main(
+ sys.argv[1:], start_dir, top_level_dir)
+ sys.exit(ret)