summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHsin-Yi Chen <hsinyichen@google.com>2017-07-19 10:54:19 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2017-07-19 10:54:19 +0000
commit4085d752d9a6a8fc2c83dfdff8befe88c4992abc (patch)
treedc8f8436f0209af49eded8f14b6677d47a50c189
parent159c0bb041f325c088cd059a4ca26344fadc18a0 (diff)
parentd3bca72098b0ff1219dad8b1fdaf3ab23d12a7ee (diff)
downloadvts-4085d752d9a6a8fc2c83dfdff8befe88c4992abc.tar.gz
Merge "Handle timeout in test runner" into oc-dev
-rw-r--r--harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java15
-rwxr-xr-xrunners/host/config_parser.py19
-rw-r--r--runners/host/keys.py1
-rw-r--r--runners/host/test_runner.py30
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.