| OLD | NEW |
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 # Copyright (c) 2010 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2010 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
| 6 | 6 |
| 7 """PyAuto: Python Interface to Chromium's Automation Proxy. | 7 """PyAuto: Python Interface to Chromium's Automation Proxy. |
| 8 | 8 |
| 9 PyAuto uses swig to expose Automation Proxy interfaces to Python. | 9 PyAuto uses swig to expose Automation Proxy interfaces to Python. |
| 10 For complete documentation on the functionality available, | 10 For complete documentation on the functionality available, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 This script can be used as an executable to fire off other scripts, similar | 23 This script can be used as an executable to fire off other scripts, similar |
| 24 to unittest.py | 24 to unittest.py |
| 25 python pyauto.py test_script | 25 python pyauto.py test_script |
| 26 """ | 26 """ |
| 27 | 27 |
| 28 import logging | 28 import logging |
| 29 import optparse | 29 import optparse |
| 30 import os | 30 import os |
| 31 import shutil | 31 import shutil |
| 32 import signal | 32 import signal |
| 33 import stat |
| 33 import subprocess | 34 import subprocess |
| 34 import sys | 35 import sys |
| 35 import tempfile | 36 import tempfile |
| 36 import time | 37 import time |
| 37 import types | 38 import types |
| 38 import unittest | 39 import unittest |
| 39 import urllib | 40 import urllib |
| 40 | 41 |
| 41 | 42 |
| 42 def _LocateBinDirs(): | 43 def _LocateBinDirs(): |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 | 81 |
| 81 # Should go after sys.path is set appropriately | 82 # Should go after sys.path is set appropriately |
| 82 import bookmark_model | 83 import bookmark_model |
| 83 import download_info | 84 import download_info |
| 84 import history_info | 85 import history_info |
| 85 import omnibox_info | 86 import omnibox_info |
| 86 import plugins_info | 87 import plugins_info |
| 87 import prefs_info | 88 import prefs_info |
| 88 from pyauto_errors import JSONInterfaceError | 89 from pyauto_errors import JSONInterfaceError |
| 89 from pyauto_errors import NTPThumbnailNotShownError | 90 from pyauto_errors import NTPThumbnailNotShownError |
| 91 import pyauto_utils |
| 90 import simplejson as json # found in third_party | 92 import simplejson as json # found in third_party |
| 91 | 93 |
| 92 _HTTP_SERVER = None | 94 _HTTP_SERVER = None |
| 93 _OPTIONS = None | 95 _OPTIONS = None |
| 94 | 96 |
| 95 | 97 |
| 96 class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): | 98 class PyUITest(pyautolib.PyUITestBase, unittest.TestCase): |
| 97 """Base class for UI Test Cases in Python. | 99 """Base class for UI Test Cases in Python. |
| 98 | 100 |
| 99 A browser is created before executing each test, and is destroyed after | 101 A browser is created before executing each test, and is destroyed after |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 unittest.TestCase.__init__(self, methodName) | 140 unittest.TestCase.__init__(self, methodName) |
| 139 | 141 |
| 140 def __del__(self): | 142 def __del__(self): |
| 141 pyautolib.PyUITestBase.__del__(self) | 143 pyautolib.PyUITestBase.__del__(self) |
| 142 | 144 |
| 143 def setUp(self): | 145 def setUp(self): |
| 144 """Override this method to launch browser differently. | 146 """Override this method to launch browser differently. |
| 145 | 147 |
| 146 Can be used to prevent launching the browser window by default in case a | 148 Can be used to prevent launching the browser window by default in case a |
| 147 test wants to do some additional setup before firing browser. | 149 test wants to do some additional setup before firing browser. |
| 150 |
| 151 When using the named interface, it connects to an existing browser |
| 152 instance. |
| 148 """ | 153 """ |
| 154 named_channel_id = _OPTIONS.channel_id |
| 155 if self.IsChromeOS(): # Enable testing interface on ChromeOS |
| 156 if self.get_clear_profile(): |
| 157 self.CleanupBrowserProfileOnChromeOS() |
| 158 if not named_channel_id: |
| 159 named_channel_id = self.EnableChromeTestingOnChromeOS() |
| 160 if named_channel_id: |
| 161 self.UseNamedChannelID(named_channel_id) |
| 149 self.SetUp() # Fire browser | 162 self.SetUp() # Fire browser |
| 150 | 163 |
| 151 def tearDown(self): | 164 def tearDown(self): |
| 152 self.TearDown() # Destroy browser | 165 self.TearDown() # Destroy browser |
| 153 | 166 |
| 167 def EnableChromeTestingOnChromeOS(self): |
| 168 """Enables the named automation interface on chromeos. |
| 169 |
| 170 Restarts chrome so that you get a fresh instance. |
| 171 Also sets some testing-friendly flags for chrome. |
| 172 |
| 173 Expects suid python to be present in the same dir as pyautolib.py |
| 174 """ |
| 175 def _IsRootSuid(path): |
| 176 return os.path.isfile(path) and (os.stat(path).st_mode & stat.S_ISUID) |
| 177 suid_python = os.path.normpath(os.path.join( |
| 178 os.path.dirname(pyautolib.__file__), 'python')) |
| 179 assert _IsRootSuid(suid_python), \ |
| 180 'Did not find suid-root python at %s' % suid_python |
| 181 file_path = os.path.join(os.path.dirname(__file__), 'chromeos', |
| 182 'enable_testing.py') |
| 183 args = [suid_python, file_path] |
| 184 # Pass extra chrome flags for testing |
| 185 for flag in self.ExtraChromeFlagsOnChromeOS(): |
| 186 args.append('--extra-chrome-flags=%s' % flag) |
| 187 proc = subprocess.Popen(args, stdout=subprocess.PIPE) |
| 188 automation_channel_path = proc.communicate()[0] |
| 189 automation_channel_path = automation_channel_path.strip() |
| 190 assert len(automation_channel_path), 'Could not enable testing interface' |
| 191 return automation_channel_path |
| 192 |
| 193 def ExtraChromeFlagsOnChromeOS(self): |
| 194 """Return a list of extra chrome flags to use with chrome for testing. |
| 195 |
| 196 These are flags needed to facilitate testing. |
| 197 """ |
| 198 return [ |
| 199 '--homepage=about:blank', |
| 200 '--allow-file-access', |
| 201 '--enable-file-cookies', |
| 202 '--dom-automation', |
| 203 ] |
| 204 |
| 205 @staticmethod |
| 206 def CleanupBrowserProfileOnChromeOS(): |
| 207 """Cleanup browser profile dir on ChromeOS. |
| 208 |
| 209 Browser should not be running, or else there will be locked files. |
| 210 """ |
| 211 profile_dir = '/home/chronos/user' |
| 212 for item in os.listdir(profile_dir): |
| 213 if item != '.pki': # Causes stateful partition to get erased |
| 214 pyauto_utils.RemovePath(os.path.join(profile_dir, item)) |
| 215 # TODO(nirnimesh): Clean up other files in /home/chronos? |
| 216 |
| 154 def RestartBrowser(self, clear_profile=True): | 217 def RestartBrowser(self, clear_profile=True): |
| 155 """Restart the browser. | 218 """Restart the browser. |
| 156 | 219 |
| 157 For use with tests that require to restart the browser. | 220 For use with tests that require to restart the browser. |
| 158 | 221 |
| 159 Args: | 222 Args: |
| 160 clear_profile: If True, the browser profile is cleared before restart. | 223 clear_profile: If True, the browser profile is cleared before restart. |
| 161 Defaults to True, that is restarts browser with a clean | 224 Defaults to True, that is restarts browser with a clean |
| 162 profile. | 225 profile. |
| 163 """ | 226 """ |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 374 and returns it back as a dictionary. | 437 and returns it back as a dictionary. |
| 375 | 438 |
| 376 Args: | 439 Args: |
| 377 cmd_dict: the command dictionary. It must have a 'command' key | 440 cmd_dict: the command dictionary. It must have a 'command' key |
| 378 Sample: | 441 Sample: |
| 379 { | 442 { |
| 380 'command': 'SetOmniboxText', | 443 'command': 'SetOmniboxText', |
| 381 'text': text, | 444 'text': text, |
| 382 } | 445 } |
| 383 windex: 0-based window index on which to work. Default: 0 (first window) | 446 windex: 0-based window index on which to work. Default: 0 (first window) |
| 447 Use -ve windex if the automation command does not apply to a |
| 448 browser window. example: chromeos login |
| 384 | 449 |
| 385 Returns: | 450 Returns: |
| 386 a dictionary for the output returned by the automation channel. | 451 a dictionary for the output returned by the automation channel. |
| 387 | 452 |
| 388 Raises: | 453 Raises: |
| 389 pyauto_errors.JSONInterfaceError if the automation call returns an error. | 454 pyauto_errors.JSONInterfaceError if the automation call returns an error. |
| 390 """ | 455 """ |
| 391 ret_dict = json.loads(self._SendJSONRequest(windex, json.dumps(cmd_dict))) | 456 ret_dict = json.loads(self._SendJSONRequest(windex, json.dumps(cmd_dict))) |
| 392 if ret_dict.has_key('error'): | 457 if ret_dict.has_key('error'): |
| 393 raise JSONInterfaceError(ret_dict['error']) | 458 raise JSONInterfaceError(ret_dict['error']) |
| (...skipping 1626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2020 Raises: | 2085 Raises: |
| 2021 pyauto_errors.JSONInterfaceError if the automation call returns an error. | 2086 pyauto_errors.JSONInterfaceError if the automation call returns an error. |
| 2022 """ | 2087 """ |
| 2023 cmd_dict = { | 2088 cmd_dict = { |
| 2024 'command': 'KillRendererProcess', | 2089 'command': 'KillRendererProcess', |
| 2025 'pid': pid | 2090 'pid': pid |
| 2026 } | 2091 } |
| 2027 return self._GetResultFromJSONRequest(cmd_dict) | 2092 return self._GetResultFromJSONRequest(cmd_dict) |
| 2028 | 2093 |
| 2029 | 2094 |
| 2095 ## ChromeOS section |
| 2096 |
| 2097 def Login(self, username, password): |
| 2098 """Login to chromeos. |
| 2099 |
| 2100 Waits until logged in. |
| 2101 Should be displaying the login screen to work. |
| 2102 |
| 2103 Raises: |
| 2104 pyauto_errors.JSONInterfaceError if the automation call returns an error. |
| 2105 """ |
| 2106 cmd_dict = { |
| 2107 'command': 'Login', |
| 2108 'username': username, |
| 2109 'password': password, |
| 2110 } |
| 2111 return self._GetResultFromJSONRequest(cmd_dict, windex=-1) |
| 2112 |
| 2113 ## ChromeOS section -- end |
| 2114 |
| 2115 |
| 2030 class PyUITestSuite(pyautolib.PyUITestSuiteBase, unittest.TestSuite): | 2116 class PyUITestSuite(pyautolib.PyUITestSuiteBase, unittest.TestSuite): |
| 2031 """Base TestSuite for PyAuto UI tests.""" | 2117 """Base TestSuite for PyAuto UI tests.""" |
| 2032 | 2118 |
| 2033 def __init__(self, args): | 2119 def __init__(self, args): |
| 2034 pyautolib.PyUITestSuiteBase.__init__(self, args) | 2120 pyautolib.PyUITestSuiteBase.__init__(self, args) |
| 2035 | 2121 |
| 2036 # Figure out path to chromium binaries | 2122 # Figure out path to chromium binaries |
| 2037 browser_dir = os.path.normpath(os.path.dirname(pyautolib.__file__)) | 2123 browser_dir = os.path.normpath(os.path.dirname(pyautolib.__file__)) |
| 2038 logging.debug('Loading pyauto libs from %s', browser_dir) | 2124 logging.debug('Loading pyauto libs from %s', browser_dir) |
| 2039 self.Initialize(pyautolib.FilePath(browser_dir)) | 2125 self.Initialize(pyautolib.FilePath(browser_dir)) |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2178 'flakiness. Defaults to 1.') | 2264 'flakiness. Defaults to 1.') |
| 2179 parser.add_option( | 2265 parser.add_option( |
| 2180 '-S', '--suite', type='string', default='FULL', | 2266 '-S', '--suite', type='string', default='FULL', |
| 2181 help='Name of the suite to load. Defaults to "FULL".') | 2267 help='Name of the suite to load. Defaults to "FULL".') |
| 2182 parser.add_option( | 2268 parser.add_option( |
| 2183 '-L', '--list-tests', action='store_true', default=False, | 2269 '-L', '--list-tests', action='store_true', default=False, |
| 2184 help='List all tests, and exit.') | 2270 help='List all tests, and exit.') |
| 2185 parser.add_option( | 2271 parser.add_option( |
| 2186 '', '--no-http-server', action='store_true', default=False, | 2272 '', '--no-http-server', action='store_true', default=False, |
| 2187 help='Do not start an http server to serve files in data dir.') | 2273 help='Do not start an http server to serve files in data dir.') |
| 2274 parser.add_option( |
| 2275 '', '--channel-id', type='string', default='', |
| 2276 help='Name of channel id, if using named interface.') |
| 2188 | 2277 |
| 2189 self._options, self._args = parser.parse_args() | 2278 self._options, self._args = parser.parse_args() |
| 2190 global _OPTIONS | 2279 global _OPTIONS |
| 2191 _OPTIONS = self._options # export options so other classes can access | 2280 _OPTIONS = self._options # export options so other classes can access |
| 2192 | 2281 |
| 2193 # Setup logging - start with defaults | 2282 # Setup logging - start with defaults |
| 2194 level = logging.INFO | 2283 level = logging.INFO |
| 2195 format = None | 2284 format = None |
| 2196 | 2285 |
| 2197 if self._options.verbose: | 2286 if self._options.verbose: |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2412 if self._options.verbose: | 2501 if self._options.verbose: |
| 2413 verbosity = 2 | 2502 verbosity = 2 |
| 2414 result = PyAutoTextTestRuner(verbosity=verbosity).run(pyauto_suite) | 2503 result = PyAutoTextTestRuner(verbosity=verbosity).run(pyauto_suite) |
| 2415 del loaded_tests # Need to destroy test cases before the suite | 2504 del loaded_tests # Need to destroy test cases before the suite |
| 2416 del pyauto_suite | 2505 del pyauto_suite |
| 2417 sys.exit(not result.wasSuccessful()) | 2506 sys.exit(not result.wasSuccessful()) |
| 2418 | 2507 |
| 2419 | 2508 |
| 2420 if __name__ == '__main__': | 2509 if __name__ == '__main__': |
| 2421 Main() | 2510 Main() |
| OLD | NEW |