• 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 test_finder_base
23from test_finders import suite_plan_finder
24from test_finders import tf_integration_finder
25from test_finders import module_finder
26
27# List of default test finder classes.
28_TEST_FINDERS = {
29    suite_plan_finder.SuitePlanFinder,
30    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.
46# 8. CC_CLASS: Test case in cc file.
47# 9. SUITE_PLAN: Suite name such as cts.
48# 10. SUITE_PLAN_FILE_PATH: File path to config xml in the suite config directories.
49_REFERENCE_TYPE = atest_enum.AtestEnum(['MODULE', 'CLASS', 'QUALIFIED_CLASS',
50                                        'MODULE_CLASS', 'PACKAGE',
51                                        'MODULE_PACKAGE', 'MODULE_FILE_PATH',
52                                        'INTEGRATION_FILE_PATH', 'INTEGRATION',
53                                        'SUITE', 'CC_CLASS', 'SUITE_PLAN',
54                                        'SUITE_PLAN_FILE_PATH'])
55
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,
61    _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,
63    _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,
68    _REFERENCE_TYPE.CC_CLASS:
69        module_finder.ModuleFinder.find_test_by_cc_class_name,
70    _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,
73}
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
109# pylint: disable=too-many-return-statements
110def _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,
128                _REFERENCE_TYPE.MODULE_FILE_PATH,
129                _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
130    if '/' in ref:
131        if ref.startswith('/'):
132            return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
133                    _REFERENCE_TYPE.MODULE_FILE_PATH,
134                    _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
135        return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
136                _REFERENCE_TYPE.MODULE_FILE_PATH,
137                _REFERENCE_TYPE.INTEGRATION,
138                _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH,
139                # TODO: Comment in SUITE when it's supported
140                # _REFERENCE_TYPE.SUITE
141               ]
142    if '.' in ref:
143        ref_end = ref.rsplit('.', 1)[-1]
144        ref_end_is_upper = ref_end[0].isupper()
145    if ':' in ref:
146        if '.' in ref:
147            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]
156    if '.' in ref:
157        # 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]
161        if ref_end in ('java', 'kt', 'bp', 'mk', 'cc', 'cpp'):
162            return [_REFERENCE_TYPE.MODULE_FILE_PATH]
163        if ref_end == 'xml':
164            return [_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
165                    _REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
166        if ref_end_is_upper:
167            return [_REFERENCE_TYPE.QUALIFIED_CLASS]
168        return [_REFERENCE_TYPE.MODULE,
169                _REFERENCE_TYPE.PACKAGE]
170    # 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.
173    return [_REFERENCE_TYPE.INTEGRATION,
174            # TODO: Comment in SUITE when it's supported
175            # _REFERENCE_TYPE.SUITE,
176            _REFERENCE_TYPE.MODULE,
177            _REFERENCE_TYPE.SUITE_PLAN,
178            _REFERENCE_TYPE.CLASS,
179            _REFERENCE_TYPE.CC_CLASS]
180
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(
201                finder_instance, find_method_info.find_method, finder.NAME))
202    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)
218    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:
222        find_method = _REF_TYPE_TO_FUNC_MAP[test_ref_type]
223        finder_instance = finder_instance_dict[find_method.im_class.NAME]
224        finder_info = _REFERENCE_TYPE[test_ref_type]
225        find_methods.append(test_finder_base.Finder(finder_instance,
226                                                    find_method,
227                                                    finder_info))
228    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
243