xref: /aosp_15_r20/tools/asuite/atest/module_info_unittest_base.py (revision c2e18aaa1096c836b086f94603d04f4eb9cf37f5)
1# Copyright 2024, 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"""Class that facilitates testing with ModuleInfo objects.
16
17Contains methods to create module objects representing various types
18of tests that can be run in Atest, as well as the corresponding ModuleInfo
19object, for use in unit tests.
20"""
21
22import pathlib
23import tempfile
24
25from atest import atest_utils
26from atest import constants
27from atest import module_info
28from atest.test_finders import test_info
29from atest.test_finders.test_info import TestInfo
30from atest.test_runners import atest_tf_test_runner
31from pyfakefs import fake_filesystem_unittest
32
33
34class ModuleInfoTest(fake_filesystem_unittest.TestCase):
35  """Fixture for tests that require interacting with module-info."""
36
37  def setUp(self):
38    self.setUpPyfakefs()
39    self.product_out_path = pathlib.Path('/src/out/product')
40    self.product_out_path.mkdir(parents=True)
41
42  def create_empty_module_info(self):
43    """Creates an empty ModuleInfo object."""
44    fake_temp_file = self.product_out_path.joinpath(
45        next(tempfile._get_candidate_names())
46    )
47    self.fs.create_file(fake_temp_file, contents='{}')
48    return module_info.load_from_file(module_file=fake_temp_file)
49
50  def create_module_info(self, modules: list[dict] = None):
51    """Creates a ModuleInfo object from the given list of modules."""
52    mod_info = self.create_empty_module_info()
53    modules = modules or []
54
55    for m in modules:
56      mod_info.name_to_module_info[m[constants.MODULE_INFO_ID]] = m
57
58    for m in modules:
59      for path in m[constants.MODULE_PATH]:
60        if not mod_info.path_to_module_info.get(path, []):
61          mod_info.path_to_module_info[path] = [m]
62        else:
63          mod_info.path_to_module_info[path].append(m)
64
65    return mod_info
66
67  def assertContainsSubset(self, expected_subset, actual_set):
68    """Checks whether actual iterable is a superset of expected iterable."""
69    missing = set(expected_subset) - set(actual_set)
70    if not missing:
71      return
72
73    self.fail(
74        f'Missing elements {missing}\n'
75        f'Expected: {expected_subset}\n'
76        f'Actual: {actual_set}'
77    )
78
79
80def host_jar_module(name, installed):
81
82  return module(
83      name=name,
84      supported_variants=['HOST'],
85      installed=installed,
86      auto_test_config=[],
87      compatibility_suites=[],
88  )
89
90
91def device_driven_test_module(
92    name,
93    installed=None,
94    compatibility_suites=None,
95    host_deps=None,
96    class_type=None,
97    is_unit_test=None,
98    module_path=None,
99    srcs=None,
100    test_configs=None,
101):
102
103  name = name or 'hello_world_test'
104  module_path = module_path or 'example_module/project'
105
106  return test_module(
107      name=name,
108      supported_variants=['DEVICE'],
109      compatibility_suites=compatibility_suites,
110      installed=installed or [f'out/product/vsoc_x86/{name}/{name}.apk'],
111      host_deps=host_deps,
112      class_type=class_type or ['APP'],
113      module_path=module_path,
114      is_unit_test=is_unit_test,
115      srcs=srcs,
116      test_configs=test_configs,
117  )
118
119
120def device_driven_multi_config_test_module(
121    name,
122    installed=None,
123    compatibility_suites=None,
124    host_deps=None,
125    class_type=None,
126    module_path=None,
127    srcs=None,
128):
129
130  module_path = module_path or 'example_module/project'
131  return test_module(
132      name=name,
133      supported_variants=['DEVICE'],
134      compatibility_suites=compatibility_suites,
135      installed=installed or [f'out/product/vsoc_x86/{name}/{name}.apk'],
136      auto_test_config=[False],
137      test_configs=[
138          f'{module_path}/configs/Config1.xml',
139          f'{module_path}/configs/Config2.xml',
140      ],
141      host_deps=host_deps,
142      class_type=class_type or ['APP'],
143      module_path=module_path,
144      srcs=srcs,
145  )
146
147
148def robolectric_test_module(name):
149  name = name or 'hello_world_test'
150  return test_module(
151      name=name,
152      supported_variants=['DEVICE'],
153      installed=[f'out/host/linux-x86/{name}/{name}.jar'],
154      compatibility_suites=['robolectric-tests'],
155  )
156
157
158def host_driven_device_test_module(name, libs=None):
159  name = name or 'hello_world_test'
160  return test_module(
161      name=name,
162      supported_variants=['HOST'],
163      installed=[f'out/host/linux-x86/{name}/{name}.jar'],
164      compatibility_suites=['null-suite'],
165      libs=libs,
166  )
167
168
169def multi_variant_unit_test_module(name):
170
171  name = name or 'hello_world_test'
172
173  return test_module(
174      name=name,
175      supported_variants=['HOST', 'DEVICE'],
176      installed=[
177          f'out/host/linux-x86/{name}/{name}.cc',
178          f'out/product/vsoc_x86/{name}/{name}.cc',
179      ],
180      compatibility_suites=['host-unit-tests'],
181      is_unit_test='true',
182  )
183
184
185def test_module(
186    name,
187    supported_variants,
188    installed,
189    auto_test_config=[True],
190    test_configs=[None],
191    compatibility_suites=None,
192    libs=None,
193    host_deps=None,
194    class_type=None,
195    module_path=None,
196    is_unit_test=None,
197    srcs=None,
198):
199  """Creates a module object which with properties specific to a test module."""
200  return module(
201      name=name,
202      supported_variants=supported_variants,
203      installed=installed,
204      auto_test_config=auto_test_config,
205      test_configs=test_configs,
206      compatibility_suites=compatibility_suites or ['null-suite'],
207      libs=libs,
208      host_deps=host_deps,
209      class_type=class_type,
210      module_path=[module_path],
211      is_unit_test=is_unit_test,
212      srcs=srcs,
213  )
214
215
216def module(
217    name,
218    supported_variants,
219    installed,
220    auto_test_config=None,
221    test_configs=None,
222    compatibility_suites=None,
223    libs=None,
224    host_deps=None,
225    class_type=None,
226    module_path=None,
227    is_unit_test=None,
228    srcs=None,
229):
230  """Creates a ModuleInfo object.
231
232  This substitutes its creation from a module-info file for test purposes.
233  """
234
235  m = {}
236
237  m[constants.MODULE_INFO_ID] = name
238  m[constants.MODULE_NAME] = name
239  m[constants.MODULE_SUPPORTED_VARIANTS] = supported_variants
240  m[constants.MODULE_INSTALLED] = installed
241  m[constants.MODULE_AUTO_TEST_CONFIG] = auto_test_config or []
242  m[constants.MODULE_TEST_CONFIG] = test_configs or []
243  m[constants.MODULE_COMPATIBILITY_SUITES] = compatibility_suites or []
244  m[constants.MODULE_LIBS] = libs or []
245  m[constants.MODULE_HOST_DEPS] = host_deps or []
246  m[constants.MODULE_CLASS] = class_type or []
247  m[constants.MODULE_PATH] = module_path or []
248  m[constants.MODULE_IS_UNIT_TEST] = is_unit_test or 'false'
249  m[constants.MODULE_SRCS] = srcs or []
250
251  return m
252