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