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