diff options
author | Hsin-Yi Chen <hsinyichen@google.com> | 2017-07-19 10:54:19 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-07-19 10:54:19 +0000 |
commit | 4085d752d9a6a8fc2c83dfdff8befe88c4992abc (patch) | |
tree | dc8f8436f0209af49eded8f14b6677d47a50c189 | |
parent | 159c0bb041f325c088cd059a4ca26344fadc18a0 (diff) | |
parent | d3bca72098b0ff1219dad8b1fdaf3ab23d12a7ee (diff) | |
download | vts-4085d752d9a6a8fc2c83dfdff8befe88c4992abc.tar.gz |
Merge "Handle timeout in test runner" into oc-dev
-rw-r--r-- | harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java | 15 | ||||
-rwxr-xr-x | runners/host/config_parser.py | 19 | ||||
-rw-r--r-- | runners/host/keys.py | 1 | ||||
-rw-r--r-- | runners/host/test_runner.py | 30 |
4 files changed, 38 insertions, 27 deletions
diff --git a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java index 9b0aea399..7c50bcbe4 100644 --- a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java +++ b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java @@ -74,6 +74,7 @@ IRuntimeHintProvider, ITestCollector, IBuildReceiver, IAbiReceiver { static final String PYTHONPATH = "PYTHONPATH"; static final String SERIAL = "serial"; static final String TEST_SUITE = "test_suite"; + static final String TEST_MAX_TIMEOUT = "test_max_timeout"; static final String VIRTUAL_ENV_PATH = "VIRTUALENVPATH"; static final String ABI_NAME = "abi_name"; static final String ABI_BITNESS = "abi_bitness"; @@ -116,6 +117,7 @@ IRuntimeHintProvider, ITestCollector, IBuildReceiver, IAbiReceiver { static final String TEMPLATE_HAL_HIDL_GTEST_PATH = "vts/testcases/template/hal_hidl_gtest/hal_hidl_gtest"; static final String TEMPLATE_HAL_HIDL_REPLAY_TEST_PATH = "vts/testcases/template/hal_hidl_replay_test/hal_hidl_replay_test"; static final String TEMPLATE_HOST_BINARY_TEST_PATH = "vts/testcases/template/host_binary_test/host_binary_test"; + static final long TEST_ABORT_TIMEOUT_MSECS = 1000 * 15; static final String TEST_RUN_SUMMARY_FILE_NAME = "test_run_summary.json"; static final float DEFAULT_TARGET_VERSION = -1; static final String DEFAULT_TESTCASE_CONFIG_PATH = "vts/tools/vts-tradefed/res/default/DefaultTestCase.config"; @@ -123,8 +125,11 @@ IRuntimeHintProvider, ITestCollector, IBuildReceiver, IAbiReceiver { private ITestDevice mDevice = null; private IAbi mAbi = null; - @Option(name = "test-timeout", description = "maximum amount of time" - + "(im milliseconds) tests are allowed to run", + @Option(name = "test-timeout", + description = "The amount of time (in milliseconds) for a test invocation. " + + "If the test cannot finish before timeout, it should interrupt itself and " + + "clean up in " + TEST_ABORT_TIMEOUT_MSECS + "ms. Hence the actual timeout " + + "is the specified value + " + TEST_ABORT_TIMEOUT_MSECS + "ms.", isTimeVal = true) private long mTestTimeout = 1000 * 60 * 60 * 3; @@ -611,6 +616,9 @@ IRuntimeHintProvider, ITestCollector, IBuildReceiver, IAbiReceiver { jsonObject.put(TEST_SUITE, suite); CLog.i("Added %s to the Json object", TEST_SUITE); + jsonObject.put(TEST_MAX_TIMEOUT, mTestTimeout); + CLog.i("Added %s to the Json object: %d", TEST_MAX_TIMEOUT, mTestTimeout); + if (mAbi != null) { jsonObject.put(ABI_NAME, mAbi.getName()); CLog.i("Added %s to the Json object", ABI_NAME); @@ -805,7 +813,8 @@ IRuntimeHintProvider, ITestCollector, IBuildReceiver, IAbiReceiver { cmd = ArrayUtil.buildArray(baseOpts, testModule); printToDeviceLogcatAboutTestModuleStatus("BEGIN"); - CommandResult commandResult = mRunUtil.runTimedCmd(mTestTimeout, cmd); + CommandResult commandResult = + mRunUtil.runTimedCmd(mTestTimeout + TEST_ABORT_TIMEOUT_MSECS, cmd); if (commandResult != null) { CommandStatus commandStatus = commandResult.getStatus(); diff --git a/runners/host/config_parser.py b/runners/host/config_parser.py index 5fcf85d5f..ad1d84522 100755 --- a/runners/host/config_parser.py +++ b/runners/host/config_parser.py @@ -44,25 +44,6 @@ def GetDefaultConfig(test_name): return result -def gen_term_signal_handler(test_runners): - """Generates a termination signal handler function. - - Args: - test_runners: A list of TestRunner objects. - - Returns: - A function to be called when termination signals are received from - command line. This function stops all TestRunner objects. - """ - - def termination_sig_handler(signal_num, frame): - for t in test_runners: - t.stop() - sys.exit(1) - - return termination_sig_handler - - def load_test_config_file(test_config_path, tb_filters=None, baseline_config=None): diff --git a/runners/host/keys.py b/runners/host/keys.py index 202ee190d..c44b50fb0 100644 --- a/runners/host/keys.py +++ b/runners/host/keys.py @@ -29,6 +29,7 @@ class ConfigKeys(object): KEY_TESTBED_NAME = "name" KEY_TEST_PATHS = "test_paths" KEY_TEST_SUITE = "test_suite" + KEY_TEST_MAX_TIMEOUT = "test_max_timeout" # Keys in test suite KEY_INCLUDE_FILTER = "include_filter" diff --git a/runners/host/test_runner.py b/runners/host/test_runner.py index 85b92961a..0d0048dc5 100644 --- a/runners/host/test_runner.py +++ b/runners/host/test_runner.py @@ -25,6 +25,8 @@ import os import pkgutil import signal import sys +import thread +import threading from vts.runners.host import base_test from vts.runners.host import config_parser @@ -98,20 +100,38 @@ def runTestClass(test_class): test_identifiers = [(test_cls_name, None)] for config in test_configs: + if keys.ConfigKeys.KEY_TEST_MAX_TIMEOUT in config: + timeout_sec = int(config[keys.ConfigKeys.KEY_TEST_MAX_TIMEOUT]) / 1000.0 + else: + timeout_sec = 60 * 60 * 3 + logging.warning("%s unspecified. Set timeout to %s seconds.", + keys.ConfigKeys.KEY_TEST_MAX_TIMEOUT, timeout_sec) + # The default SIGINT handler sends KeyboardInterrupt to main thread. + # On Windows, raising CTRL_C_EVENT, which is received as SIGINT, + # has no effect on non-console process. interrupt_main() works but + # does not unblock main thread's IO immediately. + timeout_func = (raiseSigint if not utils.is_on_windows() else + thread.interrupt_main) + sig_timer = threading.Timer(timeout_sec, timeout_func) + tr = TestRunner(config, test_identifiers) tr.parseTestConfig(config) try: - # Create console signal handler to make sure TestRunner is stopped - # in the event of termination. - handler = config_parser.gen_term_signal_handler([tr]) - signal.signal(signal.SIGTERM, handler) - signal.signal(signal.SIGINT, handler) + sig_timer.start() tr.runTestClass(test_class, None) + except KeyboardInterrupt as e: + logging.exception("Aborted by timeout or ctrl+C: %s", e) finally: + sig_timer.cancel() tr.stop() return tr.results +def raiseSigint(): + """Raises SIGINT.""" + os.kill(os.getpid(), signal.SIGINT) + + class TestRunner(object): """The class that instantiates test classes, executes test cases, and report results. |