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