146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)# Copyright 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import unittest 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry import decorators 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry.core import browser_finder 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import browser_options 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom telemetry.core import command_line 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)from telemetry.core import discover 135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)from telemetry.unittest import json_results 146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)from telemetry.unittest import progress_reporter 15116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass Config(object): 186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def __init__(self, top_level_dir, test_dirs, progress_reporters): 19116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._top_level_dir = top_level_dir 20116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._test_dirs = tuple(test_dirs) 216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) self._progress_reporters = tuple(progress_reporters) 22116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @property 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def top_level_dir(self): 25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return self._top_level_dir 26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @property 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def test_dirs(self): 29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return self._test_dirs 30116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @property 326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def progress_reporters(self): 336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return self._progress_reporters 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)def Discover(start_dir, top_level_dir=None, pattern='test*.py'): 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) loader = unittest.defaultTestLoader 386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) loader.suiteClass = progress_reporter.TestSuite 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch test_suites = [] 412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) modules = discover.DiscoverModules(start_dir, top_level_dir, pattern) 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for module in modules: 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if hasattr(module, 'suite'): 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch suite = module.suite() 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch suite = loader.loadTestsFromModule(module) 47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if suite.countTestCases(): 48116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch test_suites.append(suite) 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return test_suites 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def FilterSuite(suite, predicate): 532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) new_suite = suite.__class__() 54116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for test in suite: 55116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if isinstance(test, unittest.TestSuite): 56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch subsuite = FilterSuite(test, predicate) 57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if subsuite.countTestCases(): 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch new_suite.addTest(subsuite) 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch else: 60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch assert isinstance(test, unittest.TestCase) 61116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if predicate(test): 62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch new_suite.addTest(test) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new_suite 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 67116680a4aac90f2aa7413d9095a592090648e557Ben Murdochdef DiscoverTests(search_dirs, top_level_dir, possible_browser, 686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) selected_tests=None, selected_tests_are_exact=False, 696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) run_disabled_tests=False): 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def IsTestSelected(test): 71116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if selected_tests: 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found = False 73116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for name in selected_tests: 746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if selected_tests_are_exact: 756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if name == test.id(): 766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) found = True 776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) else: 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if name in test.id(): 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) found = True 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not found: 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if run_disabled_tests: 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return True 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) # pylint: disable=W0212 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if not hasattr(test, '_testMethodName'): 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return True 875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) method = getattr(test, test._testMethodName) 88116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return decorators.IsEnabled(method, possible_browser) 89116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) wrapper_suite = progress_reporter.TestSuite() 91116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for search_dir in search_dirs: 92116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch wrapper_suite.addTests(Discover(search_dir, top_level_dir, '*_unittest.py')) 93116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return FilterSuite(wrapper_suite, IsTestSelected) 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)def RestoreLoggingLevel(func): 97d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) def _LoggingRestoreWrapper(*args, **kwargs): 98d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) # Cache the current logging level, this needs to be done before calling 99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) # parser.parse_args, which changes logging level based on verbosity 100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) # setting. 101d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) logging_level = logging.getLogger().getEffectiveLevel() 102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) try: 103d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return func(*args, **kwargs) 104d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) finally: 105d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) # Restore logging level, which may be changed in parser.parse_args. 106d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) logging.getLogger().setLevel(logging_level) 107d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 108d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) return _LoggingRestoreWrapper 109d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 110d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 111116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconfig = None 112116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 114116680a4aac90f2aa7413d9095a592090648e557Ben Murdochclass RunTestsCommand(command_line.OptparseCommand): 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch """Run unit tests""" 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch usage = '[test_name ...] [<options>]' 118116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 119116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @classmethod 120116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def CreateParser(cls): 121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch options = browser_options.BrowserFinderOptions() 122116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch options.browser_type = 'any' 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch parser = options.CreateParser('%%prog %s' % cls.usage) 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return parser 125116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 126116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @classmethod 127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def AddCommandLineArgs(cls, parser): 128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch parser.add_option('--repeat-count', type='int', default=1, 129116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch help='Repeats each a provided number of times.') 130116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch parser.add_option('-d', '--also-run-disabled-tests', 131116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch dest='run_disabled_tests', 132116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch action='store_true', default=False, 133116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch help='Ignore @Disabled and @Enabled restrictions.') 1346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_option('--retry-limit', type='int', 1356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) help='Retry each failure up to N times' 1366e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) ' to de-flake things.') 1376e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) parser.add_option('--exact-test-filter', action='store_true', default=False, 1386e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) help='Treat test filter as exact matches (default is ' 1396e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 'substring matches).') 1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) json_results.AddOptions(parser) 141116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 142116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @classmethod 143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def ProcessCommandLineArgs(cls, parser, args): 144116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if args.verbosity == 0: 145116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch logging.getLogger().setLevel(logging.WARN) 146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) # We retry failures by default unless we're running a list of tests 1486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) # explicitly. 1496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if args.retry_limit is None and not args.positional_args: 1506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args.retry_limit = 3 1516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 152116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch try: 153116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch possible_browser = browser_finder.FindBrowser(args) 154116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch except browser_finder.BrowserFinderException, ex: 155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch parser.error(ex) 156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if not possible_browser: 158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch parser.error('No browser found of type %s. Cannot run tests.\n' 159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'Re-run with --browser=list to see ' 160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'available browser types.' % args.browser_type) 161116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) json_results.ValidateArgs(parser, args) 1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def Run(self, args): 165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch possible_browser = browser_finder.FindBrowser(args) 1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1676e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) test_suite, result = self.RunOneSuite(possible_browser, args) 1686e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) results = [result] 1706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci failed_tests = json_results.FailedTestNames(test_suite, result) 1726e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) retry_limit = args.retry_limit 1736e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) while retry_limit and failed_tests: 1756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args.positional_args = failed_tests 1766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args.exact_test_filter = True 1776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) _, result = self.RunOneSuite(possible_browser, args) 1796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) results.append(result) 1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci failed_tests = json_results.FailedTestNames(test_suite, result) 1826e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) retry_limit -= 1 1836e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1846e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) full_results = json_results.FullResults(args, test_suite, results) 1856e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) json_results.WriteFullResultsIfNecessary(args, full_results) 1866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) err_occurred, err_str = json_results.UploadFullResultsIfNecessary( 1886e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args, full_results) 1896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) if err_occurred: 1906e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) for line in err_str.splitlines(): 1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) logging.error(line) 1926e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return 1 1936e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return json_results.ExitCodeFromFullResults(full_results) 1955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) 1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) def RunOneSuite(self, possible_browser, args): 1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) test_suite = DiscoverTests(config.test_dirs, config.top_level_dir, 1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) possible_browser, args.positional_args, 1996e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args.exact_test_filter, args.run_disabled_tests) 2006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) runner = progress_reporter.TestRunner() 2016e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) result = runner.run(test_suite, config.progress_reporters, 2026e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) args.repeat_count, args) 2036e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return test_suite, result 204116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 205116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @classmethod 206116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch @RestoreLoggingLevel 207116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch def main(cls, args=None): 208116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return super(RunTestsCommand, cls).main(args) 209