Index: build/android/pylib/gtest/setup.py |
diff --git a/build/android/pylib/gtest/dispatch.py b/build/android/pylib/gtest/setup.py |
similarity index 59% |
rename from build/android/pylib/gtest/dispatch.py |
rename to build/android/pylib/gtest/setup.py |
index eea09a93b20db03b49f2329b7f4fa3d481ea2835..1757dc5f9b865b4a0392de09d219c820eb8a24f9 100644 |
--- a/build/android/pylib/gtest/dispatch.py |
+++ b/build/android/pylib/gtest/setup.py |
@@ -2,9 +2,8 @@ |
# Use of this source code is governed by a BSD-style license that can be |
# found in the LICENSE file. |
-"""Dispatches GTests.""" |
+"""Generates test runner factory and tests for GTests.""" |
-import copy |
import fnmatch |
import glob |
import logging |
@@ -17,10 +16,6 @@ from pylib import cmd_helper |
from pylib import constants |
from pylib import ports |
from pylib.base import base_test_result |
-from pylib.base import shard |
-from pylib.utils import emulator |
-from pylib.utils import report_results |
-from pylib.utils import xvfb |
import gtest_config |
import test_runner |
@@ -70,11 +65,11 @@ _ISOLATE_SCRIPT = os.path.join( |
constants.DIR_SOURCE_ROOT, 'tools', 'swarm_client', 'isolate.py') |
-def _GenerateDepsDirUsingIsolate(test_suite, build_type): |
+def _GenerateDepsDirUsingIsolate(suite_name, build_type): |
"""Generate the dependency dir for the test suite using isolate. |
Args: |
- test_suite: Name of the test suite (e.g. base_unittests). |
+ suite_name: Name of the test suite (e.g. base_unittests). |
build_type: Release/Debug |
""" |
product_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) |
@@ -83,14 +78,14 @@ def _GenerateDepsDirUsingIsolate(test_suite, build_type): |
if os.path.isdir(constants.ISOLATE_DEPS_DIR): |
shutil.rmtree(constants.ISOLATE_DEPS_DIR) |
- isolate_rel_path = _ISOLATE_FILE_PATHS.get(test_suite) |
+ isolate_rel_path = _ISOLATE_FILE_PATHS.get(suite_name) |
if not isolate_rel_path: |
logging.info('Did not find an isolate file for the test suite.') |
return |
isolate_abs_path = os.path.join(constants.DIR_SOURCE_ROOT, isolate_rel_path) |
isolated_abs_path = os.path.join( |
- product_dir, '%s.isolated' % test_suite) |
+ product_dir, '%s.isolated' % suite_name) |
assert os.path.exists(isolate_abs_path) |
isolate_cmd = [ |
'python', _ISOLATE_SCRIPT, |
@@ -151,54 +146,43 @@ def _GenerateDepsDirUsingIsolate(test_suite, build_type): |
os.rmdir(os.path.join(constants.ISOLATE_DEPS_DIR, 'out')) |
-def _FullyQualifiedTestSuites(exe, option_test_suite, build_type): |
- """Get a list of absolute paths to test suite targets. |
+def _GetSuitePath(use_exe_test_runner, suite_name, build_type): |
+ """Get the absolute path to the test suite. |
Args: |
- exe: if True, use the executable-based test runner. |
- option_test_suite: the test_suite specified as an option. |
+ use_exe_test_runner: If True, use the executable-based test runner. |
+ suite_name: The suite name specified on the command line. |
build_type: 'Release' or 'Debug'. |
Returns: |
- A list of tuples containing the suite and absolute path. |
- Ex. ('content_unittests', |
- '/tmp/chrome/src/out/Debug/content_unittests_apk/' |
- 'content_unittests-debug.apk') |
+ The absolute path of the given suite. |
+ Ex. '/tmp/chrome/src/out/Debug/content_unittests_apk/' |
+ 'content_unittests-debug.apk' |
Raises: |
Exception: If test suite not found. |
""" |
- def GetQualifiedSuite(suite): |
- if suite.is_suite_exe: |
- relpath = suite.name |
- else: |
- # out/(Debug|Release)/$SUITE_apk/$SUITE-debug.apk |
- relpath = os.path.join(suite.name + '_apk', suite.name + '-debug.apk') |
- return suite.name, os.path.join(test_suite_dir, relpath) |
- |
- test_suite_dir = os.path.join(cmd_helper.OutDirectory.get(), build_type) |
- if option_test_suite: |
- all_test_suites = [gtest_config.Suite(exe, option_test_suite)] |
+ if use_exe_test_runner: |
+ relpath = suite_name |
else: |
- all_test_suites = gtest_config.STABLE_TEST_SUITES |
+ relpath = os.path.join(suite_name + '_apk', suite_name + '-debug.apk') |
+ suite_path = os.path.join(cmd_helper.OutDirectory.get(), build_type, relpath) |
- # List of tuples (suite_name, suite_path) |
- qualified_test_suites = map(GetQualifiedSuite, all_test_suites) |
+ if not os.path.exists(suite_path): |
+ raise Exception('Test suite %s not found in %s.\n' |
+ 'Supported test suites:\n %s\n' |
+ 'Ensure it has been built.\n' % |
+ (suite_name, suite_path, |
+ [s.name for s in gtest_config.STABLE_TEST_SUITES])) |
- for t, q in qualified_test_suites: |
- if not os.path.exists(q): |
- raise Exception('Test suite %s not found in %s.\n' |
- 'Supported test suites:\n %s\n' |
- 'Ensure it has been built.\n' % |
- (t, q, [s.name for s in gtest_config.STABLE_TEST_SUITES])) |
- return qualified_test_suites |
+ return suite_path |
-def _GetDisabledTestsFilterFromFile(test_suite): |
+def _GetDisabledTestsFilterFromFile(suite_name): |
"""Returns a gtest filter based on the *_disabled file. |
Args: |
- test_suite: Name of the test suite (e.g. base_unittests). |
+ suite_name: Name of the test suite (e.g. base_unittests). |
Returns: |
A gtest filter which excludes disabled tests. |
@@ -206,7 +190,7 @@ def _GetDisabledTestsFilterFromFile(test_suite): |
""" |
filter_file_path = os.path.join( |
os.path.abspath(os.path.dirname(__file__)), |
- 'filter', '%s_disabled' % test_suite) |
+ 'filter', '%s_disabled' % suite_name) |
if not filter_file_path or not os.path.exists(filter_file_path): |
logging.info('No filter file found at %s', filter_file_path) |
@@ -224,9 +208,9 @@ def _GetTestsFromDevice(runner_factory, devices): |
"""Get a list of tests from a device. |
Args: |
- runner_factory: callable that takes a device and index and returns a |
- TestRunner object. |
- devices: List of devices. |
+ runner_factory: Callable that takes device and shard_index and returns |
+ a TestRunner. |
+ devices: A list of device ids. |
Returns: |
All the tests in the test suite. |
@@ -272,7 +256,7 @@ def _FilterTestsUsingPrefixes(all_tests, pre=False, manual=False): |
return filtered_tests |
-def GetTestsFiltered(test_suite, gtest_filter, runner_factory, devices): |
+def GetTestsFiltered(suite_name, 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 |
@@ -282,7 +266,7 @@ def GetTestsFiltered(test_suite, gtest_filter, runner_factory, devices): |
3. Applies |gtest_filter|. |
Args: |
- test_suite: Name of the test suite (e.g. base_unittests). |
+ suite_name: 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. |
@@ -295,7 +279,7 @@ def GetTestsFiltered(test_suite, gtest_filter, runner_factory, devices): |
tests = _FilterTestsUsingPrefixes( |
tests, bool(gtest_filter), bool(gtest_filter)) |
tests = unittest_util.FilterTestNames( |
- tests, _GetDisabledTestsFilterFromFile(test_suite)) |
+ tests, _GetDisabledTestsFilterFromFile(suite_name)) |
if gtest_filter: |
tests = unittest_util.FilterTestNames(tests, gtest_filter) |
@@ -303,133 +287,58 @@ def GetTestsFiltered(test_suite, gtest_filter, runner_factory, devices): |
return tests |
-def _RunATestSuite(options, suite_name): |
- """Run a single test suite. |
- |
- Helper for Dispatch() to allow stop/restart of the emulator across |
- test bundles. If using the emulator, we start it on entry and stop |
- it on exit. |
+def Setup(use_exe_test_runner, suite_name, test_arguments, timeout, |
+ cleanup_test_files, tool, build_type, webkit, push_deps, |
+ gtest_filter): |
+ """Create the test runner factory and tests. |
Args: |
- options: options for running the tests. |
- suite_name: name of the test suite being run. |
+ use_exe_test_runner: If True, use the executable-based test runner. |
+ suite_name: The suite name specified on the command line. |
+ test_arguments: Additional arguments to pass to the test binary. |
+ timeout: Timeout for each test. |
+ cleanup_test_files: Whether or not to cleanup test files on device. |
+ tool: Name of the Valgrind tool. |
+ build_type: 'Release' or 'Debug'. |
+ webkit: Whether the suite is being run from a WebKit checkout. |
+ push_deps: If True, push all dependencies to the device. |
+ gtest_filter: Filter for tests. |
Returns: |
- A tuple of (base_test_result.TestRunResult object, exit code). |
- |
- Raises: |
- Exception: For various reasons including device failure or failing to reset |
- the test server port. |
+ A tuple of (TestRunnerFactory, tests). |
""" |
- attached_devices = [] |
- buildbot_emulators = [] |
- |
- if options.use_emulator: |
- buildbot_emulators = emulator.LaunchEmulators(options.emulator_count, |
- options.abi, |
- wait_for_boot=True) |
- attached_devices = [e.device for e in buildbot_emulators] |
- elif options.test_device: |
- attached_devices = [options.test_device] |
- else: |
- attached_devices = android_commands.GetAttachedDevices() |
- |
- if not attached_devices: |
- raise Exception('A device must be attached and online.') |
- # Reset the test port allocation. It's important to do it before starting |
- # to dispatch any tests. |
if not ports.ResetTestServerPortAllocation(): |
raise Exception('Failed to reset test server port.') |
- _GenerateDepsDirUsingIsolate(suite_name, options.build_type) |
+ suite_path = _GetSuitePath(use_exe_test_runner, suite_name, build_type) |
+ |
+ # TODO(gkanwar): This breaks the abstraction of having test_dispatcher.py deal |
+ # entirely with the devices. Can we do this another way? |
+ attached_devices = android_commands.GetAttachedDevices() |
+ deps_dir = _GenerateDepsDirUsingIsolate(suite_name, build_type) |
# Constructs a new TestRunner with the current options. |
- def RunnerFactory(device, shard_index): |
+ def TestRunnerFactory(device, shard_index): |
return test_runner.TestRunner( |
device, |
- options.test_suite, |
- options.test_arguments, |
- options.timeout, |
- options.cleanup_test_files, |
- options.tool, |
- options.build_type, |
- options.webkit, |
- options.push_deps, |
+ suite_path, |
+ test_arguments, |
+ timeout, |
+ cleanup_test_files, |
+ tool, |
+ build_type, |
+ webkit, |
+ push_deps, |
constants.GTEST_TEST_PACKAGE_NAME, |
constants.GTEST_TEST_ACTIVITY_NAME, |
constants.GTEST_COMMAND_LINE_FILE) |
# Get tests and split them up based on the number of devices. |
- tests = GetTestsFiltered(suite_name, options.test_filter, |
- RunnerFactory, attached_devices) |
+ tests = GetTestsFiltered(suite_name, gtest_filter, |
+ TestRunnerFactory, attached_devices) |
num_devices = len(attached_devices) |
tests = [':'.join(tests[i::num_devices]) for i in xrange(num_devices)] |
tests = [t for t in tests if t] |
- # Run tests. |
- test_results, exit_code = shard.ShardAndRunTests( |
- RunnerFactory, attached_devices, tests, options.build_type, |
- test_timeout=None, num_retries=options.num_retries) |
- |
- report_results.LogFull( |
- results=test_results, |
- test_type='Unit test', |
- test_package=suite_name, |
- build_type=options.build_type, |
- flakiness_server=options.flakiness_dashboard_server) |
- |
- if os.path.isdir(constants.ISOLATE_DEPS_DIR): |
- shutil.rmtree(constants.ISOLATE_DEPS_DIR) |
- |
- for buildbot_emulator in buildbot_emulators: |
- buildbot_emulator.Shutdown() |
- |
- return (test_results, exit_code) |
- |
- |
-def _ListTestSuites(): |
- """Display a list of available test suites.""" |
- print 'Available test suites are:' |
- for test_suite in gtest_config.STABLE_TEST_SUITES: |
- print test_suite |
- |
- |
-def Dispatch(options): |
- """Dispatches the tests, sharding if possible. |
- |
- If options.use_emulator is True, all tests will be run in new emulator |
- instance. |
- |
- Args: |
- options: options for running the tests. |
- |
- Returns: |
- base_test_result.TestRunResults object with the results of running the tests |
- """ |
- results = base_test_result.TestRunResults() |
- |
- if options.test_suite == 'help': |
- _ListTestSuites() |
- return (results, 0) |
- |
- if options.use_xvfb: |
- framebuffer = xvfb.Xvfb() |
- framebuffer.Start() |
- |
- all_test_suites = _FullyQualifiedTestSuites(options.exe, options.test_suite, |
- options.build_type) |
- exit_code = 0 |
- for suite_name, suite_path in all_test_suites: |
- # Give each test suite its own copy of options. |
- test_options = copy.deepcopy(options) |
- test_options.test_suite = suite_path |
- test_results, test_exit_code = _RunATestSuite(test_options, suite_name) |
- results.AddTestRunResults(test_results) |
- if test_exit_code and exit_code != constants.ERROR_EXIT_CODE: |
- exit_code = test_exit_code |
- |
- if options.use_xvfb: |
- framebuffer.Stop() |
- |
- return (results, exit_code) |
+ return (TestRunnerFactory, tests) |