Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1718)

Side by Side Diff: build/android/pylib/gtest/dispatch.py

Issue 19479002: [Android] Clean up gtest filtering logic. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Addressed all comments Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « build/android/pylib/browsertests/dispatch.py ('k') | build/android/pylib/gtest/test_package.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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)
OLDNEW
« no previous file with comments | « build/android/pylib/browsertests/dispatch.py ('k') | build/android/pylib/gtest/test_package.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698