xref: /aosp_15_r20/tools/asuite/atest/test_finders/cache_finder.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1*c2e18aaaSAndroid Build Coastguard Worker# Copyright 2019, The Android Open Source Project
2*c2e18aaaSAndroid Build Coastguard Worker#
3*c2e18aaaSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*c2e18aaaSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*c2e18aaaSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*c2e18aaaSAndroid Build Coastguard Worker#
7*c2e18aaaSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*c2e18aaaSAndroid Build Coastguard Worker#
9*c2e18aaaSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*c2e18aaaSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*c2e18aaaSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*c2e18aaaSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*c2e18aaaSAndroid Build Coastguard Worker# limitations under the License.
14*c2e18aaaSAndroid Build Coastguard Worker
15*c2e18aaaSAndroid Build Coastguard Worker"""Cache Finder class."""
16*c2e18aaaSAndroid Build Coastguard Worker
17*c2e18aaaSAndroid Build Coastguard Workerimport logging
18*c2e18aaaSAndroid Build Coastguard Worker
19*c2e18aaaSAndroid Build Coastguard Workerfrom atest import atest_utils
20*c2e18aaaSAndroid Build Coastguard Workerfrom atest import constants
21*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_finders import test_filter_utils
22*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_finders import test_finder_base
23*c2e18aaaSAndroid Build Coastguard Workerfrom atest.test_finders import test_info
24*c2e18aaaSAndroid Build Coastguard Worker
25*c2e18aaaSAndroid Build Coastguard Worker
26*c2e18aaaSAndroid Build Coastguard Workerclass CacheFinder(test_finder_base.TestFinderBase):
27*c2e18aaaSAndroid Build Coastguard Worker  """Cache Finder class."""
28*c2e18aaaSAndroid Build Coastguard Worker
29*c2e18aaaSAndroid Build Coastguard Worker  NAME = 'CACHE'
30*c2e18aaaSAndroid Build Coastguard Worker
31*c2e18aaaSAndroid Build Coastguard Worker  def __init__(self, module_info=None):
32*c2e18aaaSAndroid Build Coastguard Worker    super().__init__()
33*c2e18aaaSAndroid Build Coastguard Worker    self.module_info = module_info
34*c2e18aaaSAndroid Build Coastguard Worker
35*c2e18aaaSAndroid Build Coastguard Worker  def _is_latest_testinfos(self, test_infos):
36*c2e18aaaSAndroid Build Coastguard Worker    """Check whether test_infos are up-to-date.
37*c2e18aaaSAndroid Build Coastguard Worker
38*c2e18aaaSAndroid Build Coastguard Worker    Args:
39*c2e18aaaSAndroid Build Coastguard Worker        test_infos: A list of TestInfo.
40*c2e18aaaSAndroid Build Coastguard Worker
41*c2e18aaaSAndroid Build Coastguard Worker    Returns:
42*c2e18aaaSAndroid Build Coastguard Worker        True if all keys in test_infos and TestInfo object are equal.
43*c2e18aaaSAndroid Build Coastguard Worker        Otherwise, False.
44*c2e18aaaSAndroid Build Coastguard Worker    """
45*c2e18aaaSAndroid Build Coastguard Worker    sorted_base_ti = sorted(vars(test_info.TestInfo(None, None, None)).keys())
46*c2e18aaaSAndroid Build Coastguard Worker    for cached_test_info in test_infos:
47*c2e18aaaSAndroid Build Coastguard Worker      sorted_cache_ti = sorted(vars(cached_test_info).keys())
48*c2e18aaaSAndroid Build Coastguard Worker      if not sorted_cache_ti == sorted_base_ti:
49*c2e18aaaSAndroid Build Coastguard Worker        logging.debug('test_info is not up-to-date.')
50*c2e18aaaSAndroid Build Coastguard Worker        return False
51*c2e18aaaSAndroid Build Coastguard Worker    return True
52*c2e18aaaSAndroid Build Coastguard Worker
53*c2e18aaaSAndroid Build Coastguard Worker  def find_test_by_cache(self, test_reference):
54*c2e18aaaSAndroid Build Coastguard Worker    """Find the matched test_infos in saved caches.
55*c2e18aaaSAndroid Build Coastguard Worker
56*c2e18aaaSAndroid Build Coastguard Worker    Args:
57*c2e18aaaSAndroid Build Coastguard Worker        test_reference: A string of the path to the test's file or dir.
58*c2e18aaaSAndroid Build Coastguard Worker
59*c2e18aaaSAndroid Build Coastguard Worker    Returns:
60*c2e18aaaSAndroid Build Coastguard Worker        A list of TestInfo namedtuple if cache found and is in latest
61*c2e18aaaSAndroid Build Coastguard Worker        TestInfo format, else None.
62*c2e18aaaSAndroid Build Coastguard Worker    """
63*c2e18aaaSAndroid Build Coastguard Worker    test_infos = atest_utils.load_test_info_cache(test_reference)
64*c2e18aaaSAndroid Build Coastguard Worker    if test_infos and self._is_test_infos_valid(test_infos):
65*c2e18aaaSAndroid Build Coastguard Worker      return test_infos
66*c2e18aaaSAndroid Build Coastguard Worker    return None
67*c2e18aaaSAndroid Build Coastguard Worker
68*c2e18aaaSAndroid Build Coastguard Worker  def _is_test_infos_valid(self, test_infos):
69*c2e18aaaSAndroid Build Coastguard Worker    """Check if the given test_infos are valid.
70*c2e18aaaSAndroid Build Coastguard Worker
71*c2e18aaaSAndroid Build Coastguard Worker    Args:
72*c2e18aaaSAndroid Build Coastguard Worker        test_infos: A list of TestInfo.
73*c2e18aaaSAndroid Build Coastguard Worker
74*c2e18aaaSAndroid Build Coastguard Worker    Returns:
75*c2e18aaaSAndroid Build Coastguard Worker        True if test_infos are all valid. Otherwise, False.
76*c2e18aaaSAndroid Build Coastguard Worker    """
77*c2e18aaaSAndroid Build Coastguard Worker    if not self._is_latest_testinfos(test_infos):
78*c2e18aaaSAndroid Build Coastguard Worker      return False
79*c2e18aaaSAndroid Build Coastguard Worker    for t_info in test_infos:
80*c2e18aaaSAndroid Build Coastguard Worker      if t_info.test_runner == 'BazelTestRunner':
81*c2e18aaaSAndroid Build Coastguard Worker        return False
82*c2e18aaaSAndroid Build Coastguard Worker      if not self._is_test_path_valid(t_info):
83*c2e18aaaSAndroid Build Coastguard Worker        return False
84*c2e18aaaSAndroid Build Coastguard Worker      if not self._is_test_build_target_valid(t_info):
85*c2e18aaaSAndroid Build Coastguard Worker        return False
86*c2e18aaaSAndroid Build Coastguard Worker      if not self._is_test_filter_valid(t_info):
87*c2e18aaaSAndroid Build Coastguard Worker        return False
88*c2e18aaaSAndroid Build Coastguard Worker    return True
89*c2e18aaaSAndroid Build Coastguard Worker
90*c2e18aaaSAndroid Build Coastguard Worker  def _is_test_path_valid(self, t_info):
91*c2e18aaaSAndroid Build Coastguard Worker    """Check if test path is valid.
92*c2e18aaaSAndroid Build Coastguard Worker
93*c2e18aaaSAndroid Build Coastguard Worker    Args:
94*c2e18aaaSAndroid Build Coastguard Worker        t_info: TestInfo that has been filled out by a find method.
95*c2e18aaaSAndroid Build Coastguard Worker
96*c2e18aaaSAndroid Build Coastguard Worker    Returns:
97*c2e18aaaSAndroid Build Coastguard Worker        True if test path is valid. Otherwise, False.
98*c2e18aaaSAndroid Build Coastguard Worker    """
99*c2e18aaaSAndroid Build Coastguard Worker    # For RoboTest it won't have 'MODULES-IN-' as build target. Treat test
100*c2e18aaaSAndroid Build Coastguard Worker    # path is valid if cached_test_paths is None.
101*c2e18aaaSAndroid Build Coastguard Worker    cached_test_paths = t_info.get_test_paths()
102*c2e18aaaSAndroid Build Coastguard Worker    if cached_test_paths is None:
103*c2e18aaaSAndroid Build Coastguard Worker      return True
104*c2e18aaaSAndroid Build Coastguard Worker    current_test_paths = self.module_info.get_paths(t_info.test_name)
105*c2e18aaaSAndroid Build Coastguard Worker    if not current_test_paths:
106*c2e18aaaSAndroid Build Coastguard Worker      return False
107*c2e18aaaSAndroid Build Coastguard Worker    formatted_paths = [p.replace('/', '-') for p in current_test_paths]
108*c2e18aaaSAndroid Build Coastguard Worker    if sorted(cached_test_paths) != sorted(formatted_paths):
109*c2e18aaaSAndroid Build Coastguard Worker      logging.debug('Not a valid test path.')
110*c2e18aaaSAndroid Build Coastguard Worker      return False
111*c2e18aaaSAndroid Build Coastguard Worker    return True
112*c2e18aaaSAndroid Build Coastguard Worker
113*c2e18aaaSAndroid Build Coastguard Worker  def _is_test_build_target_valid(self, t_info):
114*c2e18aaaSAndroid Build Coastguard Worker    """Check if test build targets are valid.
115*c2e18aaaSAndroid Build Coastguard Worker
116*c2e18aaaSAndroid Build Coastguard Worker    Args:
117*c2e18aaaSAndroid Build Coastguard Worker        t_info: TestInfo that has been filled out by a find method.
118*c2e18aaaSAndroid Build Coastguard Worker
119*c2e18aaaSAndroid Build Coastguard Worker    Returns:
120*c2e18aaaSAndroid Build Coastguard Worker        True if test's build target is valid. Otherwise, False.
121*c2e18aaaSAndroid Build Coastguard Worker    """
122*c2e18aaaSAndroid Build Coastguard Worker    # If the cached build target can be found in current module-info, then
123*c2e18aaaSAndroid Build Coastguard Worker    # it is a valid build targets of the test.
124*c2e18aaaSAndroid Build Coastguard Worker    for build_target in t_info.build_targets:
125*c2e18aaaSAndroid Build Coastguard Worker      if str(build_target).startswith(constants.MODULES_IN):
126*c2e18aaaSAndroid Build Coastguard Worker        continue
127*c2e18aaaSAndroid Build Coastguard Worker      if not self.module_info.is_module(build_target):
128*c2e18aaaSAndroid Build Coastguard Worker        logging.debug('%s is not a valid build target.', build_target)
129*c2e18aaaSAndroid Build Coastguard Worker        return False
130*c2e18aaaSAndroid Build Coastguard Worker    return True
131*c2e18aaaSAndroid Build Coastguard Worker
132*c2e18aaaSAndroid Build Coastguard Worker  def _is_test_filter_valid(self, t_info):
133*c2e18aaaSAndroid Build Coastguard Worker    """Check if test filter is valid.
134*c2e18aaaSAndroid Build Coastguard Worker
135*c2e18aaaSAndroid Build Coastguard Worker    Args:
136*c2e18aaaSAndroid Build Coastguard Worker        t_info: TestInfo that has been filled out by a find method.
137*c2e18aaaSAndroid Build Coastguard Worker
138*c2e18aaaSAndroid Build Coastguard Worker    Returns:
139*c2e18aaaSAndroid Build Coastguard Worker        True if test filter is valid. Otherwise, False.
140*c2e18aaaSAndroid Build Coastguard Worker    """
141*c2e18aaaSAndroid Build Coastguard Worker    test_filters = t_info.data.get(constants.TI_FILTER, [])
142*c2e18aaaSAndroid Build Coastguard Worker    if not test_filters:
143*c2e18aaaSAndroid Build Coastguard Worker      return True
144*c2e18aaaSAndroid Build Coastguard Worker    for test_filter in test_filters:
145*c2e18aaaSAndroid Build Coastguard Worker      # Check if the class filter is under current module.
146*c2e18aaaSAndroid Build Coastguard Worker      # TODO: (b/172260100) The test_name may not be inevitably equal to
147*c2e18aaaSAndroid Build Coastguard Worker      #  the module_name.
148*c2e18aaaSAndroid Build Coastguard Worker      if not self._is_class_in_module(t_info.test_name, test_filter.class_name):
149*c2e18aaaSAndroid Build Coastguard Worker        logging.debug('Not a valid test filter.')
150*c2e18aaaSAndroid Build Coastguard Worker        return False
151*c2e18aaaSAndroid Build Coastguard Worker    return True
152*c2e18aaaSAndroid Build Coastguard Worker
153*c2e18aaaSAndroid Build Coastguard Worker  def _is_class_in_module(self, module_name, filter_class):
154*c2e18aaaSAndroid Build Coastguard Worker    """Check if input class is part of input module.
155*c2e18aaaSAndroid Build Coastguard Worker
156*c2e18aaaSAndroid Build Coastguard Worker    Args:
157*c2e18aaaSAndroid Build Coastguard Worker        module_name: A string of the module name of the test.
158*c2e18aaaSAndroid Build Coastguard Worker        filter_class: A string of the class name field of TI_FILTER.
159*c2e18aaaSAndroid Build Coastguard Worker
160*c2e18aaaSAndroid Build Coastguard Worker    Returns:
161*c2e18aaaSAndroid Build Coastguard Worker        True if input filter_class is in the input module. Otherwise, False.
162*c2e18aaaSAndroid Build Coastguard Worker    """
163*c2e18aaaSAndroid Build Coastguard Worker    mod_info = self.module_info.get_module_info(module_name)
164*c2e18aaaSAndroid Build Coastguard Worker    if not mod_info:
165*c2e18aaaSAndroid Build Coastguard Worker      return False
166*c2e18aaaSAndroid Build Coastguard Worker    module_srcs = mod_info.get(constants.MODULE_SRCS, [])
167*c2e18aaaSAndroid Build Coastguard Worker    # If module didn't have src information treat the cached filter still
168*c2e18aaaSAndroid Build Coastguard Worker    # valid. Remove this after all java srcs could be found in module-info.
169*c2e18aaaSAndroid Build Coastguard Worker    if not module_srcs:
170*c2e18aaaSAndroid Build Coastguard Worker      return True
171*c2e18aaaSAndroid Build Coastguard Worker
172*c2e18aaaSAndroid Build Coastguard Worker    for src_path in module_srcs:
173*c2e18aaaSAndroid Build Coastguard Worker      abs_src_path = atest_utils.get_build_top(src_path)
174*c2e18aaaSAndroid Build Coastguard Worker      if constants.CC_EXT_RE.match(src_path):
175*c2e18aaaSAndroid Build Coastguard Worker        # TODO: (b/172260100) Also check for CC.
176*c2e18aaaSAndroid Build Coastguard Worker        return True
177*c2e18aaaSAndroid Build Coastguard Worker      else:
178*c2e18aaaSAndroid Build Coastguard Worker        full_class_name = test_filter_utils.get_fully_qualified_class_name(
179*c2e18aaaSAndroid Build Coastguard Worker            abs_src_path
180*c2e18aaaSAndroid Build Coastguard Worker        )
181*c2e18aaaSAndroid Build Coastguard Worker        package_name = test_filter_utils.get_package_name(abs_src_path)
182*c2e18aaaSAndroid Build Coastguard Worker        if filter_class == full_class_name or filter_class == package_name:
183*c2e18aaaSAndroid Build Coastguard Worker          return True
184*c2e18aaaSAndroid Build Coastguard Worker    return False
185