Merge "Include binderDriverInterfaceTest_IPC_32 in VTS package"
diff --git a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
index 715ae42..4d9b816 100644
--- a/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
+++ b/harnesses/tradefed/src/com/android/tradefed/testtype/VtsMultiDeviceTest.java
@@ -82,6 +82,7 @@
static final String TESTMODULE = "TestModule";
static final String TEST_PLAN_REPORT_FILE = "TEST_PLAN_REPORT_FILE";
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";
@@ -130,6 +131,7 @@
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";
@@ -137,8 +139,11 @@
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;
@@ -644,6 +649,9 @@
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);
@@ -875,7 +883,8 @@
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 5fcf85d..ad1d845 100755
--- a/runners/host/config_parser.py
+++ b/runners/host/config_parser.py
@@ -44,25 +44,6 @@
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 687e5af..4782545 100644
--- a/runners/host/keys.py
+++ b/runners/host/keys.py
@@ -29,6 +29,7 @@
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 b17d57a..2bd7999 100644
--- a/runners/host/test_runner.py
+++ b/runners/host/test_runner.py
@@ -25,6 +25,8 @@
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 @@
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.
diff --git a/testcases/template/gtest_binary_test/gtest_binary_test.py b/testcases/template/gtest_binary_test/gtest_binary_test.py
index c919130..12bbef2 100644
--- a/testcases/template/gtest_binary_test/gtest_binary_test.py
+++ b/testcases/template/gtest_binary_test/gtest_binary_test.py
@@ -78,7 +78,7 @@
ld_library_path = self.ld_library_path[
tag] if tag in self.ld_library_path else None
profiling_library_path = self.profiling_library_path[
- tag] if tag in self.ld_library_path else None
+ tag] if tag in self.profiling_library_path else None
args += " --gtest_list_tests"
list_test_case = binary_test_case.BinaryTestCase(
diff --git a/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py b/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py
index 9236f42..554b919 100644
--- a/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py
+++ b/testcases/template/hal_hidl_gtest/hal_hidl_gtest.py
@@ -14,13 +14,14 @@
# limitations under the License.
#
+import copy
import logging
from vts.runners.host import const
from vts.runners.host import keys
from vts.runners.host import test_runner
from vts.testcases.template.gtest_binary_test import gtest_binary_test
-
+from vts.testcases.template.gtest_binary_test import gtest_test_case
from vts.utils.python.cpu import cpu_frequency_scaling
@@ -72,6 +73,107 @@
if passthrough_opt or self.coverage.enabled:
self._EnablePassthroughMode()
+ # @Override
+ def CreateTestCase(self, path, tag=''):
+ '''Create a list of GtestTestCase objects from a binary path.
+
+ Support testing against different service names by first executing a
+ dummpy test case which lists all the registered hal services. Then
+ query the service name(s) for each registered service with lshal.
+ For each service name, create a new test case each with the service
+ name as an additional argument.
+
+ Args:
+ path: string, absolute path of a gtest binary on device
+ tag: string, a tag that will be appended to the end of test name
+
+ Returns:
+ A list of GtestTestCase objects.
+ '''
+ initial_test_cases = super(HidlHalGTest, self).CreateTestCase(path,
+ tag)
+ if not initial_test_cases:
+ return initial_test_cases
+ # first, run one test with --list_registered_services.
+ list_service_test_case = copy.copy(initial_test_cases[0])
+ list_service_test_case.args += " --list_registered_services"
+ results = self.shell.Execute(list_service_test_case.GetRunCommand())
+ if (results[const.EXIT_CODE][0]):
+ logging.error('Failed to list test cases from binary %s',
+ list_service_test_case.path)
+ # parse the results to get the registered service list.
+ registered_services = []
+ for line in results[const.STDOUT][0].split('\n'):
+ line = str(line)
+ if line.startswith('hal_service: '):
+ service = line[len('hal_service: '):]
+ registered_services.append(service)
+
+ # If no service registered, return the initial test cases directly.
+ if not registered_services:
+ return initial_test_cases
+
+ # find the correponding service name(s) for each registered service and
+ # store the mapping in dict service_instances.
+ service_instances = {}
+ for service in registered_services:
+ cmd = '"lshal -i | grep -o %s/.* | sort -u"' % service
+ out = str(self._dut.adb.shell(cmd)).split()
+ service_names = map(lambda x: x[x.find('/') + 1:], out)
+ logging.info("registered service: %s with name: %s" %
+ (service, ' '.join(service_names)))
+ service_instances[service] = service_names
+
+ # get all the combination of service instances.
+ service_instance_combinations = self._GetServiceInstancesCombinations(
+ registered_services, service_instances)
+
+ new_test_cases = []
+ for test_case in initial_test_cases:
+ for instance_combination in service_instance_combinations:
+ new_test_case = copy.copy(test_case)
+ for instance in instance_combination:
+ new_test_case.args += " --hal_service_instance=" + instance
+ new_test_case.tag = instance[instance.find(
+ '/'):] + new_test_case.tag
+ new_test_cases.append(new_test_case)
+ return new_test_cases
+
+ @classmethod
+ def _GetServiceInstancesCombinations(self, services, service_instances):
+ '''Create all combinations of instances for all services.
+
+ Args:
+ services: list, all services used in the test. e.g. [s1, s2]
+ service_instances: dictionary, mapping of each service and the
+ corresponding service name(s).
+ e.g. {"s1": ["n1"], "s2": ["n2", "n3"]}
+
+ Returns:
+ A list of all service instance combinations.
+ e.g. [[s1/n1, s2/n2], [s1/n1, s2/n3]]
+ '''
+
+ service_instance_combinations = []
+ if not services:
+ return service_instance_combinations
+ service = services.pop()
+ pre_instance_combs = self._GetServiceInstancesCombinations(
+ services, service_instances)
+ if service not in service_instances:
+ return pre_instance_combs
+ for name in service_instances[service]:
+ if not pre_instance_combs:
+ new_instance_comb = [service + '/' + name]
+ service_instance_combinations.append(new_instance_comb)
+ else:
+ for instance_comb in pre_instance_combs:
+ new_instance_comb = [service + '/' + name]
+ new_instance_comb.extend(instance_comb)
+ service_instance_combinations.append(new_instance_comb)
+
+ return service_instance_combinations
+
def _EnablePassthroughMode(self):
"""Enable passthrough mode by setting getStub to true.
@@ -94,21 +196,20 @@
super(HidlHalGTest, self).setUp()
if (self._skip_if_thermal_throttling and
- getattr(self, "_cpu_freq", None)):
+ getattr(self, "_cpu_freq", None)):
self._cpu_freq.SkipIfThermalThrottling(retry_delay_secs=30)
def tearDown(self):
"""Skips the test case if there is thermal throttling."""
if (self._skip_if_thermal_throttling and
- getattr(self, "_cpu_freq", None)):
+ getattr(self, "_cpu_freq", None)):
self._cpu_freq.SkipIfThermalThrottling()
super(HidlHalGTest, self).tearDown()
def tearDownClass(self):
"""Turns off CPU frequency scaling."""
- if (not self._skip_all_testcases and
- getattr(self, "_cpu_freq", None)):
+ if (not self._skip_all_testcases and getattr(self, "_cpu_freq", None)):
logging.info("Enable CPU frequency scaling")
self._cpu_freq.EnableCpuScaling()
diff --git a/testcases/template/hal_hidl_gtest/hal_hidl_gtest_unittest.py b/testcases/template/hal_hidl_gtest/hal_hidl_gtest_unittest.py
new file mode 100644
index 0000000..bde230e
--- /dev/null
+++ b/testcases/template/hal_hidl_gtest/hal_hidl_gtest_unittest.py
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import unittest
+
+from vts.testcases.template.hal_hidl_gtest import hal_hidl_gtest
+
+class HidlHalGTestUnitTest(unittest.TestCase):
+ """Tests for hal hidl gtest template"""
+
+ def testGetServiceInstancesCombinations(self):
+ """Test the function to get service instance combinations"""
+
+ comb1 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ [], {})
+ self.assertEquals(0, len(comb1))
+ comb2 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ ["s1"], {})
+ self.assertEquals(0, len(comb2))
+ comb3 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ ["s1"], {"s1": ["n1"]})
+ self.assertEqual([["s1/n1"]], comb3)
+ comb4 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ ["s1"], {"s1": ["n1", "n2"]})
+ self.assertEqual([["s1/n1"], ["s1/n2"]], comb4)
+ comb5 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"]})
+ self.assertEqual([["s1/n1"], ["s1/n2"]], comb5)
+ comb6 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"],
+ "s2": ["n3"]})
+ self.assertEqual([["s2/n3", "s1/n1"], ["s2/n3", "s1/n2"]], comb6)
+ comb7 = hal_hidl_gtest.HidlHalGTest._GetServiceInstancesCombinations(
+ ["s1", "s2"], {"s1": ["n1", "n2"],
+ "s2": ["n3", "n4"]})
+ self.assertEqual([["s2/n3", "s1/n1"], ["s2/n3", "s1/n2"],
+ ["s2/n4", "s1/n1"], ["s2/n4", "s1/n2"]], comb7)
+
+
+if __name__ == '__main__':
+ unittest.main()