Home | History | Annotate | Download | only in atest
      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 
     19 import logging
     20 
     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,
     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,
     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 
     98 # pylint: disable=too-many-return-statements
     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,
    125                 # TODO: Comment in SUITE when it's supported
    126                 # _REFERENCE_TYPE.SUITE
    127                ]
    128     if '.' in ref:
    129         ref_end = ref.rsplit('.', 1)[-1]
    130         ref_end_is_upper = ref_end[0].isupper()
    131     if ':' in ref:
    132         if '.' in ref:
    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]
    142     if '.' in ref:
    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]
    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,
    154             # TODO: Comment in SUITE when it's supported
    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)
    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:
    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))
    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
    219