You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
10 KiB
258 lines
10 KiB
# Copyright 2018, The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
"""
|
|
Test Finder Handler module.
|
|
"""
|
|
|
|
import logging
|
|
|
|
import atest_enum
|
|
from test_finders import cache_finder
|
|
from test_finders import test_finder_base
|
|
from test_finders import suite_plan_finder
|
|
from test_finders import tf_integration_finder
|
|
from test_finders import module_finder
|
|
|
|
# List of default test finder classes.
|
|
_TEST_FINDERS = {
|
|
suite_plan_finder.SuitePlanFinder,
|
|
tf_integration_finder.TFIntegrationFinder,
|
|
module_finder.ModuleFinder,
|
|
cache_finder.CacheFinder,
|
|
}
|
|
|
|
# Explanation of REFERENCE_TYPEs:
|
|
# ----------------------------------
|
|
# 0. MODULE: LOCAL_MODULE or LOCAL_PACKAGE_NAME value in Android.mk/Android.bp.
|
|
# 1. CLASS: Names which the same with a ClassName.java/kt file.
|
|
# 2. QUALIFIED_CLASS: String like "a.b.c.ClassName".
|
|
# 3. MODULE_CLASS: Combo of MODULE and CLASS as "module:class".
|
|
# 4. PACKAGE: Package in java file. Same as file path to java file.
|
|
# 5. MODULE_PACKAGE: Combo of MODULE and PACKAGE as "module:package".
|
|
# 6. MODULE_FILE_PATH: File path to dir of tests or test itself.
|
|
# 7. INTEGRATION_FILE_PATH: File path to config xml in one of the 4 integration
|
|
# config directories.
|
|
# 8. INTEGRATION: xml file name in one of the 4 integration config directories.
|
|
# 9. SUITE: Value of the "run-suite-tag" in xml config file in 4 config dirs.
|
|
# Same as value of "test-suite-tag" in AndroidTest.xml files.
|
|
# 10. CC_CLASS: Test case in cc file.
|
|
# 11. SUITE_PLAN: Suite name such as cts.
|
|
# 12. SUITE_PLAN_FILE_PATH: File path to config xml in the suite config directories.
|
|
# 13. CACHE: A pseudo type that runs cache_finder without finding test in real.
|
|
_REFERENCE_TYPE = atest_enum.AtestEnum(['MODULE', 'CLASS', 'QUALIFIED_CLASS',
|
|
'MODULE_CLASS', 'PACKAGE',
|
|
'MODULE_PACKAGE', 'MODULE_FILE_PATH',
|
|
'INTEGRATION_FILE_PATH', 'INTEGRATION',
|
|
'SUITE', 'CC_CLASS', 'SUITE_PLAN',
|
|
'SUITE_PLAN_FILE_PATH', 'CACHE'])
|
|
|
|
_REF_TYPE_TO_FUNC_MAP = {
|
|
_REFERENCE_TYPE.MODULE: module_finder.ModuleFinder.find_test_by_module_name,
|
|
_REFERENCE_TYPE.CLASS: module_finder.ModuleFinder.find_test_by_class_name,
|
|
_REFERENCE_TYPE.MODULE_CLASS: module_finder.ModuleFinder.find_test_by_module_and_class,
|
|
_REFERENCE_TYPE.QUALIFIED_CLASS: module_finder.ModuleFinder.find_test_by_class_name,
|
|
_REFERENCE_TYPE.PACKAGE: module_finder.ModuleFinder.find_test_by_package_name,
|
|
_REFERENCE_TYPE.MODULE_PACKAGE: module_finder.ModuleFinder.find_test_by_module_and_package,
|
|
_REFERENCE_TYPE.MODULE_FILE_PATH: module_finder.ModuleFinder.find_test_by_path,
|
|
_REFERENCE_TYPE.INTEGRATION_FILE_PATH:
|
|
tf_integration_finder.TFIntegrationFinder.find_int_test_by_path,
|
|
_REFERENCE_TYPE.INTEGRATION:
|
|
tf_integration_finder.TFIntegrationFinder.find_test_by_integration_name,
|
|
_REFERENCE_TYPE.CC_CLASS:
|
|
module_finder.ModuleFinder.find_test_by_cc_class_name,
|
|
_REFERENCE_TYPE.SUITE_PLAN:suite_plan_finder.SuitePlanFinder.find_test_by_suite_name,
|
|
_REFERENCE_TYPE.SUITE_PLAN_FILE_PATH:
|
|
suite_plan_finder.SuitePlanFinder.find_test_by_suite_path,
|
|
_REFERENCE_TYPE.CACHE: cache_finder.CacheFinder.find_test_by_cache,
|
|
}
|
|
|
|
|
|
def _get_finder_instance_dict(module_info):
|
|
"""Return dict of finder instances.
|
|
|
|
Args:
|
|
module_info: ModuleInfo for finder classes to use.
|
|
|
|
Returns:
|
|
Dict of finder instances keyed by their name.
|
|
"""
|
|
instance_dict = {}
|
|
for finder in _get_test_finders():
|
|
instance_dict[finder.NAME] = finder(module_info=module_info)
|
|
return instance_dict
|
|
|
|
|
|
def _get_test_finders():
|
|
"""Returns the test finders.
|
|
|
|
If external test types are defined outside atest, they can be try-except
|
|
imported into here.
|
|
|
|
Returns:
|
|
Set of test finder classes.
|
|
"""
|
|
test_finders_list = _TEST_FINDERS
|
|
# Example import of external test finder:
|
|
try:
|
|
from test_finders import example_finder
|
|
test_finders_list.add(example_finder.ExampleFinder)
|
|
except ImportError:
|
|
pass
|
|
return test_finders_list
|
|
|
|
# pylint: disable=too-many-return-statements
|
|
def _get_test_reference_types(ref):
|
|
"""Determine type of test reference based on the content of string.
|
|
|
|
Examples:
|
|
The string 'SequentialRWTest' could be a reference to
|
|
a Module or a Class name.
|
|
|
|
The string 'cts/tests/filesystem' could be a Path, Integration
|
|
or Suite reference.
|
|
|
|
Args:
|
|
ref: A string referencing a test.
|
|
|
|
Returns:
|
|
A list of possible REFERENCE_TYPEs (ints) for reference string.
|
|
"""
|
|
if ref.startswith('.') or '..' in ref:
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
|
|
_REFERENCE_TYPE.MODULE_FILE_PATH,
|
|
_REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
|
|
if '/' in ref:
|
|
if ref.startswith('/'):
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
|
|
_REFERENCE_TYPE.MODULE_FILE_PATH,
|
|
_REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
|
|
_REFERENCE_TYPE.MODULE_FILE_PATH,
|
|
_REFERENCE_TYPE.INTEGRATION,
|
|
_REFERENCE_TYPE.SUITE_PLAN_FILE_PATH,
|
|
# TODO: Uncomment in SUITE when it's supported
|
|
# _REFERENCE_TYPE.SUITE
|
|
]
|
|
if '.' in ref:
|
|
ref_end = ref.rsplit('.', 1)[-1]
|
|
ref_end_is_upper = ref_end[0].isupper()
|
|
if ':' in ref:
|
|
if '.' in ref:
|
|
if ref_end_is_upper:
|
|
# Module:fully.qualified.Class or Integration:fully.q.Class
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION,
|
|
_REFERENCE_TYPE.MODULE_CLASS]
|
|
# Module:some.package
|
|
return [_REFERENCE_TYPE.CACHE, _REFERENCE_TYPE.MODULE_PACKAGE,
|
|
_REFERENCE_TYPE.MODULE_CLASS]
|
|
# Module:Class or IntegrationName:Class
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION,
|
|
_REFERENCE_TYPE.MODULE_CLASS]
|
|
if '.' in ref:
|
|
# The string of ref_end possibly includes specific mathods, e.g.
|
|
# foo.java#method, so let ref_end be the first part of splitting '#'.
|
|
if "#" in ref_end:
|
|
ref_end = ref_end.split('#')[0]
|
|
if ref_end in ('java', 'kt', 'bp', 'mk', 'cc', 'cpp'):
|
|
return [_REFERENCE_TYPE.CACHE, _REFERENCE_TYPE.MODULE_FILE_PATH]
|
|
if ref_end == 'xml':
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION_FILE_PATH,
|
|
_REFERENCE_TYPE.SUITE_PLAN_FILE_PATH]
|
|
if ref_end_is_upper:
|
|
return [_REFERENCE_TYPE.CACHE, _REFERENCE_TYPE.QUALIFIED_CLASS]
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.MODULE,
|
|
_REFERENCE_TYPE.PACKAGE]
|
|
# Note: We assume that if you're referencing a file in your cwd,
|
|
# that file must have a '.' in its name, i.e. foo.java, foo.xml.
|
|
# If this ever becomes not the case, then we need to include path below.
|
|
return [_REFERENCE_TYPE.CACHE,
|
|
_REFERENCE_TYPE.INTEGRATION,
|
|
# TODO: Uncomment in SUITE when it's supported
|
|
# _REFERENCE_TYPE.SUITE,
|
|
_REFERENCE_TYPE.MODULE,
|
|
_REFERENCE_TYPE.SUITE_PLAN,
|
|
_REFERENCE_TYPE.CLASS,
|
|
_REFERENCE_TYPE.CC_CLASS]
|
|
|
|
|
|
def _get_registered_find_methods(module_info):
|
|
"""Return list of registered find methods.
|
|
|
|
This is used to return find methods that were not listed in the
|
|
default find methods but just registered in the finder classes. These
|
|
find methods will run before the default find methods.
|
|
|
|
Args:
|
|
module_info: ModuleInfo for finder classes to instantiate with.
|
|
|
|
Returns:
|
|
List of registered find methods.
|
|
"""
|
|
find_methods = []
|
|
finder_instance_dict = _get_finder_instance_dict(module_info)
|
|
for finder in _get_test_finders():
|
|
finder_instance = finder_instance_dict[finder.NAME]
|
|
for find_method_info in finder_instance.get_all_find_methods():
|
|
find_methods.append(test_finder_base.Finder(
|
|
finder_instance, find_method_info.find_method, finder.NAME))
|
|
return find_methods
|
|
|
|
|
|
def _get_default_find_methods(module_info, test):
|
|
"""Default find methods to be used based on the given test name.
|
|
|
|
Args:
|
|
module_info: ModuleInfo for finder instances to use.
|
|
test: String of test name to help determine which find methods
|
|
to utilize.
|
|
|
|
Returns:
|
|
List of find methods to use.
|
|
"""
|
|
find_methods = []
|
|
finder_instance_dict = _get_finder_instance_dict(module_info)
|
|
test_ref_types = _get_test_reference_types(test)
|
|
logging.debug('Resolved input to possible references: %s', [
|
|
_REFERENCE_TYPE[t] for t in test_ref_types])
|
|
for test_ref_type in test_ref_types:
|
|
find_method = _REF_TYPE_TO_FUNC_MAP[test_ref_type]
|
|
finder_instance = finder_instance_dict[find_method.im_class.NAME]
|
|
finder_info = _REFERENCE_TYPE[test_ref_type]
|
|
find_methods.append(test_finder_base.Finder(finder_instance,
|
|
find_method,
|
|
finder_info))
|
|
return find_methods
|
|
|
|
|
|
def get_find_methods_for_test(module_info, test):
|
|
"""Return a list of ordered find methods.
|
|
|
|
Args:
|
|
test: String of test name to get find methods for.
|
|
|
|
Returns:
|
|
List of ordered find methods.
|
|
"""
|
|
registered_find_methods = _get_registered_find_methods(module_info)
|
|
default_find_methods = _get_default_find_methods(module_info, test)
|
|
return registered_find_methods + default_find_methods
|