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