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 mainline_modules=None): 35 """Init for TestInfo. 36 37 Args: 38 test_name: String of test name. 39 test_runner: String of test runner. 40 build_targets: Set of build targets. 41 data: Dict of data for test runners to use. 42 suite: Suite for test runners to use. 43 module_class: A list of test classes. It's a snippet of class 44 in module_info. e.g. ["EXECUTABLES", "NATIVE_TESTS"] 45 install_locations: Set of install locations. 46 e.g. set(['host', 'device']) 47 test_finder: String of test finder. 48 compatibility_suites: A list of compatibility_suites. It's a 49 snippet of compatibility_suites in module_info. e.g. 50 ["device-tests", "vts10"] 51 mainline_modules: A list of mainline modules. 52 e.g. ['some1.apk', 'some2.apex', 'some3.apks', 53 'some1.apk+some2.apex'] 54 """ 55 self.test_name = test_name 56 self.test_runner = test_runner 57 self.build_targets = build_targets 58 self.data = data if data else {} 59 self.suite = suite 60 self.module_class = module_class if module_class else [] 61 self.install_locations = (install_locations if install_locations 62 else set()) 63 # True if the TestInfo is built from a test configured in TEST_MAPPING. 64 self.from_test_mapping = False 65 # True if the test should run on host and require no device. The 66 # attribute is only set through TEST_MAPPING file. 67 self.host = False 68 self.test_finder = test_finder 69 self.compatibility_suites = (compatibility_suites 70 if compatibility_suites else []) 71 self.mainline_modules = mainline_modules if mainline_modules else [] 72 73 def __str__(self): 74 host_info = (' - runs on host without device required.' if self.host 75 else '') 76 return ('test_name: %s - test_runner:%s - build_targets:%s - data:%s - ' 77 'suite:%s - module_class: %s - install_locations:%s%s - ' 78 'test_finder: %s - compatibility_suites:%s -' 79 'mainline_modules:%s' % ( 80 self.test_name, self.test_runner, self.build_targets, 81 self.data, self.suite, self.module_class, 82 self.install_locations, host_info, self.test_finder, 83 self.compatibility_suites, self.mainline_modules)) 84 85 def get_supported_exec_mode(self): 86 """Get the supported execution mode of the test. 87 88 Determine the test supports which execution mode by strategy: 89 Robolectric/JAVA_LIBRARIES --> 'both' 90 Not native tests or installed only in out/target --> 'device' 91 Installed only in out/host --> 'both' 92 Installed under host and target --> 'both' 93 94 Return: 95 String of execution mode. 96 """ 97 install_path = self.install_locations 98 if not self.module_class: 99 return constants.DEVICE_TEST 100 # Let Robolectric test support both. 101 if constants.MODULE_CLASS_ROBOLECTRIC in self.module_class: 102 return constants.BOTH_TEST 103 # Let JAVA_LIBRARIES support both. 104 if constants.MODULE_CLASS_JAVA_LIBRARIES in self.module_class: 105 return constants.BOTH_TEST 106 if not install_path: 107 return constants.DEVICE_TEST 108 # Non-Native test runs on device-only. 109 if constants.MODULE_CLASS_NATIVE_TESTS not in self.module_class: 110 return constants.DEVICE_TEST 111 # Native test with install path as host should be treated as both. 112 # Otherwise, return device test. 113 if len(install_path) == 1 and constants.DEVICE_TEST in install_path: 114 return constants.DEVICE_TEST 115 return constants.BOTH_TEST 116 117 def get_test_paths(self): 118 """Get the relative path of test_info. 119 120 Search build target's MODULE-IN as the test path. 121 122 Return: 123 A list of string of the relative path for test, None if test 124 path information not found. 125 """ 126 test_paths = [] 127 for build_target in self.build_targets: 128 if str(build_target).startswith(constants.MODULES_IN): 129 test_paths.append( 130 str(build_target).replace( 131 constants.MODULES_IN, '').replace('-', '/')) 132 return test_paths if test_paths else None 133 134class TestFilter(TestFilterBase): 135 """Information needed to filter a test in Tradefed""" 136 137 def to_set_of_tf_strings(self): 138 """Return TestFilter as set of strings in TradeFed filter format.""" 139 if self.methods: 140 return {'%s#%s' % (self.class_name, m) for m in self.methods} 141 return {self.class_name} 142