OLD | NEW |
---|---|
1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Dispatches GTests.""" | 5 """Dispatches GTests.""" |
6 | 6 |
7 import copy | 7 import copy |
8 import fnmatch | 8 import fnmatch |
9 import glob | 9 import glob |
10 import logging | 10 import logging |
11 import os | 11 import os |
12 import shutil | 12 import shutil |
13 import sys | |
13 | 14 |
14 from pylib import android_commands | 15 from pylib import android_commands |
15 from pylib import cmd_helper | 16 from pylib import cmd_helper |
16 from pylib import constants | 17 from pylib import constants |
17 from pylib import ports | 18 from pylib import ports |
18 from pylib.base import base_test_result | 19 from pylib.base import base_test_result |
19 from pylib.base import shard | 20 from pylib.base import shard |
20 from pylib.utils import emulator | 21 from pylib.utils import emulator |
21 from pylib.utils import report_results | 22 from pylib.utils import report_results |
22 from pylib.utils import xvfb | 23 from pylib.utils import xvfb |
23 | 24 |
24 import gtest_config | 25 import gtest_config |
25 import test_runner | 26 import test_runner |
26 | 27 |
28 sys.path.insert(0, | |
29 os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib')) | |
30 from common import unittest_util | |
31 | |
27 | 32 |
28 # TODO(frankf): Add more test targets here after making sure we don't | 33 # TODO(frankf): Add more test targets here after making sure we don't |
29 # blow up the dependency size (and the world). | 34 # blow up the dependency size (and the world). |
30 _ISOLATE_FILE_PATHS = { | 35 _ISOLATE_FILE_PATHS = { |
31 'base_unittests': 'base/base_unittests.isolate', | 36 'base_unittests': 'base/base_unittests.isolate', |
32 'breakpad_unittests': 'breakpad/breakpad_unittests.isolate', | 37 'breakpad_unittests': 'breakpad/breakpad_unittests.isolate', |
33 'cc_perftests': 'cc/cc_perftests.isolate', | 38 'cc_perftests': 'cc/cc_perftests.isolate', |
34 'components_unittests': 'components/components_unittests.isolate', | 39 'components_unittests': 'components/components_unittests.isolate', |
35 'content_browsertests': 'content/content_browsertests.isolate', | 40 'content_browsertests': 'content/content_browsertests.isolate', |
36 'content_unittests': 'content/content_unittests.isolate', | 41 'content_unittests': 'content/content_unittests.isolate', |
(...skipping 27 matching lines...) Expand all Loading... | |
64 ] | 69 ] |
65 | 70 |
66 _ISOLATE_SCRIPT = os.path.join( | 71 _ISOLATE_SCRIPT = os.path.join( |
67 constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py') | 72 constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py') |
68 | 73 |
69 | 74 |
70 def _GenerateDepsDirUsingIsolate(test_suite, build_type): | 75 def _GenerateDepsDirUsingIsolate(test_suite, build_type): |
71 """Generate the dependency dir for the test suite using isolate. | 76 """Generate the dependency dir for the test suite using isolate. |
72 | 77 |
73 Args: | 78 Args: |
74 test_suite: The test suite basename (e.g. base_unittests). | 79 test_suite: Name of the test suite (e.g. base_unittests). |
75 build_type: Release/Debug | 80 build_type: Release/Debug |
76 """ | 81 """ |
77 product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) | 82 product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) |
78 assert os.path.isabs(product_dir) | 83 assert os.path.isabs(product_dir) |
79 | 84 |
80 if os.path.isdir(constants.ISOLATE_DEPS_DIR): | 85 if os.path.isdir(constants.ISOLATE_DEPS_DIR): |
81 shutil.rmtree(constants.ISOLATE_DEPS_DIR) | 86 shutil.rmtree(constants.ISOLATE_DEPS_DIR) |
82 | 87 |
83 isolate_rel_path = _ISOLATE_FILE_PATHS.get(test_suite) | 88 isolate_rel_path = _ISOLATE_FILE_PATHS.get(test_suite) |
84 if not isolate_rel_path: | 89 if not isolate_rel_path: |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
184 | 189 |
185 for t, q in qualified_test_suites: | 190 for t, q in qualified_test_suites: |
186 if not os.path.exists(q): | 191 if not os.path.exists(q): |
187 raise Exception('Test suite %s not found in %s.\n' | 192 raise Exception('Test suite %s not found in %s.\n' |
188 'Supported test suites:\n %s\n' | 193 'Supported test suites:\n %s\n' |
189 'Ensure it has been built.\n' % | 194 'Ensure it has been built.\n' % |
190 (t, q, [s.name for s in gtest_config.STABLE_TEST_SUITES])) | 195 (t, q, [s.name for s in gtest_config.STABLE_TEST_SUITES])) |
191 return qualified_test_suites | 196 return qualified_test_suites |
192 | 197 |
193 | 198 |
194 def GetTestsFromDevice(runner): | 199 def _GetDisabledTestsFilterFromFile(test_suite): |
195 """Get a list of tests from a device, excluding disabled tests. | 200 """Returns a gtest filter based on the *_disabled file. |
196 | 201 |
197 Args: | 202 Args: |
198 runner: a TestRunner. | 203 test_suite: Name of the test suite (e.g. base_unittests). |
204 | |
199 Returns: | 205 Returns: |
200 All non-disabled tests on the device. | 206 A gtest filter which excludes disabled tests. |
207 Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc' | |
201 """ | 208 """ |
202 # The executable/apk needs to be copied before we can call GetAllTests. | 209 filter_file_path = os.path.join( |
203 runner.test_package.Install() | 210 os.path.abspath(os.path.dirname(__file__)), |
204 all_tests = runner.test_package.GetAllTests() | 211 'filter', '%s_disabled' % test_suite) |
205 # Only includes tests that do not have any match in the disabled list. | 212 |
206 disabled_list = runner.GetDisabledTests() | 213 if not filter_file_path or not os.path.exists(filter_file_path): |
craigdh
2013/07/17 21:27:03
logging.info that no filter file was found?
frankf
2013/07/17 22:18:54
Done.
| |
207 return filter(lambda t: not any([fnmatch.fnmatch(t, disabled_pattern) | 214 return '*' |
208 for disabled_pattern in disabled_list]), | 215 |
209 all_tests) | 216 filters = [x for x in [x.strip() for x in file(filter_file_path).readlines()] |
217 if x and x[0] != '#'] | |
218 disabled_filter = '*-%s' % ':'.join(filters) | |
219 logging.info('Applying filter "%s" obtained from %s', | |
220 disabled_filter, filter_file_path) | |
221 return disabled_filter | |
210 | 222 |
211 | 223 |
212 def GetAllEnabledTests(runner_factory, devices): | 224 def _GetTestsFromDevice(runner_factory, devices): |
213 """Get all enabled tests. | 225 """Get a list of tests from a device. |
214 | |
215 Obtains a list of enabled tests from the test package on the device, | |
216 then filters it again using the disabled list on the host. | |
217 | 226 |
218 Args: | 227 Args: |
219 runner_factory: callable that takes a devices and returns a TestRunner. | 228 runner_factory: Callable that takes a devices and returns a TestRunner. |
craigdh
2013/07/17 21:27:03
devices -> device and shard index
frankf
2013/07/17 22:18:54
Done.
| |
220 devices: list of devices. | 229 devices: List of devices. |
221 | 230 |
222 Returns: | 231 Returns: |
223 List of all enabled tests. | 232 All the tests in the test suite. |
224 | |
225 Raises: | |
226 Exception: If no devices available. | |
227 """ | 233 """ |
228 for device in devices: | 234 for device in devices: |
229 try: | 235 try: |
230 logging.info('Obtaining tests from %s', device) | 236 logging.info('Obtaining tests from %s', device) |
231 runner = runner_factory(device, 0) | 237 runner = runner_factory(device, 0) |
232 return GetTestsFromDevice(runner) | 238 runner.test_package.Install() |
239 return runner.test_package.GetAllTests() | |
233 except Exception as e: | 240 except Exception as e: |
234 logging.warning('Failed obtaining tests from %s with exception: %s', | 241 logging.warning('Failed obtaining tests from %s with exception: %s', |
235 device, e) | 242 device, e) |
236 raise Exception('No device available to get the list of tests.') | 243 raise Exception('No device available to get the list of tests.') |
craigdh
2013/07/17 21:27:03
This is a pain right now, because if there is an i
frankf
2013/07/17 22:18:54
The issue is that we're catching too general excep
| |
237 | 244 |
238 | 245 |
246 def _FilterTestsUsingPrefixes(all_tests, pre=False, manual=False): | |
247 """Removes tests with disabled prefixes. | |
248 | |
249 Args: | |
250 all_tests: List of tests to filter. | |
251 pre: If True, include tests with _PRE prefix. | |
252 manual: If True, include tests with _MANUAL prefix. | |
253 | |
254 Returns: | |
255 List of tests remaining. | |
256 """ | |
257 filtered_tests = [] | |
258 filter_prefixes = ['DISABLED_', 'FLAKY_', 'FAILS_'] | |
259 | |
260 if not pre: | |
261 filter_prefixes.append('PRE_') | |
262 | |
263 if not manual: | |
264 filter_prefixes.append('MANUAL_') | |
265 | |
266 for t in all_tests: | |
267 test_case, test = t.split('.', 1) | |
268 if any([test_case.startswith(prefix) or test.startswith(prefix) for prefix | |
craigdh
2013/07/17 21:27:03
lose the continue, just do:
if not any(...):
fi
frankf
2013/07/17 22:18:54
Done.
| |
269 in filter_prefixes]): | |
270 continue | |
271 filtered_tests.append(t) | |
272 return filtered_tests | |
273 | |
274 | |
275 def GetTestsFiltered(test_suite, gtest_filter, runner_factory, devices): | |
276 """Get all tests in the suite and filter them. | |
277 | |
278 Obtains a list of tests from the test package on the device, and | |
279 applies the following filters in order: | |
280 1. Remove tests with disabled prefixes. | |
281 2. Remove tests specified in the *_disabled files in the 'filter' dir | |
282 3. Applies |gtest_filter|. | |
283 | |
284 Args: | |
285 test_suite: Name of the test suite (e.g. base_unittests). | |
286 gtest_filter: A filter including negative or positive patterns. | |
287 runner_factory: Callable that takes a devices and returns a TestRunner. | |
288 devices: List of devices. | |
289 | |
290 Returns: | |
291 List of tests remaining. | |
292 """ | |
293 tests = _GetTestsFromDevice(runner_factory, devices) | |
294 tests = _FilterTestsUsingPrefixes( | |
295 tests, bool(gtest_filter), bool(gtest_filter)) | |
296 tests = unittest_util.FilterTestNames( | |
297 tests, _GetDisabledTestsFilterFromFile(test_suite)) | |
298 | |
299 if gtest_filter: | |
300 tests = unittest_util.FilterTestNames(tests, gtest_filter) | |
301 | |
302 return tests | |
303 | |
304 | |
239 def _RunATestSuite(options, suite_name): | 305 def _RunATestSuite(options, suite_name): |
240 """Run a single test suite. | 306 """Run a single test suite. |
241 | 307 |
242 Helper for Dispatch() to allow stop/restart of the emulator across | 308 Helper for Dispatch() to allow stop/restart of the emulator across |
243 test bundles. If using the emulator, we start it on entry and stop | 309 test bundles. If using the emulator, we start it on entry and stop |
244 it on exit. | 310 it on exit. |
245 | 311 |
246 Args: | 312 Args: |
247 options: options for running the tests. | 313 options: options for running the tests. |
248 suite_name: name of the test suite being run. | 314 suite_name: name of the test suite being run. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
287 options.cleanup_test_files, | 353 options.cleanup_test_files, |
288 options.tool, | 354 options.tool, |
289 options.build_type, | 355 options.build_type, |
290 options.webkit, | 356 options.webkit, |
291 options.push_deps, | 357 options.push_deps, |
292 constants.GTEST_TEST_PACKAGE_NAME, | 358 constants.GTEST_TEST_PACKAGE_NAME, |
293 constants.GTEST_TEST_ACTIVITY_NAME, | 359 constants.GTEST_TEST_ACTIVITY_NAME, |
294 constants.GTEST_COMMAND_LINE_FILE) | 360 constants.GTEST_COMMAND_LINE_FILE) |
295 | 361 |
296 # Get tests and split them up based on the number of devices. | 362 # Get tests and split them up based on the number of devices. |
297 if options.test_filter: | 363 tests = GetTestsFiltered(suite_name, options.test_filter, |
298 all_tests = [t for t in options.test_filter.split(':') if t] | 364 RunnerFactory, attached_devices) |
299 else: | |
300 all_tests = GetAllEnabledTests(RunnerFactory, attached_devices) | |
301 num_devices = len(attached_devices) | 365 num_devices = len(attached_devices) |
302 tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)] | 366 tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] |
303 tests = [t for t in tests if t] | 367 tests = [t for t in tests if t] |
304 | 368 |
305 # Run tests. | 369 # Run tests. |
306 test_results, exit_code = shard.ShardAndRunTests( | 370 test_results, exit_code = shard.ShardAndRunTests( |
307 RunnerFactory, attached_devices, tests, options.build_type, | 371 RunnerFactory, attached_devices, tests, options.build_type, |
308 test_timeout=None, num_retries=options.num_retries) | 372 test_timeout=None, num_retries=options.num_retries) |
309 | 373 |
310 report_results.LogFull( | 374 report_results.LogFull( |
311 results=test_results, | 375 results=test_results, |
312 test_type='Unit test', | 376 test_type='Unit test', |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
361 test_options.test_suite = suite_path | 425 test_options.test_suite = suite_path |
362 test_results, test_exit_code = _RunATestSuite(test_options, suite_name) | 426 test_results, test_exit_code = _RunATestSuite(test_options, suite_name) |
363 results.AddTestRunResults(test_results) | 427 results.AddTestRunResults(test_results) |
364 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: | 428 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: |
365 exit_code = test_exit_code | 429 exit_code = test_exit_code |
366 | 430 |
367 if options.use_xvfb: | 431 if options.use_xvfb: |
368 framebuffer.Stop() | 432 framebuffer.Stop() |
369 | 433 |
370 return (results, exit_code) | 434 return (results, exit_code) |
OLD | NEW |