OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """PyAuto: Python Interface to Chromium's Automation Proxy. | 6 """PyAuto: Python Interface to Chromium's Automation Proxy. |
7 | 7 |
8 PyAuto uses swig to expose Automation Proxy interfaces to Python. | 8 PyAuto uses swig to expose Automation Proxy interfaces to Python. |
9 For complete documentation on the functionality available, | 9 For complete documentation on the functionality available, |
10 run pydoc on this file. | 10 run pydoc on this file. |
(...skipping 6166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6177 '', '--chrome-flags', type='string', default='', | 6177 '', '--chrome-flags', type='string', default='', |
6178 help='Flags passed to Chrome. This is in addition to the usual flags ' | 6178 help='Flags passed to Chrome. This is in addition to the usual flags ' |
6179 'like suppressing first-run dialogs, enabling automation. ' | 6179 'like suppressing first-run dialogs, enabling automation. ' |
6180 'See chrome/common/chrome_switches.cc for the list of flags ' | 6180 'See chrome/common/chrome_switches.cc for the list of flags ' |
6181 'chrome understands.') | 6181 'chrome understands.') |
6182 parser.add_option( | 6182 parser.add_option( |
6183 '', '--http-data-dir', type='string', | 6183 '', '--http-data-dir', type='string', |
6184 default=os.path.join('chrome', 'test', 'data'), | 6184 default=os.path.join('chrome', 'test', 'data'), |
6185 help='Relative path from which http server should serve files.') | 6185 help='Relative path from which http server should serve files.') |
6186 parser.add_option( | 6186 parser.add_option( |
6187 '', '--list-missing-tests', action='store_true', default=False, | |
6188 help='Print a list of tests not included in PYAUTO_TESTS, and exit') | |
6189 parser.add_option( | |
6190 '-L', '--list-tests', action='store_true', default=False, | 6187 '-L', '--list-tests', action='store_true', default=False, |
6191 help='List all tests, and exit.') | 6188 help='List all tests, and exit.') |
6192 parser.add_option( | 6189 parser.add_option( |
6193 '--shard', | 6190 '--shard', |
6194 help='Specify sharding params. Example: 1/3 implies split the list of ' | 6191 help='Specify sharding params. Example: 1/3 implies split the list of ' |
6195 'tests into 3 groups of which this is the 1st.') | 6192 'tests into 3 groups of which this is the 1st.') |
6196 parser.add_option( | 6193 parser.add_option( |
6197 '', '--log-file', type='string', default=None, | 6194 '', '--log-file', type='string', default=None, |
6198 help='Provide a path to a file to which the logger will log') | 6195 help='Provide a path to a file to which the logger will log') |
6199 parser.add_option( | 6196 parser.add_option( |
(...skipping 25 matching lines...) Expand all Loading... | |
6225 # Set up logging. All log messages will be prepended with a timestamp. | 6222 # Set up logging. All log messages will be prepended with a timestamp. |
6226 format = '%(asctime)s %(levelname)-8s %(message)s' | 6223 format = '%(asctime)s %(levelname)-8s %(message)s' |
6227 | 6224 |
6228 level = logging.INFO | 6225 level = logging.INFO |
6229 if self._options.verbose: | 6226 if self._options.verbose: |
6230 level=logging.DEBUG | 6227 level=logging.DEBUG |
6231 | 6228 |
6232 logging.basicConfig(level=level, format=format, | 6229 logging.basicConfig(level=level, format=format, |
6233 filename=self._options.log_file) | 6230 filename=self._options.log_file) |
6234 | 6231 |
6235 if self._options.list_missing_tests: | |
6236 self._ListMissingTests() | |
6237 sys.exit(0) | |
6238 | |
6239 def TestsDir(self): | 6232 def TestsDir(self): |
6240 """Returns the path to dir containing tests. | 6233 """Returns the path to dir containing tests. |
6241 | 6234 |
6242 This is typically the dir containing the tests description file. | 6235 This is typically the dir containing the tests description file. |
6243 This method should be overridden by derived class to point to other dirs | 6236 This method should be overridden by derived class to point to other dirs |
6244 if needed. | 6237 if needed. |
6245 """ | 6238 """ |
6246 return os.path.dirname(__file__) | 6239 return os.path.dirname(__file__) |
6247 | 6240 |
6248 @staticmethod | 6241 @staticmethod |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6295 return _GetTestsFromModule(obj) | 6288 return _GetTestsFromModule(obj) |
6296 elif (isinstance(obj, (type, types.ClassType)) and | 6289 elif (isinstance(obj, (type, types.ClassType)) and |
6297 issubclass(obj, PyUITest) and obj != PyUITest): | 6290 issubclass(obj, PyUITest) and obj != PyUITest): |
6298 return [module.__name__ + '.' + x for x in _GetTestsFromTestCase(obj)] | 6291 return [module.__name__ + '.' + x for x in _GetTestsFromTestCase(obj)] |
6299 elif type(obj) == types.UnboundMethodType: | 6292 elif type(obj) == types.UnboundMethodType: |
6300 return [name] | 6293 return [name] |
6301 else: | 6294 else: |
6302 logging.warn('No tests in "%s"', name) | 6295 logging.warn('No tests in "%s"', name) |
6303 return [] | 6296 return [] |
6304 | 6297 |
6305 def _ListMissingTests(self): | |
6306 """Print tests missing from PYAUTO_TESTS.""" | |
6307 # Fetch tests from all test scripts | |
6308 all_test_files = filter(lambda x: x.endswith('.py'), | |
6309 os.listdir(self.TestsDir())) | |
6310 all_tests_modules = [os.path.splitext(x)[0] for x in all_test_files] | |
6311 all_tests = reduce(lambda x, y: x + y, | |
6312 map(self._ImportTestsFromName, all_tests_modules)) | |
6313 # Fetch tests included by PYAUTO_TESTS | |
6314 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) | |
6315 pyauto_tests = reduce(lambda x, y: x + y, | |
6316 map(self._ImportTestsFromName, | |
6317 self._ExpandTestNamesFrom(pyauto_tests_file, | |
6318 self._options.suite))) | |
6319 for a_test in all_tests: | |
6320 if a_test not in pyauto_tests: | |
6321 print a_test | |
6322 | |
6323 def _HasTestCases(self, module_string): | 6298 def _HasTestCases(self, module_string): |
6324 """Determines if we have any PyUITest test case classes in the module | 6299 """Determines if we have any PyUITest test case classes in the module |
6325 identified by |module_string|.""" | 6300 identified by |module_string|.""" |
6326 module = __import__(module_string) | 6301 module = __import__(module_string) |
6327 for name in dir(module): | 6302 for name in dir(module): |
6328 obj = getattr(module, name) | 6303 obj = getattr(module, name) |
6329 if (isinstance(obj, (type, types.ClassType)) and | 6304 if (isinstance(obj, (type, types.ClassType)) and |
6330 issubclass(obj, PyUITest)): | 6305 issubclass(obj, PyUITest)): |
6331 return True | 6306 return True |
6332 return False | 6307 return False |
6333 | 6308 |
6334 def _ExpandTestNames(self, args): | 6309 def _ExpandTestNames(self, args): |
6335 """Returns a list of tests loaded from the given args. | 6310 """Returns a list of tests loaded from the given args. |
6336 | 6311 |
6337 The given args can be either a module (ex: module1) or a testcase | 6312 The given args can be either a module (ex: module1) or a testcase |
6338 (ex: module2.MyTestCase) or a test (ex: module1.MyTestCase.testX) | 6313 (ex: module2.MyTestCase) or a test (ex: module1.MyTestCase.testX) |
6339 If empty, the tests in the already imported modules are loaded. | 6314 or a suite name (ex: @FULL). If empty, the tests in the already imported |
6315 modules are loaded. | |
6340 | 6316 |
6341 Args: | 6317 Args: |
6342 args: [module1, module2, module3.testcase, module4.testcase.testX] | 6318 args: [module1, module2, module3.testcase, module4.testcase.testX] |
6343 These modules or test cases or tests should be importable | 6319 These modules or test cases or tests should be importable. |
6320 Suites can be specified by prefixing @. Example: @FULL | |
6344 | 6321 |
6345 Returns: | 6322 Returns: |
6346 a list of expanded test names. Example: | 6323 a list of expanded test names. Example: |
6347 [ | 6324 [ |
6348 'module1.TestCase1.testA', | 6325 'module1.TestCase1.testA', |
6349 'module1.TestCase1.testB', | 6326 'module1.TestCase1.testB', |
6350 'module2.TestCase2.testX', | 6327 'module2.TestCase2.testX', |
6351 'module3.testcase.testY', | 6328 'module3.testcase.testY', |
6352 'module4.testcase.testX' | 6329 'module4.testcase.testX' |
6353 ] | 6330 ] |
6354 """ | 6331 """ |
6332 | |
6333 def _TestsFromDescriptionFile(suite=None): | |
6334 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) | |
6335 if suite: | |
6336 logging.debug("Reading %s (@%s)", pyauto_tests_file, suite) | |
6337 else: | |
6338 logging.debug("Reading %s", pyauto_tests_file) | |
6339 if not os.path.exists(pyauto_tests_file): | |
6340 logging.warn("%s missing. Cannot load tests.", pyauto_tests_file) | |
6341 return [] | |
6342 else: | |
6343 return self._ExpandTestNamesFrom(pyauto_tests_file, suite) | |
6344 | |
6355 if not args: # Load tests ourselves | 6345 if not args: # Load tests ourselves |
6356 if self._HasTestCases('__main__'): # we are running a test script | 6346 if self._HasTestCases('__main__'): # we are running a test script |
6357 module_name = os.path.splitext(os.path.basename(sys.argv[0]))[0] | 6347 module_name = os.path.splitext(os.path.basename(sys.argv[0]))[0] |
6358 args.append(module_name) # run the test cases found in it | 6348 args.append(module_name) # run the test cases found in it |
6359 else: # run tests from the test description file | 6349 else: # run tests from the test description file |
6360 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) | 6350 args = _TestsFromDescriptionFile(self._options.suite) |
dennis_jeffrey
2012/08/01 01:23:27
suite=self._options.suite (or else remove default
| |
6361 logging.debug("Reading %s", pyauto_tests_file) | 6351 else: # Check args with @ prefix for suites |
6362 if not os.path.exists(pyauto_tests_file): | 6352 out_args = [] |
6363 logging.warn("%s missing. Cannot load tests.", pyauto_tests_file) | 6353 for arg in args: |
6354 if arg.startswith('@'): | |
6355 suite = arg[1:] | |
6356 out_args += _TestsFromDescriptionFile(suite) | |
dennis_jeffrey
2012/08/01 01:23:27
similar comment as line 6350 above
| |
6364 else: | 6357 else: |
6365 args = self._ExpandTestNamesFrom(pyauto_tests_file, | 6358 out_args.append(arg) |
6366 self._options.suite) | 6359 args = out_args |
6367 return args | 6360 return args |
6368 | 6361 |
6369 def _ExpandTestNamesFrom(self, filename, suite): | 6362 def _ExpandTestNamesFrom(self, filename, suite): |
6370 """Load test names from the given file. | 6363 """Load test names from the given file. |
6371 | 6364 |
6372 Args: | 6365 Args: |
6373 filename: the file to read the tests from | 6366 filename: the file to read the tests from |
6374 suite: the name of the suite to load from |filename|. | 6367 suite: the name of the suite to load from |filename|. |
6375 | 6368 |
6376 Returns: | 6369 Returns: |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6458 successful = result.wasSuccessful() | 6451 successful = result.wasSuccessful() |
6459 if not successful: | 6452 if not successful: |
6460 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) | 6453 pyauto_tests_file = os.path.join(self.TestsDir(), self._tests_filename) |
6461 print >>sys.stderr, 'Tests can be disabled by editing %s. ' \ | 6454 print >>sys.stderr, 'Tests can be disabled by editing %s. ' \ |
6462 'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL) | 6455 'Ref: %s' % (pyauto_tests_file, _PYAUTO_DOC_URL) |
6463 sys.exit(not successful) | 6456 sys.exit(not successful) |
6464 | 6457 |
6465 | 6458 |
6466 if __name__ == '__main__': | 6459 if __name__ == '__main__': |
6467 Main() | 6460 Main() |
OLD | NEW |