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 |
27 | 31 |
28 # TODO(frankf): Add more test targets here after making sure we don't | 32 |
29 # blow up the dependency size (and the world). | |
30 _ISOLATE_FILE_PATHS = { | 33 _ISOLATE_FILE_PATHS = { |
31 'base_unittests': 'base/base_unittests.isolate', | 34 'base_unittests': 'base/base_unittests.isolate', |
32 'breakpad_unittests': 'breakpad/breakpad_unittests.isolate', | 35 'breakpad_unittests': 'breakpad/breakpad_unittests.isolate', |
33 'cc_perftests': 'cc/cc_perftests.isolate', | 36 'cc_perftests': 'cc/cc_perftests.isolate', |
34 'components_unittests': 'components/components_unittests.isolate', | 37 'components_unittests': 'components/components_unittests.isolate', |
35 'content_browsertests': 'content/content_browsertests.isolate', | 38 'content_browsertests': 'content/content_browsertests.isolate', |
36 'content_unittests': 'content/content_unittests.isolate', | 39 'content_unittests': 'content/content_unittests.isolate', |
37 'media_unittests': 'media/media_unittests.isolate', | 40 'media_unittests': 'media/media_unittests.isolate', |
38 'modules_unittests': 'third_party/webrtc/modules/modules_unittests.isolate', | 41 'modules_unittests': 'third_party/webrtc/modules/modules_unittests.isolate', |
39 'net_unittests': 'net/net_unittests.isolate', | 42 'net_unittests': 'net/net_unittests.isolate', |
(...skipping 24 matching lines...) Expand all Loading... |
64 ] | 67 ] |
65 | 68 |
66 _ISOLATE_SCRIPT = os.path.join( | 69 _ISOLATE_SCRIPT = os.path.join( |
67 constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py') | 70 constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py') |
68 | 71 |
69 | 72 |
70 def _GenerateDepsDirUsingIsolate(test_suite, build_type): | 73 def _GenerateDepsDirUsingIsolate(test_suite, build_type): |
71 """Generate the dependency dir for the test suite using isolate. | 74 """Generate the dependency dir for the test suite using isolate. |
72 | 75 |
73 Args: | 76 Args: |
74 test_suite: The test suite basename (e.g. base_unittests). | 77 test_suite: Name of the test suite (e.g. base_unittests). |
75 build_type: Release/Debug | 78 build_type: Release/Debug |
76 """ | 79 """ |
77 product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) | 80 product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) |
78 assert os.path.isabs(product_dir) | 81 assert os.path.isabs(product_dir) |
79 | 82 |
80 if os.path.isdir(constants.ISOLATE_DEPS_DIR): | 83 if os.path.isdir(constants.ISOLATE_DEPS_DIR): |
81 shutil.rmtree(constants.ISOLATE_DEPS_DIR) | 84 shutil.rmtree(constants.ISOLATE_DEPS_DIR) |
82 | 85 |
83 isolate_rel_path = _ISOLATE_FILE_PATHS.get(test_suite) | 86 isolate_rel_path = _ISOLATE_FILE_PATHS.get(test_suite) |
84 if not isolate_rel_path: | 87 if not isolate_rel_path: |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 | 187 |
185 for t, q in qualified_test_suites: | 188 for t, q in qualified_test_suites: |
186 if not os.path.exists(q): | 189 if not os.path.exists(q): |
187 raise Exception('Test suite %s not found in %s.\n' | 190 raise Exception('Test suite %s not found in %s.\n' |
188 'Supported test suites:\n %s\n' | 191 'Supported test suites:\n %s\n' |
189 'Ensure it has been built.\n' % | 192 'Ensure it has been built.\n' % |
190 (t, q, [s.name for s in gtest_config.STABLE_TEST_SUITES])) | 193 (t, q, [s.name for s in gtest_config.STABLE_TEST_SUITES])) |
191 return qualified_test_suites | 194 return qualified_test_suites |
192 | 195 |
193 | 196 |
194 def GetTestsFromDevice(runner): | 197 def _GetDisabledTestsFilterFromFile(test_suite): |
195 """Get a list of tests from a device, excluding disabled tests. | 198 """Returns a gtest filter based on the *_disabled file. |
196 | 199 |
197 Args: | 200 Args: |
198 runner: a TestRunner. | 201 test_suite: Name of the test suite (e.g. base_unittests). |
| 202 |
199 Returns: | 203 Returns: |
200 All non-disabled tests on the device. | 204 A gtest filter which excludes disabled tests. |
| 205 Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc' |
201 """ | 206 """ |
202 # The executable/apk needs to be copied before we can call GetAllTests. | 207 filter_file_path = os.path.join( |
203 runner.test_package.Install() | 208 os.path.abspath(os.path.dirname(__file__)), |
204 all_tests = runner.test_package.GetAllTests() | 209 'filter', '%s_disabled' % test_suite) |
205 # Only includes tests that do not have any match in the disabled list. | 210 |
206 disabled_list = runner.GetDisabledTests() | 211 if not filter_file_path or not os.path.exists(filter_file_path): |
207 return filter(lambda t: not any([fnmatch.fnmatch(t, disabled_pattern) | 212 logging.info('No filter file found at %s', filter_file_path) |
208 for disabled_pattern in disabled_list]), | 213 return '*' |
209 all_tests) | 214 |
| 215 filters = [x for x in [x.strip() for x in file(filter_file_path).readlines()] |
| 216 if x and x[0] != '#'] |
| 217 disabled_filter = '*-%s' % ':'.join(filters) |
| 218 logging.info('Applying filter "%s" obtained from %s', |
| 219 disabled_filter, filter_file_path) |
| 220 return disabled_filter |
210 | 221 |
211 | 222 |
212 def GetAllEnabledTests(runner_factory, devices): | 223 def _GetTestsFromDevice(runner_factory, devices): |
213 """Get all enabled tests. | 224 """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 | 225 |
218 Args: | 226 Args: |
219 runner_factory: callable that takes a devices and returns a TestRunner. | 227 runner_factory: callable that takes a device and index and returns a |
220 devices: list of devices. | 228 TestRunner object. |
| 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() |
233 except Exception as e: | 239 return runner.test_package.GetAllTests() |
| 240 except (android_commands.errors.WaitForResponseTimedOutError, |
| 241 android_commands.errors.DeviceUnresponsiveError), e: |
234 logging.warning('Failed obtaining tests from %s with exception: %s', | 242 logging.warning('Failed obtaining tests from %s with exception: %s', |
235 device, e) | 243 device, e) |
236 raise Exception('No device available to get the list of tests.') | 244 raise Exception('No device available to get the list of tests.') |
237 | 245 |
238 | 246 |
| 247 def _FilterTestsUsingPrefixes(all_tests, pre=False, manual=False): |
| 248 """Removes tests with disabled prefixes. |
| 249 |
| 250 Args: |
| 251 all_tests: List of tests to filter. |
| 252 pre: If True, include tests with _PRE prefix. |
| 253 manual: If True, include tests with _MANUAL prefix. |
| 254 |
| 255 Returns: |
| 256 List of tests remaining. |
| 257 """ |
| 258 filtered_tests = [] |
| 259 filter_prefixes = ['DISABLED_', 'FLAKY_', 'FAILS_'] |
| 260 |
| 261 if not pre: |
| 262 filter_prefixes.append('PRE_') |
| 263 |
| 264 if not manual: |
| 265 filter_prefixes.append('MANUAL_') |
| 266 |
| 267 for t in all_tests: |
| 268 test_case, test = t.split('.', 1) |
| 269 if not any([test_case.startswith(prefix) or test.startswith(prefix) for |
| 270 prefix in filter_prefixes]): |
| 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 and/or positive patterns. |
| 287 runner_factory: callable that takes a device and index and returns a |
| 288 TestRunner object. |
| 289 devices: List of devices. |
| 290 |
| 291 Returns: |
| 292 List of tests remaining. |
| 293 """ |
| 294 tests = _GetTestsFromDevice(runner_factory, devices) |
| 295 tests = _FilterTestsUsingPrefixes( |
| 296 tests, bool(gtest_filter), bool(gtest_filter)) |
| 297 tests = unittest_util.FilterTestNames( |
| 298 tests, _GetDisabledTestsFilterFromFile(test_suite)) |
| 299 |
| 300 if gtest_filter: |
| 301 tests = unittest_util.FilterTestNames(tests, gtest_filter) |
| 302 |
| 303 return tests |
| 304 |
| 305 |
239 def _RunATestSuite(options, suite_name): | 306 def _RunATestSuite(options, suite_name): |
240 """Run a single test suite. | 307 """Run a single test suite. |
241 | 308 |
242 Helper for Dispatch() to allow stop/restart of the emulator across | 309 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 | 310 test bundles. If using the emulator, we start it on entry and stop |
244 it on exit. | 311 it on exit. |
245 | 312 |
246 Args: | 313 Args: |
247 options: options for running the tests. | 314 options: options for running the tests. |
248 suite_name: name of the test suite being run. | 315 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, | 354 options.cleanup_test_files, |
288 options.tool, | 355 options.tool, |
289 options.build_type, | 356 options.build_type, |
290 options.webkit, | 357 options.webkit, |
291 options.push_deps, | 358 options.push_deps, |
292 constants.GTEST_TEST_PACKAGE_NAME, | 359 constants.GTEST_TEST_PACKAGE_NAME, |
293 constants.GTEST_TEST_ACTIVITY_NAME, | 360 constants.GTEST_TEST_ACTIVITY_NAME, |
294 constants.GTEST_COMMAND_LINE_FILE) | 361 constants.GTEST_COMMAND_LINE_FILE) |
295 | 362 |
296 # Get tests and split them up based on the number of devices. | 363 # Get tests and split them up based on the number of devices. |
297 if options.test_filter: | 364 tests = GetTestsFiltered(suite_name, options.test_filter, |
298 all_tests = [t for t in options.test_filter.split(':') if t] | 365 RunnerFactory, attached_devices) |
299 else: | |
300 all_tests = GetAllEnabledTests(RunnerFactory, attached_devices) | |
301 num_devices = len(attached_devices) | 366 num_devices = len(attached_devices) |
302 tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)] | 367 tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] |
303 tests = [t for t in tests if t] | 368 tests = [t for t in tests if t] |
304 | 369 |
305 # Run tests. | 370 # Run tests. |
306 test_results, exit_code = shard.ShardAndRunTests( | 371 test_results, exit_code = shard.ShardAndRunTests( |
307 RunnerFactory, attached_devices, tests, options.build_type, | 372 RunnerFactory, attached_devices, tests, options.build_type, |
308 test_timeout=None, num_retries=options.num_retries) | 373 test_timeout=None, num_retries=options.num_retries) |
309 | 374 |
310 report_results.LogFull( | 375 report_results.LogFull( |
311 results=test_results, | 376 results=test_results, |
312 test_type='Unit test', | 377 test_type='Unit test', |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
361 test_options.test_suite = suite_path | 426 test_options.test_suite = suite_path |
362 test_results, test_exit_code = _RunATestSuite(test_options, suite_name) | 427 test_results, test_exit_code = _RunATestSuite(test_options, suite_name) |
363 results.AddTestRunResults(test_results) | 428 results.AddTestRunResults(test_results) |
364 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: | 429 if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: |
365 exit_code = test_exit_code | 430 exit_code = test_exit_code |
366 | 431 |
367 if options.use_xvfb: | 432 if options.use_xvfb: |
368 framebuffer.Stop() | 433 framebuffer.Stop() |
369 | 434 |
370 return (results, exit_code) | 435 return (results, exit_code) |
OLD | NEW |