# 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. """ Suite Plan Finder class. """ import logging import os import re import constants from test_finders import test_finder_base from test_finders import test_finder_utils from test_finders import test_info from test_runners import suite_plan_test_runner _SUITE_PLAN_NAME_RE = re.compile(r'^.*\/(?P.*)-tradefed\/res\/config\/' r'(?P.*).xml$') class SuitePlanFinder(test_finder_base.TestFinderBase): """Suite Plan Finder class.""" NAME = 'SUITE_PLAN' _SUITE_PLAN_TEST_RUNNER = suite_plan_test_runner.SuitePlanTestRunner.NAME def __init__(self, module_info=None): super().__init__() self.root_dir = os.environ.get(constants.ANDROID_BUILD_TOP) self.mod_info = module_info self.suite_plan_dirs = self._get_suite_plan_dirs() def _get_mod_paths(self, module_name): """Return the paths of the given module name.""" if self.mod_info: return self.mod_info.get_paths(module_name) return [] def _get_suite_plan_dirs(self): """Get suite plan dirs from MODULE_INFO based on targets. Strategy: Search module-info.json using SUITE_PLANS to get all the suite plan dirs. Returns: A tuple of lists of strings of suite plan dir rel to repo root. None if the path can not be found in module-info.json. """ return [d for x in constants.SUITE_PLANS for d in self._get_mod_paths(x+'-tradefed') if d is not None] def _get_test_info_from_path(self, path, suite_name=None): """Get the test info from the result of using regular expression matching with the give path. Args: path: A string of the test's absolute or relative path. suite_name: A string of the suite name. Returns: A populated TestInfo namedtuple if regular expression matches, else None. """ # Don't use names that simply match the path, # must be the actual name used by *TS to run the test. match = _SUITE_PLAN_NAME_RE.match(path) if not match: logging.debug('Suite plan test outside config dir: %s', path) return None suite = match.group('suite') suite_plan_name = match.group('suite_plan_name') if suite_name: if suite_plan_name != suite_name: logging.debug('Input (%s) not valid suite plan name, ' 'did you mean: %s?', suite_name, suite_plan_name) return None return test_info.TestInfo( test_name=suite_plan_name, test_runner=self._SUITE_PLAN_TEST_RUNNER, build_targets=set([suite]), suite=suite) def find_test_by_suite_path(self, suite_path): """Find the first test info matching the given path. Strategy: If suite_path is to file --> Return TestInfo if the file exists in the suite plan dirs, else return None. If suite_path is to dir --> Return None Args: suite_path: A string of the path to the test's file or dir. Returns: A list of populated TestInfo namedtuple if test found, else None. This is a list with at most 1 element. """ path, _ = test_finder_utils.split_methods(suite_path) # Make sure we're looking for a config. if not path.endswith('.xml'): return None path = os.path.realpath(path) suite_plan_dir = test_finder_utils.get_int_dir_from_path( path, self.suite_plan_dirs) if suite_plan_dir: rel_config = os.path.relpath(path, self.root_dir) return [self._get_test_info_from_path(rel_config)] return None def find_test_by_suite_name(self, suite_name): """Find the test for the given suite name. Strategy: If suite_name is cts --> Return TestInfo to indicate suite runner to make cts and run test using cts-tradefed. If suite_name is cts-common --> Return TestInfo to indicate suite runner to make cts and run test using cts-tradefed if file exists in the suite plan dirs, else return None. Args: suite_name: A string of suite name. Returns: A list of populated TestInfo namedtuple if suite_name matches a suite in constants.SUITE_PLAN, else check if the file existing in the suite plan dirs, else return None. """ logging.debug('Finding test by suite: %s', suite_name) test_infos = [] if suite_name in constants.SUITE_PLANS: test_infos.append(test_info.TestInfo( test_name=suite_name, test_runner=self._SUITE_PLAN_TEST_RUNNER, build_targets=set([suite_name]), suite=suite_name)) else: test_files = test_finder_utils.search_integration_dirs( suite_name, self.suite_plan_dirs) if not test_files: return None for test_file in test_files: _test_info = self._get_test_info_from_path(test_file, suite_name) if _test_info: test_infos.append(_test_info) return test_infos