blob: 53ee79fa2817feb6ad8c80409f05f4077bfe7a1e [file] [log] [blame]
Kevin Cheng8b2c94c2017-12-18 14:43:26 -08001# 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
mikehoran8bf6d082018-02-26 16:22:06 -080019import logging
20
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080021import atest_enum
22from test_finders import test_finder_base
easoncylee5f5cf032018-06-26 16:17:08 +080023from test_finders import suite_plan_finder
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080024from test_finders import tf_integration_finder
25from test_finders import module_finder
26
27# List of default test finder classes.
28_TEST_FINDERS = {
easoncylee5f5cf032018-06-26 16:17:08 +080029 suite_plan_finder.SuitePlanFinder,
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080030 tf_integration_finder.TFIntegrationFinder,
31 module_finder.ModuleFinder,
32}
33
34# Explanation of REFERENCE_TYPEs:
35# ----------------------------------
36# 0. MODULE: LOCAL_MODULE or LOCAL_PACKAGE_NAME value in Android.mk/Android.bp.
37# 1. MODULE_CLASS: Combo of MODULE and CLASS as "module:class".
38# 2. PACKAGE: package in java file. Same as file path to java file.
39# 3. MODULE_PACKAGE: Combo of MODULE and PACKAGE as "module:package".
40# 4. MODULE_FILE_PATH: File path to dir of tests or test itself.
41# 5. INTEGRATION_FILE_PATH: File path to config xml in one of the 4 integration
42# config directories.
43# 6. INTEGRATION: xml file name in one of the 4 integration config directories.
44# 7. SUITE: Value of the "run-suite-tag" in xml config file in 4 config dirs.
45# Same as value of "test-suite-tag" in AndroidTest.xml files.
kellyhungf4b59472018-05-10 17:00:10 +080046# 8. CC_CLASS: Test case in cc file.
easoncylee5f5cf032018-06-26 16:17:08 +080047# 9. SUITE_PLAN: Suite name such as cts.
48# 10. SUITE_PLAN_FILE_PATH: File path to config xml in the suite config directories.
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080049_REFERENCE_TYPE = atest_enum.AtestEnum(['MODULE', 'CLASS', 'QUALIFIED_CLASS',
50 'MODULE_CLASS', 'PACKAGE',
51 'MODULE_PACKAGE', 'MODULE_FILE_PATH',
52 'INTEGRATION_FILE_PATH', 'INTEGRATION',
easoncylee5f5cf032018-06-26 16:17:08 +080053 'SUITE', 'CC_CLASS', 'SUITE_PLAN',
54 'SUITE_PLAN_FILE_PATH'])
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080055
56_REF_TYPE_TO_FUNC_MAP = {
57 _REFERENCE_TYPE.MODULE: module_finder.ModuleFinder.find_test_by_module_name,
58 _REFERENCE_TYPE.CLASS: module_finder.ModuleFinder.find_test_by_class_name,
59 _REFERENCE_TYPE.MODULE_CLASS: module_finder.ModuleFinder.find_test_by_module_and_class,
60 _REFERENCE_TYPE.QUALIFIED_CLASS: module_finder.ModuleFinder.find_test_by_class_name,
mikehoran6740a412018-02-20 15:04:16 -080061 _REFERENCE_TYPE.PACKAGE: module_finder.ModuleFinder.find_test_by_package_name,
62 _REFERENCE_TYPE.MODULE_PACKAGE: module_finder.ModuleFinder.find_test_by_module_and_package,
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080063 _REFERENCE_TYPE.MODULE_FILE_PATH: module_finder.ModuleFinder.find_test_by_path,
64 _REFERENCE_TYPE.INTEGRATION_FILE_PATH:
65 tf_integration_finder.TFIntegrationFinder.find_int_test_by_path,
66 _REFERENCE_TYPE.INTEGRATION:
67 tf_integration_finder.TFIntegrationFinder.find_test_by_integration_name,
kellyhungf4b59472018-05-10 17:00:10 +080068 _REFERENCE_TYPE.CC_CLASS:
69 module_finder.ModuleFinder.find_test_by_cc_class_name,
easoncylee5f5cf032018-06-26 16:17:08 +080070 _REFERENCE_TYPE.SUITE_PLAN:suite_plan_finder.SuitePlanFinder.find_test_by_suite_name,
71 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH:
72 suite_plan_finder.SuitePlanFinder.find_test_by_suite_path,
Kevin Cheng8b2c94c2017-12-18 14:43:26 -080073}
74
75
76def _get_finder_instance_dict(module_info):
77 """Return dict of finder instances.
78
79 Args:
80 module_info: ModuleInfo for finder classes to use.
81
82 Returns:
83 Dict of finder instances keyed by their name.
84 """
85 instance_dict = {}
86 for finder in _get_test_finders():
87 instance_dict[finder.NAME] = finder(module_info=module_info)
88 return instance_dict
89
90
91def _get_test_finders():
92 """Returns the test finders.
93
94 If external test types are defined outside atest, they can be try-except
95 imported into here.
96
97 Returns:
98 Set of test finder classes.
99 """
100 test_finders_list = _TEST_FINDERS
101 # Example import of external test finder:
102 try:
103 from test_finders import example_finder
104 test_finders_list.add(example_finder.ExampleFinder)
105 except ImportError:
106 pass
107 return test_finders_list
108
mikehoran6740a412018-02-20 15:04:16 -0800109# pylint: disable=too-many-return-statements
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800110def _get_test_reference_types(ref):
111 """Determine type of test reference based on the content of string.
112
113 Examples:
114 The string 'SequentialRWTest' could be a reference to
115 a Module or a Class name.
116
117 The string 'cts/tests/filesystem' could be a Path, Integration
118 or Suite reference.
119
120 Args:
121 ref: A string referencing a test.
122
123 Returns:
124 A list of possible REFERENCE_TYPEs (ints) for reference string.
125 """
126 if ref.startswith('.') or '..' in ref:
127 return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
easoncylee5f5cf032018-06-26 16:17:08 +0800128 _REFERENCE_TYPE.MODULE_FILE_PATH,
129 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800130 if '/' in ref:
131 if ref.startswith('/'):
132 return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
easoncylee5f5cf032018-06-26 16:17:08 +0800133 _REFERENCE_TYPE.MODULE_FILE_PATH,
134 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800135 return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
136 _REFERENCE_TYPE.MODULE_FILE_PATH,
137 _REFERENCE_TYPE.INTEGRATION,
easoncylee5f5cf032018-06-26 16:17:08 +0800138 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH,
Kevin Chengdd8fba12018-02-20 10:17:33 -0800139 # TODO: Comment in SUITE when it's supported
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800140 # _REFERENCE_TYPE.SUITE
141 ]
mikehoran6740a412018-02-20 15:04:16 -0800142 if '.' in ref:
143 ref_end = ref.rsplit('.', 1)[-1]
144 ref_end_is_upper = ref_end[0].isupper()
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800145 if ':' in ref:
146 if '.' in ref:
mikehoran6740a412018-02-20 15:04:16 -0800147 if ref_end_is_upper:
148 # Module:fully.qualified.Class or Integration:fully.q.Class
149 return [_REFERENCE_TYPE.INTEGRATION,
150 _REFERENCE_TYPE.MODULE_CLASS]
151 # Module:some.package
152 return [_REFERENCE_TYPE.MODULE_PACKAGE]
153 # Module:Class or IntegrationName:Class
154 return [_REFERENCE_TYPE.INTEGRATION,
155 _REFERENCE_TYPE.MODULE_CLASS]
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800156 if '.' in ref:
kellyhungf4b59472018-05-10 17:00:10 +0800157 # The string of ref_end possibly includes specific mathods, e.g.
158 # foo.java#method, so let ref_end be the first part of splitting '#'.
159 if "#" in ref_end:
160 ref_end = ref_end.split('#')[0]
yelinhsiehe4580a52018-08-16 15:51:54 +0800161 if ref_end in ('java', 'kt', 'bp', 'mk', 'cc', 'cpp'):
mikehoran6740a412018-02-20 15:04:16 -0800162 return [_REFERENCE_TYPE.MODULE_FILE_PATH]
163 if ref_end == 'xml':
easoncylee5f5cf032018-06-26 16:17:08 +0800164 return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
165 _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
mikehoran6740a412018-02-20 15:04:16 -0800166 if ref_end_is_upper:
167 return [_REFERENCE_TYPE.QUALIFIED_CLASS]
Jim Tangc8dadcd2019-04-22 11:53:42 +0800168 return [_REFERENCE_TYPE.MODULE,
169 _REFERENCE_TYPE.PACKAGE]
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800170 # Note: We assume that if you're referencing a file in your cwd,
171 # that file must have a '.' in its name, i.e. foo.java, foo.xml.
172 # If this ever becomes not the case, then we need to include path below.
easoncylee5f5cf032018-06-26 16:17:08 +0800173 return [_REFERENCE_TYPE.INTEGRATION,
Kevin Chengdd8fba12018-02-20 10:17:33 -0800174 # TODO: Comment in SUITE when it's supported
easoncylee2dd42a92018-04-26 15:49:56 +0800175 # _REFERENCE_TYPE.SUITE,
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800176 _REFERENCE_TYPE.MODULE,
easoncylee5f5cf032018-06-26 16:17:08 +0800177 _REFERENCE_TYPE.SUITE_PLAN,
kellyhungf4b59472018-05-10 17:00:10 +0800178 _REFERENCE_TYPE.CLASS,
179 _REFERENCE_TYPE.CC_CLASS]
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800180
181
182def _get_registered_find_methods(module_info):
183 """Return list of registered find methods.
184
185 This is used to return find methods that were not listed in the
186 default find methods but just registered in the finder classes. These
187 find methods will run before the default find methods.
188
189 Args:
190 module_info: ModuleInfo for finder classes to instantiate with.
191
192 Returns:
193 List of registered find methods.
194 """
195 find_methods = []
196 finder_instance_dict = _get_finder_instance_dict(module_info)
197 for finder in _get_test_finders():
198 finder_instance = finder_instance_dict[finder.NAME]
199 for find_method_info in finder_instance.get_all_find_methods():
200 find_methods.append(test_finder_base.Finder(
nelsonli34997d52018-08-17 09:43:28 +0800201 finder_instance, find_method_info.find_method, finder.NAME))
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800202 return find_methods
203
204
205def _get_default_find_methods(module_info, test):
206 """Default find methods to be used based on the given test name.
207
208 Args:
209 module_info: ModuleInfo for finder instances to use.
210 test: String of test name to help determine which find methods
211 to utilize.
212
213 Returns:
214 List of find methods to use.
215 """
216 find_methods = []
217 finder_instance_dict = _get_finder_instance_dict(module_info)
mikehoran8bf6d082018-02-26 16:22:06 -0800218 test_ref_types = _get_test_reference_types(test)
219 logging.debug('Resolved input to possible references: %s', [
220 _REFERENCE_TYPE[t] for t in test_ref_types])
221 for test_ref_type in test_ref_types:
Kevin Chengdd8fba12018-02-20 10:17:33 -0800222 find_method = _REF_TYPE_TO_FUNC_MAP[test_ref_type]
223 finder_instance = finder_instance_dict[find_method.im_class.NAME]
nelsonli34997d52018-08-17 09:43:28 +0800224 finder_info = _REFERENCE_TYPE[test_ref_type]
Kevin Chengdd8fba12018-02-20 10:17:33 -0800225 find_methods.append(test_finder_base.Finder(finder_instance,
nelsonli34997d52018-08-17 09:43:28 +0800226 find_method,
227 finder_info))
Kevin Cheng8b2c94c2017-12-18 14:43:26 -0800228 return find_methods
229
230
231def get_find_methods_for_test(module_info, test):
232 """Return a list of ordered find methods.
233
234 Args:
235 test: String of test name to get find methods for.
236
237 Returns:
238 List of ordered find methods.
239 """
240 registered_find_methods = _get_registered_find_methods(module_info)
241 default_find_methods = _get_default_find_methods(module_info, test)
242 return registered_find_methods + default_find_methods