Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 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 | """ |
| 16 | Test Finder Handler module. |
| 17 | """ |
| 18 | |
mikehoran | 8bf6d08 | 2018-02-26 16:22:06 -0800 | [diff] [blame^] | 19 | import logging |
| 20 | |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 21 | import atest_enum |
| 22 | from test_finders import test_finder_base |
| 23 | from test_finders import tf_integration_finder |
| 24 | from 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, |
mikehoran | 6740a41 | 2018-02-20 15:04:16 -0800 | [diff] [blame] | 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, |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 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 | |
| 65 | def _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 | |
| 80 | def _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 | |
mikehoran | 6740a41 | 2018-02-20 15:04:16 -0800 | [diff] [blame] | 98 | # pylint: disable=too-many-return-statements |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 99 | def _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, |
Kevin Cheng | dd8fba1 | 2018-02-20 10:17:33 -0800 | [diff] [blame] | 125 | # TODO: Comment in SUITE when it's supported |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 126 | # _REFERENCE_TYPE.SUITE |
| 127 | ] |
mikehoran | 6740a41 | 2018-02-20 15:04:16 -0800 | [diff] [blame] | 128 | if '.' in ref: |
| 129 | ref_end = ref.rsplit('.', 1)[-1] |
| 130 | ref_end_is_upper = ref_end[0].isupper() |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 131 | if ':' in ref: |
| 132 | if '.' in ref: |
mikehoran | 6740a41 | 2018-02-20 15:04:16 -0800 | [diff] [blame] | 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] |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 142 | if '.' in ref: |
mikehoran | 6740a41 | 2018-02-20 15:04:16 -0800 | [diff] [blame] | 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] |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 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, |
Kevin Cheng | dd8fba1 | 2018-02-20 10:17:33 -0800 | [diff] [blame] | 154 | # TODO: Comment in SUITE when it's supported |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 155 | # REFERENCE_TYPE.SUITE, |
| 156 | _REFERENCE_TYPE.MODULE, |
| 157 | _REFERENCE_TYPE.CLASS] |
| 158 | |
| 159 | |
| 160 | def _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 | |
| 183 | def _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) |
mikehoran | 8bf6d08 | 2018-02-26 16:22:06 -0800 | [diff] [blame^] | 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: |
Kevin Cheng | dd8fba1 | 2018-02-20 10:17:33 -0800 | [diff] [blame] | 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)) |
Kevin Cheng | 8b2c94c | 2017-12-18 14:43:26 -0800 | [diff] [blame] | 204 | return find_methods |
| 205 | |
| 206 | |
| 207 | def 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 |