1# Copyright 2018, The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15""" 16TestInfo class. 17""" 18 19from collections import namedtuple 20 21import constants 22 23 24TestFilterBase = namedtuple('TestFilter', ['class_name', 'methods']) 25 26 27class TestInfo: 28 """Information needed to identify and run a test.""" 29 30 # pylint: disable=too-many-arguments 31 def __init__(self, test_name, test_runner, build_targets, data=None, 32 suite=None, module_class=None, install_locations=None, 33 test_finder='', compatibility_suites=None): 34 """Init for TestInfo. 35 36 Args: 37 test_name: String of test name. 38 test_runner: String of test runner. 39 build_targets: Set of build targets. 40 data: Dict of data for test runners to use. 41 suite: Suite for test runners to use. 42 module_class: A list of test classes. It's a snippet of class 43 in module_info. e.g. ["EXECUTABLES", "NATIVE_TESTS"] 44 install_locations: Set of install locations. 45 e.g. set(['host', 'device']) 46 test_finder: String of test finder. 47 compatibility_suites: A list of compatibility_suites. It's a 48 snippet of compatibility_suites in module_info. e.g. 49 ["device-tests", "vts10"] 50 """ 51 self.test_name = test_name 52 self.test_runner = test_runner 53 self.build_targets = build_targets 54 self.data = data if data else {} 55 self.suite = suite 56 self.module_class = module_class if module_class else [] 57 self.install_locations = (install_locations if install_locations 58 else set()) 59 # True if the TestInfo is built from a test configured in TEST_MAPPING. 60 self.from_test_mapping = False 61 # True if the test should run on host and require no device. The 62 # attribute is only set through TEST_MAPPING file. 63 self.host = False 64 self.test_finder = test_finder 65 self.compatibility_suites = (map(str, compatibility_suites) 66 if compatibility_suites else []) 67 68 def __str__(self): 69 host_info = (' - runs on host without device required.' if self.host 70 else '') 71 return ('test_name: %s - test_runner:%s - build_targets:%s - data:%s - ' 72 'suite:%s - module_class: %s - install_locations:%s%s - ' 73 'test_finder: %s - compatibility_suites:%s' % ( 74 self.test_name, self.test_runner, self.build_targets, 75 self.data, self.suite, self.module_class, 76 self.install_locations, host_info, self.test_finder, 77 self.compatibility_suites)) 78 79 def get_supported_exec_mode(self): 80 """Get the supported execution mode of the test. 81 82 Determine the test supports which execution mode by strategy: 83 Robolectric/JAVA_LIBRARIES --> 'both' 84 Not native tests or installed only in out/target --> 'device' 85 Installed only in out/host --> 'both' 86 Installed under host and target --> 'both' 87 88 Return: 89 String of execution mode. 90 """ 91 install_path = self.install_locations 92 if not self.module_class: 93 return constants.DEVICE_TEST 94 # Let Robolectric test support both. 95 if constants.MODULE_CLASS_ROBOLECTRIC in self.module_class: 96 return constants.BOTH_TEST 97 # Let JAVA_LIBRARIES support both. 98 if constants.MODULE_CLASS_JAVA_LIBRARIES in self.module_class: 99 return constants.BOTH_TEST 100 if not install_path: 101 return constants.DEVICE_TEST 102 # Non-Native test runs on device-only. 103 if constants.MODULE_CLASS_NATIVE_TESTS not in self.module_class: 104 return constants.DEVICE_TEST 105 # Native test with install path as host should be treated as both. 106 # Otherwise, return device test. 107 if len(install_path) == 1 and constants.DEVICE_TEST in install_path: 108 return constants.DEVICE_TEST 109 return constants.BOTH_TEST 110 111 112class TestFilter(TestFilterBase): 113 """Information needed to filter a test in Tradefed""" 114 115 def to_set_of_tf_strings(self): 116 """Return TestFilter as set of strings in TradeFed filter format.""" 117 if self.methods: 118 return {'%s#%s' % (self.class_name, m) for m in self.methods} 119 return {self.class_name} 120