1 # Copyright 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
8 from telemetry import decorators
9 from telemetry.core import browser_finder
10 from telemetry.core import browser_options
11 from telemetry.core import command_line
12 from telemetry.core import discover
13 from telemetry.unittest import json_results
14 from telemetry.unittest import progress_reporter
18 def __init__(self, top_level_dir, test_dirs, progress_reporters):
19 self._top_level_dir = top_level_dir
20 self._test_dirs = tuple(test_dirs)
21 self._progress_reporters = tuple(progress_reporters)
24 def top_level_dir(self):
25 return self._top_level_dir
29 return self._test_dirs
32 def progress_reporters(self):
33 return self._progress_reporters
36 def Discover(start_dir, top_level_dir=None, pattern='test*.py'):
37 loader = unittest.defaultTestLoader
38 loader.suiteClass = progress_reporter.TestSuite
41 modules = discover.DiscoverModules(start_dir, top_level_dir, pattern)
42 for module in modules:
43 if hasattr(module, 'suite'):
44 suite = module.suite()
46 suite = loader.loadTestsFromModule(module)
47 if suite.countTestCases():
48 test_suites.append(suite)
52 def FilterSuite(suite, predicate):
53 new_suite = suite.__class__()
55 if isinstance(test, unittest.TestSuite):
56 subsuite = FilterSuite(test, predicate)
57 if subsuite.countTestCases():
58 new_suite.addTest(subsuite)
60 assert isinstance(test, unittest.TestCase)
62 new_suite.addTest(test)
67 def DiscoverTests(search_dirs, top_level_dir, possible_browser,
68 selected_tests=None, selected_tests_are_exact=False,
69 run_disabled_tests=False):
70 def IsTestSelected(test):
73 for name in selected_tests:
74 if selected_tests_are_exact:
82 if run_disabled_tests:
84 # pylint: disable=W0212
85 if not hasattr(test, '_testMethodName'):
87 method = getattr(test, test._testMethodName)
88 return decorators.IsEnabled(method, possible_browser)
90 wrapper_suite = progress_reporter.TestSuite()
91 for search_dir in search_dirs:
92 wrapper_suite.addTests(Discover(search_dir, top_level_dir, '*_unittest.py'))
93 return FilterSuite(wrapper_suite, IsTestSelected)
96 def RestoreLoggingLevel(func):
97 def _LoggingRestoreWrapper(*args, **kwargs):
98 # Cache the current logging level, this needs to be done before calling
99 # parser.parse_args, which changes logging level based on verbosity
101 logging_level = logging.getLogger().getEffectiveLevel()
103 return func(*args, **kwargs)
105 # Restore logging level, which may be changed in parser.parse_args.
106 logging.getLogger().setLevel(logging_level)
108 return _LoggingRestoreWrapper
114 class RunTestsCommand(command_line.OptparseCommand):
117 usage = '[test_name ...] [<options>]'
120 def CreateParser(cls):
121 options = browser_options.BrowserFinderOptions()
122 options.browser_type = 'any'
123 parser = options.CreateParser('%%prog %s' % cls.usage)
127 def AddCommandLineArgs(cls, parser):
128 parser.add_option('--repeat-count', type='int', default=1,
129 help='Repeats each a provided number of times.')
130 parser.add_option('-d', '--also-run-disabled-tests',
131 dest='run_disabled_tests',
132 action='store_true', default=False,
133 help='Ignore @Disabled and @Enabled restrictions.')
134 parser.add_option('--retry-limit', type='int',
135 help='Retry each failure up to N times'
136 ' to de-flake things.')
137 parser.add_option('--exact-test-filter', action='store_true', default=False,
138 help='Treat test filter as exact matches (default is '
139 'substring matches).')
140 json_results.AddOptions(parser)
143 def ProcessCommandLineArgs(cls, parser, args):
144 if args.verbosity == 0:
145 logging.getLogger().setLevel(logging.WARN)
147 # We retry failures by default unless we're running a list of tests
149 if args.retry_limit is None and not args.positional_args:
153 possible_browser = browser_finder.FindBrowser(args)
154 except browser_finder.BrowserFinderException, ex:
157 if not possible_browser:
158 parser.error('No browser found of type %s. Cannot run tests.\n'
159 'Re-run with --browser=list to see '
160 'available browser types.' % args.browser_type)
162 json_results.ValidateArgs(parser, args)
165 possible_browser = browser_finder.FindBrowser(args)
167 test_suite, result = self.RunOneSuite(possible_browser, args)
171 failed_tests = json_results.FailedTestNames(test_suite, result)
172 retry_limit = args.retry_limit
174 while retry_limit and failed_tests:
175 args.positional_args = failed_tests
176 args.exact_test_filter = True
178 _, result = self.RunOneSuite(possible_browser, args)
179 results.append(result)
181 failed_tests = json_results.FailedTestNames(test_suite, result)
184 full_results = json_results.FullResults(args, test_suite, results)
185 json_results.WriteFullResultsIfNecessary(args, full_results)
187 err_occurred, err_str = json_results.UploadFullResultsIfNecessary(
190 for line in err_str.splitlines():
194 return json_results.ExitCodeFromFullResults(full_results)
196 def RunOneSuite(self, possible_browser, args):
197 test_suite = DiscoverTests(config.test_dirs, config.top_level_dir,
198 possible_browser, args.positional_args,
199 args.exact_test_filter, args.run_disabled_tests)
200 runner = progress_reporter.TestRunner()
201 result = runner.run(test_suite, config.progress_reporters,
202 args.repeat_count, args)
203 return test_suite, result
207 def main(cls, args=None):
208 return super(RunTestsCommand, cls).main(args)