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""" 16Test Finder Handler module. 17""" 18 19# pylint: disable=line-too-long 20# pylint: disable=import-outside-toplevel 21# pylint: disable=protected-access 22 23import inspect 24import logging 25 26import atest_enum 27 28from test_finders import cache_finder 29from test_finders import test_finder_base 30from test_finders import suite_plan_finder 31from test_finders import tf_integration_finder 32from test_finders import module_finder 33 34# List of default test finder classes. 35_TEST_FINDERS = { 36 suite_plan_finder.SuitePlanFinder, 37 tf_integration_finder.TFIntegrationFinder, 38 module_finder.ModuleFinder, 39 cache_finder.CacheFinder, 40} 41 42# Explanation of REFERENCE_TYPEs: 43# ---------------------------------- 44# 0. MODULE: LOCAL_MODULE or LOCAL_PACKAGE_NAME value in Android.mk/Android.bp. 45# 1. CLASS: Names which the same with a ClassName.java/kt file. 46# 2. QUALIFIED_CLASS: String like "a.b.c.ClassName". 47# 3. MODULE_CLASS: Combo of MODULE and CLASS as "module:class". 48# 4. PACKAGE: Package in java file. Same as file path to java file. 49# 5. MODULE_PACKAGE: Combo of MODULE and PACKAGE as "module:package". 50# 6. MODULE_FILE_PATH: File path to dir of tests or test itself. 51# 7. INTEGRATION_FILE_PATH: File path to config xml in one of the 4 integration 52# config directories. 53# 8. INTEGRATION: xml file name in one of the 4 integration config directories. 54# 9. SUITE: Value of the "run-suite-tag" in xml config file in 4 config dirs. 55# Same as value of "test-suite-tag" in AndroidTest.xml files. 56# 10. CC_CLASS: Test case in cc file. 57# 11. SUITE_PLAN: Suite name such as cts. 58# 12. SUITE_PLAN_FILE_PATH: File path to config xml in the suite config 59# directories. 60# 13. CACHE: A pseudo type that runs cache_finder without finding test in real. 61_REFERENCE_TYPE = atest_enum.AtestEnum(['MODULE', 'CLASS', 'QUALIFIED_CLASS', 62 'MODULE_CLASS', 'PACKAGE', 63 'MODULE_PACKAGE', 'MODULE_FILE_PATH', 64 'INTEGRATION_FILE_PATH', 'INTEGRATION', 65 'SUITE', 'CC_CLASS', 'SUITE_PLAN', 66 'SUITE_PLAN_FILE_PATH', 'CACHE', 67 'CONFIG']) 68 69_REF_TYPE_TO_FUNC_MAP = { 70 _REFERENCE_TYPE.MODULE: module_finder.ModuleFinder.find_test_by_module_name, 71 _REFERENCE_TYPE.CLASS: module_finder.ModuleFinder.find_test_by_class_name, 72 _REFERENCE_TYPE.MODULE_CLASS: module_finder.ModuleFinder.find_test_by_module_and_class, 73 _REFERENCE_TYPE.QUALIFIED_CLASS: module_finder.ModuleFinder.find_test_by_class_name, 74 _REFERENCE_TYPE.PACKAGE: module_finder.ModuleFinder.find_test_by_package_name, 75 _REFERENCE_TYPE.MODULE_PACKAGE: module_finder.ModuleFinder.find_test_by_module_and_package, 76 _REFERENCE_TYPE.MODULE_FILE_PATH: module_finder.ModuleFinder.find_test_by_path, 77 _REFERENCE_TYPE.INTEGRATION_FILE_PATH: 78 tf_integration_finder.TFIntegrationFinder.find_int_test_by_path, 79 _REFERENCE_TYPE.INTEGRATION: 80 tf_integration_finder.TFIntegrationFinder.find_test_by_integration_name, 81 _REFERENCE_TYPE.CC_CLASS: 82 module_finder.ModuleFinder.find_test_by_cc_class_name, 83 _REFERENCE_TYPE.SUITE_PLAN:suite_plan_finder.SuitePlanFinder.find_test_by_suite_name, 84 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH: 85 suite_plan_finder.SuitePlanFinder.find_test_by_suite_path, 86 _REFERENCE_TYPE.CACHE: cache_finder.CacheFinder.find_test_by_cache, 87 _REFERENCE_TYPE.CONFIG: module_finder.ModuleFinder.find_test_by_config_name, 88} 89 90 91def _get_finder_instance_dict(module_info): 92 """Return dict of finder instances. 93 94 Args: 95 module_info: ModuleInfo for finder classes to use. 96 97 Returns: 98 Dict of finder instances keyed by their name. 99 """ 100 instance_dict = {} 101 for finder in _get_test_finders(): 102 instance_dict[finder.NAME] = finder(module_info=module_info) 103 return instance_dict 104 105 106def _get_test_finders(): 107 """Returns the test finders. 108 109 If external test types are defined outside atest, they can be try-except 110 imported into here. 111 112 Returns: 113 Set of test finder classes. 114 """ 115 test_finders_list = _TEST_FINDERS 116 # Example import of external test finder: 117 try: 118 from test_finders import example_finder 119 test_finders_list.add(example_finder.ExampleFinder) 120 except ImportError: 121 pass 122 return test_finders_list 123 124# pylint: disable=too-many-branches 125# pylint: disable=too-many-return-statements 126def _get_test_reference_types(ref): 127 """Determine type of test reference based on the content of string. 128 129 Examples: 130 The string 'SequentialRWTest' could be a reference to 131 a Module or a Class name. 132 133 The string 'cts/tests/filesystem' could be a Path, Integration 134 or Suite reference. 135 136 Args: 137 ref: A string referencing a test. 138 139 Returns: 140 A list of possible REFERENCE_TYPEs (ints) for reference string. 141 """ 142 if ref.startswith('.') or '..' in ref: 143 return [_REFERENCE_TYPE.CACHE, 144 _REFERENCE_TYPE.INTEGRATION_FILE_PATH, 145 _REFERENCE_TYPE.MODULE_FILE_PATH, 146 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH] 147 if '/' in ref: 148 if ref.startswith('/'): 149 return [_REFERENCE_TYPE.CACHE, 150 _REFERENCE_TYPE.INTEGRATION_FILE_PATH, 151 _REFERENCE_TYPE.MODULE_FILE_PATH, 152 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH] 153 if ':' in ref: 154 return [_REFERENCE_TYPE.CACHE, 155 _REFERENCE_TYPE.INTEGRATION_FILE_PATH, 156 _REFERENCE_TYPE.MODULE_FILE_PATH, 157 _REFERENCE_TYPE.INTEGRATION, 158 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH, 159 _REFERENCE_TYPE.MODULE_CLASS] 160 return [_REFERENCE_TYPE.CACHE, 161 _REFERENCE_TYPE.INTEGRATION_FILE_PATH, 162 _REFERENCE_TYPE.MODULE_FILE_PATH, 163 _REFERENCE_TYPE.INTEGRATION, 164 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH, 165 _REFERENCE_TYPE.CC_CLASS, 166 # TODO: Uncomment in SUITE when it's supported 167 # _REFERENCE_TYPE.SUITE 168 ] 169 if '.' in ref: 170 ref_end = ref.rsplit('.', 1)[-1] 171 ref_end_is_upper = ref_end[0].isupper() 172 if ':' in ref: 173 if '.' in ref: 174 if ref_end_is_upper: 175 # Module:fully.qualified.Class or Integration:fully.q.Class 176 return [_REFERENCE_TYPE.CACHE, 177 _REFERENCE_TYPE.INTEGRATION, 178 _REFERENCE_TYPE.MODULE_CLASS] 179 # Module:some.package 180 return [_REFERENCE_TYPE.CACHE, _REFERENCE_TYPE.MODULE_PACKAGE, 181 _REFERENCE_TYPE.MODULE_CLASS] 182 # Module:Class or IntegrationName:Class 183 return [_REFERENCE_TYPE.CACHE, 184 _REFERENCE_TYPE.INTEGRATION, 185 _REFERENCE_TYPE.MODULE_CLASS] 186 if '.' in ref: 187 # The string of ref_end possibly includes specific mathods, e.g. 188 # foo.java#method, so let ref_end be the first part of splitting '#'. 189 if "#" in ref_end: 190 ref_end = ref_end.split('#')[0] 191 if ref_end in ('java', 'kt', 'bp', 'mk', 'cc', 'cpp'): 192 return [_REFERENCE_TYPE.CACHE, _REFERENCE_TYPE.MODULE_FILE_PATH] 193 if ref_end == 'xml': 194 return [_REFERENCE_TYPE.CACHE, 195 _REFERENCE_TYPE.INTEGRATION_FILE_PATH, 196 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH] 197 if ref_end_is_upper: 198 return [_REFERENCE_TYPE.CACHE, _REFERENCE_TYPE.QUALIFIED_CLASS] 199 return [_REFERENCE_TYPE.CACHE, 200 _REFERENCE_TYPE.MODULE, 201 _REFERENCE_TYPE.PACKAGE] 202 # Note: We assume that if you're referencing a file in your cwd, 203 # that file must have a '.' in its name, i.e. foo.java, foo.xml. 204 # If this ever becomes not the case, then we need to include path below. 205 return [_REFERENCE_TYPE.CACHE, 206 _REFERENCE_TYPE.INTEGRATION, 207 # TODO: Uncomment in SUITE when it's supported 208 # _REFERENCE_TYPE.SUITE, 209 _REFERENCE_TYPE.MODULE, 210 _REFERENCE_TYPE.CONFIG, 211 _REFERENCE_TYPE.SUITE_PLAN, 212 _REFERENCE_TYPE.CLASS, 213 _REFERENCE_TYPE.CC_CLASS] 214 215 216def _get_registered_find_methods(module_info): 217 """Return list of registered find methods. 218 219 This is used to return find methods that were not listed in the 220 default find methods but just registered in the finder classes. These 221 find methods will run before the default find methods. 222 223 Args: 224 module_info: ModuleInfo for finder classes to instantiate with. 225 226 Returns: 227 List of registered find methods. 228 """ 229 find_methods = [] 230 finder_instance_dict = _get_finder_instance_dict(module_info) 231 for finder in _get_test_finders(): 232 finder_instance = finder_instance_dict[finder.NAME] 233 for find_method_info in finder_instance.get_all_find_methods(): 234 find_methods.append(test_finder_base.Finder( 235 finder_instance, find_method_info.find_method, finder.NAME)) 236 return find_methods 237 238 239def _get_default_find_methods(module_info, test): 240 """Default find methods to be used based on the given test name. 241 242 Args: 243 module_info: ModuleInfo for finder instances to use. 244 test: String of test name to help determine which find methods 245 to utilize. 246 247 Returns: 248 List of find methods to use. 249 """ 250 find_methods = [] 251 finder_instance_dict = _get_finder_instance_dict(module_info) 252 test_ref_types = _get_test_reference_types(test) 253 logging.debug('Resolved input to possible references: %s', [ 254 _REFERENCE_TYPE[t] for t in test_ref_types]) 255 for test_ref_type in test_ref_types: 256 find_method = _REF_TYPE_TO_FUNC_MAP[test_ref_type] 257 finder_instance = finder_instance_dict[inspect._findclass(find_method).NAME] 258 finder_info = _REFERENCE_TYPE[test_ref_type] 259 find_methods.append(test_finder_base.Finder(finder_instance, 260 find_method, 261 finder_info)) 262 return find_methods 263 264 265def get_find_methods_for_test(module_info, test): 266 """Return a list of ordered find methods. 267 268 Args: 269 test: String of test name to get find methods for. 270 271 Returns: 272 List of ordered find methods. 273 """ 274 registered_find_methods = _get_registered_find_methods(module_info) 275 default_find_methods = _get_default_find_methods(module_info, test) 276 return registered_find_methods + default_find_methods 277