• 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
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