| # Copyright 2018, 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. |
| |
| """ |
| TestInfo class. |
| """ |
| |
| from collections import namedtuple |
| |
| # pylint: disable=import-error |
| import constants |
| |
| |
| TestFilterBase = namedtuple('TestFilter', ['class_name', 'methods']) |
| |
| |
| class TestInfo(object): |
| """Information needed to identify and run a test.""" |
| |
| # pylint: disable=too-many-arguments |
| def __init__(self, test_name, test_runner, build_targets, data=None, |
| suite=None, module_class=None, install_locations=None, |
| test_finder='', compatibility_suites=None): |
| """Init for TestInfo. |
| |
| Args: |
| test_name: String of test name. |
| test_runner: String of test runner. |
| build_targets: Set of build targets. |
| data: Dict of data for test runners to use. |
| suite: Suite for test runners to use. |
| module_class: A list of test classes. It's a snippet of class |
| in module_info. e.g. ["EXECUTABLES", "NATIVE_TESTS"] |
| install_locations: Set of install locations. |
| e.g. set(['host', 'device']) |
| test_finder: String of test finder. |
| compatibility_suites: A list of compatibility_suites. It's a |
| snippet of compatibility_suites in module_info. e.g. |
| ["device-tests", "vts10"] |
| """ |
| self.test_name = test_name |
| self.test_runner = test_runner |
| self.build_targets = build_targets |
| self.data = data if data else {} |
| self.suite = suite |
| self.module_class = module_class if module_class else [] |
| self.install_locations = (install_locations if install_locations |
| else set()) |
| # True if the TestInfo is built from a test configured in TEST_MAPPING. |
| self.from_test_mapping = False |
| # True if the test should run on host and require no device. The |
| # attribute is only set through TEST_MAPPING file. |
| self.host = False |
| self.test_finder = test_finder |
| self.compatibility_suites = (map(str, compatibility_suites) |
| if compatibility_suites else []) |
| |
| def __str__(self): |
| host_info = (' - runs on host without device required.' if self.host |
| else '') |
| return ('test_name: %s - test_runner:%s - build_targets:%s - data:%s - ' |
| 'suite:%s - module_class: %s - install_locations:%s%s - ' |
| 'test_finder: %s - compatibility_suites:%s' % ( |
| self.test_name, self.test_runner, self.build_targets, |
| self.data, self.suite, self.module_class, |
| self.install_locations, host_info, self.test_finder, |
| self.compatibility_suites)) |
| |
| def get_supported_exec_mode(self): |
| """Get the supported execution mode of the test. |
| |
| Determine the test supports which execution mode by strategy: |
| Robolectric/JAVA_LIBRARIES --> 'both' |
| Not native tests or installed only in out/target --> 'device' |
| Installed only in out/host --> 'both' |
| Installed under host and target --> 'both' |
| |
| Return: |
| String of execution mode. |
| """ |
| install_path = self.install_locations |
| if not self.module_class: |
| return constants.DEVICE_TEST |
| # Let Robolectric test support both. |
| if constants.MODULE_CLASS_ROBOLECTRIC in self.module_class: |
| return constants.BOTH_TEST |
| # Let JAVA_LIBRARIES support both. |
| if constants.MODULE_CLASS_JAVA_LIBRARIES in self.module_class: |
| return constants.BOTH_TEST |
| if not install_path: |
| return constants.DEVICE_TEST |
| # Non-Native test runs on device-only. |
| if constants.MODULE_CLASS_NATIVE_TESTS not in self.module_class: |
| return constants.DEVICE_TEST |
| # Native test with install path as host should be treated as both. |
| # Otherwise, return device test. |
| if len(install_path) == 1 and constants.DEVICE_TEST in install_path: |
| return constants.DEVICE_TEST |
| return constants.BOTH_TEST |
| |
| |
| class TestFilter(TestFilterBase): |
| """Information needed to filter a test in Tradefed""" |
| |
| def to_set_of_tf_strings(self): |
| """Return TestFilter as set of strings in TradeFed filter format.""" |
| if self.methods: |
| return {'%s#%s' % (self.class_name, m) for m in self.methods} |
| return {self.class_name} |