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