Chromium Code Reviews| 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 |