diff options
author | nduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-05 00:58:53 +0000 |
---|---|---|
committer | nduca@chromium.org <nduca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-05 00:58:53 +0000 |
commit | 953d04a25a27bc6a81e4420b04d2b21c738db506 (patch) | |
tree | b6dfeea7200735e58303f409adedd4ad5ab718d6 /tools/chrome_remote_control | |
parent | 41c444da42aa6ad0f10b69826058322100157ad7 (diff) | |
download | chromium_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')
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) |