[Android] Clean up gtest filtering logic.

Apply gtest_filter option to tests obtained from the device.

BUG=246871
NOTRY=True

Review URL: https://chromiumcodereview.appspot.com/19479002

git-svn-id: http://src.chromium.org/svn/trunk/src/build@212229 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
frankf@chromium.org 2013-07-18 03:42:49 +00:00
Родитель 32b9b58543
Коммит f941755385
6 изменённых файлов: 111 добавлений и 105 удалений

Просмотреть файл

@ -19,10 +19,6 @@ from pylib.gtest import dispatch as gtest_dispatch
from pylib.gtest import test_runner
from pylib.utils import report_results
sys.path.insert(0,
os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib'))
from common import unittest_util
def Dispatch(options):
"""Dispatches all content_browsertests.
@ -75,21 +71,16 @@ def Dispatch(options):
constants.BROWSERTEST_TEST_ACTIVITY_NAME,
constants.BROWSERTEST_COMMAND_LINE_FILE)
# Get tests and split them up based on the number of devices.
all_enabled = gtest_dispatch.GetAllEnabledTests(RunnerFactory,
attached_devices)
if options.test_filter:
all_tests = unittest_util.FilterTestNames(all_enabled,
options.test_filter)
else:
all_tests = _FilterTests(all_enabled)
tests = gtest_dispatch.GetTestsFiltered(
constants.BROWSERTEST_SUITE_NAME, options.test_filter, RunnerFactory,
attached_devices)
# Run tests.
# TODO(nileshagrawal): remove this abnormally long setup timeout once fewer
# files are pushed to the devices for content_browsertests: crbug.com/138275
setup_timeout = 20 * 60 # 20 minutes
test_results, exit_code = shard.ShardAndRunTests(
RunnerFactory, attached_devices, all_tests, options.build_type,
RunnerFactory, attached_devices, tests, options.build_type,
setup_timeout=setup_timeout, test_timeout=None,
num_retries=options.num_retries)
report_results.LogFull(
@ -103,21 +94,3 @@ def Dispatch(options):
shutil.rmtree(constants.ISOLATE_DEPS_DIR)
return (test_results, exit_code)
def _FilterTests(all_enabled_tests):
"""Filters out tests and fixtures starting with PRE_ and MANUAL_."""
return [t for t in all_enabled_tests if _ShouldRunOnBot(t)]
def _ShouldRunOnBot(test):
fixture, case = test.split('.', 1)
if _StartsWith(fixture, case, 'PRE_'):
return False
if _StartsWith(fixture, case, 'MANUAL_'):
return False
return True
def _StartsWith(a, b, prefix):
return a.startswith(prefix) or b.startswith(prefix)

Просмотреть файл

@ -10,6 +10,7 @@ import glob
import logging
import os
import shutil
import sys
from pylib import android_commands
from pylib import cmd_helper
@ -24,9 +25,11 @@ from pylib.utils import xvfb
import gtest_config
import test_runner
sys.path.insert(0,
os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib'))
from common import unittest_util
# TODO(frankf): Add more test targets here after making sure we don't
# blow up the dependency size (and the world).
_ISOLATE_FILE_PATHS = {
'base_unittests': 'base/base_unittests.isolate',
'breakpad_unittests': 'breakpad/breakpad_unittests.isolate',
@ -71,7 +74,7 @@ def _GenerateDepsDirUsingIsolate(test_suite, build_type):
"""Generate the dependency dir for the test suite using isolate.
Args:
test_suite: The test suite basename (e.g. base_unittests).
test_suite: Name of the test suite (e.g. base_unittests).
build_type: Release/Debug
"""
product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type)
@ -191,51 +194,115 @@ def _FullyQualifiedTestSuites(exe, option_test_suite, build_type):
return qualified_test_suites
def GetTestsFromDevice(runner):
"""Get a list of tests from a device, excluding disabled tests.
def _GetDisabledTestsFilterFromFile(test_suite):
"""Returns a gtest filter based on the *_disabled file.
Args:
runner: a TestRunner.
test_suite: Name of the test suite (e.g. base_unittests).
Returns:
All non-disabled tests on the device.
A gtest filter which excludes disabled tests.
Example: '*-StackTrace.*:StringPrintfTest.StringPrintfMisc'
"""
# The executable/apk needs to be copied before we can call GetAllTests.
runner.test_package.Install()
all_tests = runner.test_package.GetAllTests()
# Only includes tests that do not have any match in the disabled list.
disabled_list = runner.GetDisabledTests()
return filter(lambda t: not any([fnmatch.fnmatch(t, disabled_pattern)
for disabled_pattern in disabled_list]),
all_tests)
filter_file_path = os.path.join(
os.path.abspath(os.path.dirname(__file__)),
'filter', '%s_disabled' % test_suite)
if not filter_file_path or not os.path.exists(filter_file_path):
logging.info('No filter file found at %s', filter_file_path)
return '*'
filters = [x for x in [x.strip() for x in file(filter_file_path).readlines()]
if x and x[0] != '#']
disabled_filter = '*-%s' % ':'.join(filters)
logging.info('Applying filter "%s" obtained from %s',
disabled_filter, filter_file_path)
return disabled_filter
def GetAllEnabledTests(runner_factory, devices):
"""Get all enabled tests.
Obtains a list of enabled tests from the test package on the device,
then filters it again using the disabled list on the host.
def _GetTestsFromDevice(runner_factory, devices):
"""Get a list of tests from a device.
Args:
runner_factory: callable that takes a devices and returns a TestRunner.
devices: list of devices.
runner_factory: callable that takes a device and index and returns a
TestRunner object.
devices: List of devices.
Returns:
List of all enabled tests.
Raises:
Exception: If no devices available.
All the tests in the test suite.
"""
for device in devices:
try:
logging.info('Obtaining tests from %s', device)
runner = runner_factory(device, 0)
return GetTestsFromDevice(runner)
except Exception as e:
runner.test_package.Install()
return runner.test_package.GetAllTests()
except (android_commands.errors.WaitForResponseTimedOutError,
android_commands.errors.DeviceUnresponsiveError), e:
logging.warning('Failed obtaining tests from %s with exception: %s',
device, e)
raise Exception('No device available to get the list of tests.')
def _FilterTestsUsingPrefixes(all_tests, pre=False, manual=False):
"""Removes tests with disabled prefixes.
Args:
all_tests: List of tests to filter.
pre: If True, include tests with _PRE prefix.
manual: If True, include tests with _MANUAL prefix.
Returns:
List of tests remaining.
"""
filtered_tests = []
filter_prefixes = ['DISABLED_', 'FLAKY_', 'FAILS_']
if not pre:
filter_prefixes.append('PRE_')
if not manual:
filter_prefixes.append('MANUAL_')
for t in all_tests:
test_case, test = t.split('.', 1)
if not any([test_case.startswith(prefix) or test.startswith(prefix) for
prefix in filter_prefixes]):
filtered_tests.append(t)
return filtered_tests
def GetTestsFiltered(test_suite, gtest_filter, runner_factory, devices):
"""Get all tests in the suite and filter them.
Obtains a list of tests from the test package on the device, and
applies the following filters in order:
1. Remove tests with disabled prefixes.
2. Remove tests specified in the *_disabled files in the 'filter' dir
3. Applies |gtest_filter|.
Args:
test_suite: Name of the test suite (e.g. base_unittests).
gtest_filter: A filter including negative and/or positive patterns.
runner_factory: callable that takes a device and index and returns a
TestRunner object.
devices: List of devices.
Returns:
List of tests remaining.
"""
tests = _GetTestsFromDevice(runner_factory, devices)
tests = _FilterTestsUsingPrefixes(
tests, bool(gtest_filter), bool(gtest_filter))
tests = unittest_util.FilterTestNames(
tests, _GetDisabledTestsFilterFromFile(test_suite))
if gtest_filter:
tests = unittest_util.FilterTestNames(tests, gtest_filter)
return tests
def _RunATestSuite(options, suite_name):
"""Run a single test suite.
@ -294,12 +361,10 @@ def _RunATestSuite(options, suite_name):
constants.GTEST_COMMAND_LINE_FILE)
# Get tests and split them up based on the number of devices.
if options.test_filter:
all_tests = [t for t in options.test_filter.split(':') if t]
else:
all_tests = GetAllEnabledTests(RunnerFactory, attached_devices)
tests = GetTestsFiltered(suite_name, options.test_filter,
RunnerFactory, attached_devices)
num_devices = len(attached_devices)
tests = [':'.join(all_tests[i::num_devices]) for i in xrange(num_devices)]
tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)]
tests = [t for t in tests if t]
# Run tests.

Просмотреть файл

@ -61,14 +61,11 @@ class TestPackage(object):
"""Install the test package to the device."""
raise NotImplementedError('Method must be overriden.')
def GetDisabledPrefixes(self):
return ['DISABLED_', 'FLAKY_', 'FAILS_']
def _ParseGTestListTests(self, all_tests):
"""Parses and filters the raw test lists.
def _ParseGTestListTests(self, raw_list):
"""Parses a raw test list as provided by --gtest_list_tests.
Args:
all_tests: The raw test listing with the following format:
raw_list: The raw test listing with the following format:
IPCChannelTest.
SendMessageInChannelConnected
@ -77,14 +74,14 @@ class TestPackage(object):
DISABLED_SendWithTimeoutMixedOKAndTimeout
Returns:
A list of non-disabled tests. For the above raw listing:
A list of all tests. For the above raw listing:
[IPCChannelTest.SendMessageInChannelConnected, IPCSyncChannelTest.Simple]
[IPCChannelTest.SendMessageInChannelConnected, IPCSyncChannelTest.Simple,
IPCSyncChannelTest.DISABLED_SendWithTimeoutMixedOKAndTimeout]
"""
ret = []
current = ''
disabled_prefixes = self.GetDisabledPrefixes()
for test in all_tests:
for test in raw_list:
if not test:
continue
if test[0] != ' ' and not test.endswith('.'):
@ -96,6 +93,5 @@ class TestPackage(object):
if 'YOU HAVE' in test:
break
test_name = test[2:]
if not any([test_name.startswith(x) for x in disabled_prefixes]):
ret += [current + test_name]
ret += [current + test_name]
return ret

Просмотреть файл

@ -49,7 +49,6 @@ class TestRunner(base_test_runner.BaseTestRunner):
"""
super(TestRunner, self).__init__(device, tool_name, build_type, push_deps,
cleanup_test_files)
self._running_on_emulator = self.device.startswith('emulator')
self._test_arguments = test_arguments
self.in_webkit_checkout = in_webkit_checkout
if timeout == 0:
@ -126,25 +125,6 @@ class TestRunner(base_test_runner.BaseTestRunner):
os.path.join(self.adb.GetExternalStorage(),
'third_party/hyphen/hyph_en_US.dic'))
# TODO(craigdh): There is no reason for this to be part of TestRunner.
def GetDisabledTests(self):
"""Returns a list of disabled tests.
Returns:
A list of disabled tests obtained from 'filter' subdirectory.
"""
gtest_filter_base_path = os.path.join(
os.path.abspath(os.path.dirname(__file__)),
'filter',
self.test_package.test_suite_basename)
disabled_tests = run_tests_helper.GetExpectations(
gtest_filter_base_path + '_disabled')
if self._running_on_emulator:
# Append emulator's filter file.
disabled_tests.extend(run_tests_helper.GetExpectations(
gtest_filter_base_path + '_emulator_additional_disabled'))
return disabled_tests
def _ParseTestOutput(self, p):
"""Process the test output.

Просмотреть файл

@ -31,14 +31,6 @@ class CustomFormatter(logging.Formatter):
return '%s %ss %s' % (record.levelname[0], timediff.rjust(4), msg)
def GetExpectations(file_name):
"""Returns a list of test names in the |file_name| test expectations file."""
if not file_name or not os.path.exists(file_name):
return []
return [x for x in [x.strip() for x in file(file_name).readlines()]
if x and x[0] != '#']
def SetLogLevel(verbose_count):
"""Sets log level as |verbose_count|."""
log_level = logging.WARNING # Default.

Просмотреть файл

@ -126,7 +126,7 @@ def AddCoreGTestOptions(option_parser, default_timeout=60):
# TODO(gkanwar): Consolidate and clean up test filtering for gtests and
# content_browsertests.
option_parser.add_option('--gtest_filter', dest='test_filter',
help='Filter GTests by name.')
help='googletest-style filter string.')
option_parser.add_option('-a', '--test_arguments', dest='test_arguments',
help='Additional arguments to pass to the test.')
# TODO(gkanwar): Most likely deprecate/remove this option once we've pinned