1#!/usr/bin/env python3 2# 3# Copyright (C) 2021 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the 'License'); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an 'AS IS' BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16"""Unit tests for mainline_modules_sdks.py.""" 17import dataclasses 18import re 19import typing 20from pathlib import Path 21import os 22import shutil 23import tempfile 24import unittest 25import zipfile 26import json 27from unittest import mock 28 29import mainline_modules_sdks as mm 30 31MAINLINE_MODULES_BY_APEX = dict( 32 (m.apex, m) for m in (mm.MAINLINE_MODULES + mm.BUNDLED_MAINLINE_MODULES + 33 mm.PLATFORM_SDKS_FOR_MAINLINE)) 34 35 36@dataclasses.dataclass() 37class FakeSnapshotBuilder(mm.SnapshotBuilder): 38 """A fake snapshot builder that does not run the build. 39 40 This skips the whole build process and just creates some fake sdk 41 modules. 42 """ 43 44 snapshots: typing.List[typing.Any] = dataclasses.field(default_factory=list) 45 46 @staticmethod 47 def create_sdk_library_files(z, name): 48 z.writestr(f"sdk_library/public/{name}-removed.txt", "") 49 z.writestr(f"sdk_library/public/{name}.srcjar", "") 50 z.writestr(f"sdk_library/public/{name}-stubs.jar", "") 51 z.writestr(f"sdk_library/public/{name}.txt", 52 "method public int testMethod(int);") 53 54 def create_snapshot_file(self, out_dir, name, for_r_build): 55 zip_file = Path(mm.sdk_snapshot_zip_file(out_dir, name)) 56 with zipfile.ZipFile(zip_file, "w") as z: 57 z.writestr("Android.bp", "") 58 if name.endswith("-sdk"): 59 if for_r_build: 60 for library in for_r_build.sdk_libraries: 61 self.create_sdk_library_files(z, library.name) 62 else: 63 self.create_sdk_library_files(z, re.sub(r"-.*$", "", name)) 64 65 def build_snapshots(self, build_release, modules): 66 self.snapshots.append((build_release.name, build_release.soong_env, 67 [m.apex for m in modules])) 68 # Create input file structure. 69 sdks_out_dir = Path(self.mainline_sdks_dir).joinpath("test") 70 sdks_out_dir.mkdir(parents=True, exist_ok=True) 71 # Create a fake sdk zip file for each module. 72 for module in modules: 73 for sdk in module.sdks: 74 self.create_snapshot_file(sdks_out_dir, sdk, module.for_r_build) 75 return sdks_out_dir 76 77 def get_art_module_info_file_data(self, sdk): 78 info_file_data = f"""[ 79 {{ 80 "@type": "java_sdk_library", 81 "@name": "art.module.public.api", 82 "@deps": [ 83 "libcore_license" 84 ], 85 "dist_stem": "art", 86 "scopes": {{ 87 "public": {{ 88 "current_api": "sdk_library/public/{re.sub(r"-.*$", "", sdk)}.txt", 89 "latest_api": "{Path(self.mainline_sdks_dir).joinpath("test")}/prebuilts/sdk/art.api.public.latest/gen/art.api.public.latest", 90 "latest_removed_api": "{Path(self.mainline_sdks_dir).joinpath("test")}/prebuilts/sdk/art-removed.api.public.latest/gen/art-removed.api.public.latest", 91 "removed_api": "sdk_library/public/{re.sub(r"-.*$", "", sdk)}-removed.txt" 92 }} 93 }} 94 }} 95] 96""" 97 return info_file_data 98 99 @staticmethod 100 def write_data_to_file(file, data): 101 with open(file, "w", encoding="utf8") as fd: 102 fd.write(data) 103 104 def create_snapshot_info_file(self, module, sdk_info_file, sdk): 105 if module == MAINLINE_MODULES_BY_APEX["com.android.art"]: 106 self.write_data_to_file(sdk_info_file, 107 self.get_art_module_info_file_data(sdk)) 108 else: 109 # For rest of the modules, generate an empty .info file. 110 self.write_data_to_file(sdk_info_file, "[]") 111 112 def get_module_extension_version(self): 113 # Return any integer value indicating the module extension version for testing. 114 return 5 115 116 def build_sdk_scope_targets(self, build_release, modules): 117 target_paths = [] 118 target_dict = {} 119 for module in modules: 120 for sdk in module.sdks: 121 if "host-exports" in sdk or "test-exports" in sdk: 122 continue 123 124 sdk_info_file = mm.sdk_snapshot_info_file( 125 Path(self.mainline_sdks_dir).joinpath("test"), sdk) 126 self.create_snapshot_info_file(module, sdk_info_file, sdk) 127 paths, dict_item = self.latest_api_file_targets(sdk_info_file) 128 target_paths.extend(paths) 129 target_dict[sdk_info_file] = dict_item 130 131 for target_path in target_paths: 132 os.makedirs(os.path.split(target_path)[0]) 133 self.write_data_to_file(target_path, "") 134 135 return target_dict 136 137 138class TestProduceDist(unittest.TestCase): 139 140 def setUp(self): 141 self.tmp_dir = tempfile.mkdtemp() 142 self.tmp_out_dir = os.path.join(self.tmp_dir, "out") 143 os.mkdir(self.tmp_out_dir) 144 self.tmp_dist_dir = os.path.join(self.tmp_dir, "dist") 145 os.mkdir(self.tmp_dist_dir) 146 147 def tearDown(self): 148 shutil.rmtree(self.tmp_dir, ignore_errors=True) 149 150 def produce_dist(self, modules, build_releases): 151 subprocess_runner = mm.SubprocessRunner() 152 snapshot_builder = FakeSnapshotBuilder( 153 tool_path="path/to/mainline_modules_sdks.sh", 154 subprocess_runner=subprocess_runner, 155 out_dir=self.tmp_out_dir, 156 ) 157 producer = mm.SdkDistProducer( 158 subprocess_runner=subprocess_runner, 159 snapshot_builder=snapshot_builder, 160 dist_dir=self.tmp_dist_dir, 161 ) 162 producer.produce_dist(modules, build_releases) 163 164 def list_files_in_dir(self, tmp_dist_dir): 165 files = [] 166 for abs_dir, _, filenames in os.walk(tmp_dist_dir): 167 rel_dir = os.path.relpath(abs_dir, tmp_dist_dir) 168 if rel_dir == ".": 169 rel_dir = "" 170 for f in filenames: 171 files.append(os.path.join(rel_dir, f)) 172 return files 173 174 def test_unbundled_modules(self): 175 # Create the out/soong/build_number.txt file that is copied into the 176 # snapshots. 177 self.create_build_number_file() 178 179 modules = [ 180 MAINLINE_MODULES_BY_APEX["com.android.art"], 181 MAINLINE_MODULES_BY_APEX["com.android.ipsec"], 182 MAINLINE_MODULES_BY_APEX["com.android.tethering"], 183 # Create a google specific module. 184 mm.aosp_to_google(MAINLINE_MODULES_BY_APEX["com.android.wifi"]), 185 ] 186 build_releases = [ 187 mm.Q, 188 mm.R, 189 mm.S, 190 mm.LATEST, 191 ] 192 self.produce_dist(modules, build_releases) 193 194 # pylint: disable=line-too-long 195 self.assertEqual( 196 [ 197 # Build specific snapshots. 198 "mainline-sdks/for-R-build/current/com.android.ipsec/sdk/ipsec-module-sdk-current.zip", 199 "mainline-sdks/for-R-build/current/com.android.tethering/sdk/tethering-module-sdk-current.zip", 200 "mainline-sdks/for-R-build/current/com.google.android.wifi/sdk/wifi-module-sdk-current.zip", 201 "mainline-sdks/for-S-build/current/com.android.art/host-exports/art-module-host-exports-current.zip", 202 "mainline-sdks/for-S-build/current/com.android.art/sdk/art-module-sdk-current.zip", 203 "mainline-sdks/for-S-build/current/com.android.art/test-exports/art-module-test-exports-current.zip", 204 "mainline-sdks/for-S-build/current/com.android.ipsec/sdk/ipsec-module-sdk-current.zip", 205 "mainline-sdks/for-S-build/current/com.android.tethering/sdk/tethering-module-sdk-current.zip", 206 "mainline-sdks/for-S-build/current/com.google.android.wifi/sdk/wifi-module-sdk-current.zip", 207 "mainline-sdks/for-latest-build/current/com.android.art/gantry-metadata.json", 208 "mainline-sdks/for-latest-build/current/com.android.art/host-exports/art-module-host-exports-current.zip", 209 "mainline-sdks/for-latest-build/current/com.android.art/sdk/art-module-sdk-current-api-diff.txt", 210 "mainline-sdks/for-latest-build/current/com.android.art/sdk/art-module-sdk-current.zip", 211 "mainline-sdks/for-latest-build/current/com.android.art/test-exports/art-module-test-exports-current.zip", 212 "mainline-sdks/for-latest-build/current/com.android.ipsec/gantry-metadata.json", 213 "mainline-sdks/for-latest-build/current/com.android.ipsec/sdk/ipsec-module-sdk-current-api-diff.txt", 214 "mainline-sdks/for-latest-build/current/com.android.ipsec/sdk/ipsec-module-sdk-current.zip", 215 "mainline-sdks/for-latest-build/current/com.android.tethering/gantry-metadata.json", 216 "mainline-sdks/for-latest-build/current/com.android.tethering/sdk/tethering-module-sdk-current-api-diff.txt", 217 "mainline-sdks/for-latest-build/current/com.android.tethering/sdk/tethering-module-sdk-current.zip", 218 "mainline-sdks/for-latest-build/current/com.google.android.wifi/gantry-metadata.json", 219 "mainline-sdks/for-latest-build/current/com.google.android.wifi/sdk/wifi-module-sdk-current-api-diff.txt", 220 "mainline-sdks/for-latest-build/current/com.google.android.wifi/sdk/wifi-module-sdk-current.zip", 221 ], 222 sorted(self.list_files_in_dir(self.tmp_dist_dir))) 223 224 r_snaphot_dir = os.path.join(self.tmp_out_dir, 225 "soong/mainline-sdks/test/for-R-build") 226 aosp_ipsec_r_bp_file = "com.android.ipsec/sdk_library/Android.bp" 227 aosp_tethering_r_bp_file = "com.android.tethering/sdk_library/Android.bp" 228 google_wifi_android_bp = "com.google.android.wifi/sdk_library/Android.bp" 229 self.assertEqual([ 230 aosp_ipsec_r_bp_file, 231 "com.android.ipsec/sdk_library/public/android.net.ipsec.ike-removed.txt", 232 "com.android.ipsec/sdk_library/public/android.net.ipsec.ike-stubs.jar", 233 "com.android.ipsec/sdk_library/public/android.net.ipsec.ike.srcjar", 234 "com.android.ipsec/sdk_library/public/android.net.ipsec.ike.txt", 235 "com.android.ipsec/snapshot-creation-build-number.txt", 236 aosp_tethering_r_bp_file, 237 "com.android.tethering/sdk_library/public/framework-tethering-removed.txt", 238 "com.android.tethering/sdk_library/public/framework-tethering-stubs.jar", 239 "com.android.tethering/sdk_library/public/framework-tethering.srcjar", 240 "com.android.tethering/sdk_library/public/framework-tethering.txt", 241 "com.android.tethering/snapshot-creation-build-number.txt", 242 google_wifi_android_bp, 243 "com.google.android.wifi/sdk_library/public/framework-wifi-removed.txt", 244 "com.google.android.wifi/sdk_library/public/framework-wifi-stubs.jar", 245 "com.google.android.wifi/sdk_library/public/framework-wifi.srcjar", 246 "com.google.android.wifi/sdk_library/public/framework-wifi.txt", 247 "com.google.android.wifi/snapshot-creation-build-number.txt", 248 "ipsec-module-sdk-current.zip", 249 "tethering-module-sdk-current.zip", 250 "wifi-module-sdk-current.zip", 251 ], sorted(self.list_files_in_dir(r_snaphot_dir))) 252 253 def read_r_snapshot_contents(path): 254 abs_path = os.path.join(r_snaphot_dir, path) 255 with open(abs_path, "r", encoding="utf8") as file: 256 return file.read() 257 258 # Check the contents of the AOSP ipsec module 259 ipsec_contents = read_r_snapshot_contents(aosp_ipsec_r_bp_file) 260 expected = read_test_data("ipsec_for_r_Android.bp") 261 self.assertEqual(expected, ipsec_contents) 262 263 # Check the contents of the AOSP tethering module 264 tethering_contents = read_r_snapshot_contents(aosp_tethering_r_bp_file) 265 expected = read_test_data("tethering_for_r_Android.bp") 266 self.assertEqual(expected, tethering_contents) 267 268 # Check the contents of the Google ipsec module 269 wifi_contents = read_r_snapshot_contents(google_wifi_android_bp) 270 expected = read_test_data("google_wifi_for_r_Android.bp") 271 self.assertEqual(expected, wifi_contents) 272 273 def test_old_release(self): 274 modules = [ 275 MAINLINE_MODULES_BY_APEX["com.android.art"], # An unnbundled module 276 MAINLINE_MODULES_BY_APEX["com.android.runtime"], # A bundled module 277 MAINLINE_MODULES_BY_APEX["platform-mainline"], # Platform SDK 278 ] 279 build_releases = [mm.S] 280 self.produce_dist(modules, build_releases) 281 282 # pylint: disable=line-too-long 283 self.assertEqual([ 284 "mainline-sdks/for-S-build/current/com.android.art/host-exports/art-module-host-exports-current.zip", 285 "mainline-sdks/for-S-build/current/com.android.art/sdk/art-module-sdk-current.zip", 286 "mainline-sdks/for-S-build/current/com.android.art/test-exports/art-module-test-exports-current.zip", 287 ], sorted(self.list_files_in_dir(self.tmp_dist_dir))) 288 289 def test_latest_release(self): 290 modules = [ 291 MAINLINE_MODULES_BY_APEX["com.android.art"], # An unnbundled module 292 MAINLINE_MODULES_BY_APEX["com.android.runtime"], # A bundled module 293 MAINLINE_MODULES_BY_APEX["platform-mainline"], # Platform SDK 294 ] 295 build_releases = [mm.LATEST] 296 self.produce_dist(modules, build_releases) 297 298 # pylint: disable=line-too-long 299 self.assertEqual( 300 [ 301 # Bundled modules and platform SDKs. 302 "bundled-mainline-sdks/com.android.runtime/host-exports/runtime-module-host-exports-current.zip", 303 "bundled-mainline-sdks/com.android.runtime/sdk/runtime-module-sdk-current.zip", 304 "bundled-mainline-sdks/platform-mainline/sdk/platform-mainline-sdk-current.zip", 305 "bundled-mainline-sdks/platform-mainline/test-exports/platform-mainline-test-exports-current.zip", 306 # Unbundled (normal) modules. 307 "mainline-sdks/for-latest-build/current/com.android.art/gantry-metadata.json", 308 "mainline-sdks/for-latest-build/current/com.android.art/host-exports/art-module-host-exports-current.zip", 309 "mainline-sdks/for-latest-build/current/com.android.art/sdk/art-module-sdk-current-api-diff.txt", 310 "mainline-sdks/for-latest-build/current/com.android.art/sdk/art-module-sdk-current.zip", 311 "mainline-sdks/for-latest-build/current/com.android.art/test-exports/art-module-test-exports-current.zip", 312 ], 313 sorted(self.list_files_in_dir(self.tmp_dist_dir))) 314 315 art_api_diff_file = os.path.join( 316 self.tmp_dist_dir, 317 "mainline-sdks/for-latest-build/current/com.android.art/sdk/art-module-sdk-current-api-diff.txt" 318 ) 319 self.assertNotEqual( 320 os.path.getsize(art_api_diff_file), 321 0, 322 msg="Api diff file should not be empty for the art module") 323 324 art_gantry_metadata_json_file = os.path.join( 325 self.tmp_dist_dir, 326 "mainline-sdks/for-latest-build/current/com.android.art/gantry-metadata.json" 327 ) 328 329 with open(art_gantry_metadata_json_file, "r", 330 encoding="utf8") as gantry_metadata_json_file_object: 331 json_data = json.load(gantry_metadata_json_file_object) 332 333 self.assertEqual( 334 json_data["api_diff_file"], 335 "art-module-sdk-current-api-diff.txt", 336 msg="Incorrect api-diff file name.") 337 self.assertEqual( 338 json_data["api_diff_file_size"], 339 267, 340 msg="Incorrect api-diff file size.") 341 self.assertEqual( 342 json_data["module_extension_version"], 343 5, 344 msg="The module extension version does not match the expected value." 345 ) 346 347 def create_build_number_file(self): 348 soong_dir = os.path.join(self.tmp_out_dir, "soong") 349 os.makedirs(soong_dir, exist_ok=True) 350 build_number_file = os.path.join(soong_dir, "build_number.txt") 351 with open(build_number_file, "w", encoding="utf8") as f: 352 f.write("build-number") 353 354 def test_snapshot_build_order(self): 355 # Create the out/soong/build_number.txt file that is copied into the 356 # snapshots. 357 self.create_build_number_file() 358 359 subprocess_runner = unittest.mock.Mock(mm.SubprocessRunner) 360 snapshot_builder = FakeSnapshotBuilder( 361 tool_path="path/to/mainline_modules_sdks.sh", 362 subprocess_runner=subprocess_runner, 363 out_dir=self.tmp_out_dir, 364 ) 365 producer = mm.SdkDistProducer( 366 subprocess_runner=subprocess_runner, 367 snapshot_builder=snapshot_builder, 368 dist_dir=self.tmp_dist_dir, 369 ) 370 371 modules = [ 372 MAINLINE_MODULES_BY_APEX["com.android.art"], 373 MAINLINE_MODULES_BY_APEX["com.android.ipsec"], 374 # Create a google specific module. 375 mm.aosp_to_google(MAINLINE_MODULES_BY_APEX["com.android.wifi"]), 376 ] 377 build_releases = [ 378 mm.Q, 379 mm.R, 380 mm.S, 381 mm.LATEST, 382 ] 383 384 producer.produce_dist(modules, build_releases) 385 386 # Check the order in which the snapshots are built. 387 self.assertEqual([ 388 ( 389 "R", 390 {}, 391 ["com.android.ipsec", "com.google.android.wifi"], 392 ), 393 ( 394 "latest", 395 {}, 396 [ 397 "com.android.art", "com.android.ipsec", 398 "com.google.android.wifi" 399 ], 400 ), 401 ( 402 "S", 403 { 404 "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE": "S" 405 }, 406 [ 407 "com.android.art", "com.android.ipsec", 408 "com.google.android.wifi" 409 ], 410 ), 411 ], snapshot_builder.snapshots) 412 413 414def path_to_test_data(relative_path): 415 """Construct a path to a test data file. 416 417 The relative_path is relative to the location of this file. 418 """ 419 this_file = __file__ 420 # When running as a python_test_host (name=<x>) with an embedded launcher 421 # the __file__ points to .../<x>/<x>.py but the .../<x> is not a directory 422 # it is a binary with the launcher and the python file embedded inside. In 423 # that case a test data file <rel> is at .../<x>_data/<rel>, not 424 # .../<x>/<x>_data/<rel> so it is necessary to trim the base name (<x>.py) 425 # from the file. 426 if not os.path.isfile(this_file): 427 this_file = os.path.dirname(this_file) 428 # When the python file is at .../<x>.py (or in the case of an embedded 429 # launcher at .../<x>/<x>.py) then the test data is at .../<x>_data/<rel>. 430 this_file_without_ext, _ = os.path.splitext(this_file) 431 return os.path.join(this_file_without_ext + "_data", relative_path) 432 433 434def read_test_data(relative_path): 435 with open(path_to_test_data(relative_path), "r", encoding="utf8") as f: 436 return f.read() 437 438 439class TestAndroidBpTransformations(unittest.TestCase): 440 441 def apply_transformations(self, src, transformations, build_release, expected): 442 producer = mm.SdkDistProducer( 443 subprocess_runner=mock.Mock(mm.SubprocessRunner), 444 snapshot_builder=mock.Mock(mm.SnapshotBuilder), 445 script=self._testMethodName, 446 ) 447 448 with tempfile.TemporaryDirectory() as tmp_dir: 449 path = os.path.join(tmp_dir, "Android.bp") 450 with open(path, "w", encoding="utf8") as f: 451 f.write(src) 452 453 mm.apply_transformations( 454 producer, tmp_dir, transformations, build_release) 455 456 with open(path, "r", encoding="utf8") as f: 457 result = f.read() 458 459 self.maxDiff = None 460 self.assertEqual(expected, result) 461 462 def test_common_mainline_module(self): 463 """Tests the transformations applied to a common mainline sdk on S. 464 465 This uses ipsec as an example of a common mainline sdk. This checks 466 that the general Soong config module types and variables are used. 467 """ 468 src = read_test_data("ipsec_Android.bp.input") 469 470 expected = read_test_data("ipsec_Android.bp.expected") 471 472 module = MAINLINE_MODULES_BY_APEX["com.android.ipsec"] 473 transformations = module.transformations(mm.S, mm.Sdk) 474 475 self.apply_transformations(src, transformations, mm.S, expected) 476 477 def test_common_mainline_module_tiramisu(self): 478 """Tests the transformations applied to a common mainline sdk on T. 479 480 This uses ipsec as an example of a common mainline sdk. This checks 481 that the use_source_config_var property is inserted. 482 """ 483 src = read_test_data("ipsec_Android.bp.input") 484 485 expected = read_test_data("ipsec_tiramisu_Android.bp.expected") 486 487 module = MAINLINE_MODULES_BY_APEX["com.android.ipsec"] 488 transformations = module.transformations(mm.Tiramisu, mm.Sdk) 489 490 self.apply_transformations(src, transformations, mm.Tiramisu, expected) 491 492 def test_optional_mainline_module(self): 493 """Tests the transformations applied to an optional mainline sdk on S. 494 495 This uses wifi as an example of a optional mainline sdk. This checks 496 that the module specific Soong config module types and variables are 497 used. 498 """ 499 src = read_test_data("wifi_Android.bp.input") 500 501 expected = read_test_data("wifi_Android.bp.expected") 502 503 module = MAINLINE_MODULES_BY_APEX["com.android.wifi"] 504 transformations = module.transformations(mm.S, mm.Sdk) 505 506 self.apply_transformations(src, transformations, mm.S, expected) 507 508 def test_optional_mainline_module_tiramisu(self): 509 """Tests the transformations applied to an optional mainline sdk on T. 510 511 This uses wifi as an example of a optional mainline sdk. This checks 512 that the use_source_config_var property is inserted. 513 """ 514 src = read_test_data("wifi_Android.bp.input") 515 516 expected = read_test_data("wifi_tiramisu_Android.bp.expected") 517 518 module = MAINLINE_MODULES_BY_APEX["com.android.wifi"] 519 transformations = module.transformations(mm.Tiramisu, mm.Sdk) 520 521 self.apply_transformations(src, transformations, mm.Tiramisu, expected) 522 523 def test_art(self): 524 """Tests the transformations applied to a the ART mainline module. 525 526 The ART mainline module uses a different Soong config setup to the 527 common mainline modules. This checks that the ART specific Soong config 528 module types, and variables are used. 529 """ 530 src = read_test_data("art_Android.bp.input") 531 532 expected = read_test_data("art_Android.bp.expected") 533 534 module = MAINLINE_MODULES_BY_APEX["com.android.art"] 535 transformations = module.transformations(mm.S, mm.Sdk) 536 537 self.apply_transformations(src, transformations, mm.S, expected) 538 539 def test_art_module_exports(self): 540 """Tests the transformations applied to a the ART mainline module. 541 542 The ART mainline module uses a different Soong config setup to the 543 common mainline modules. This checks that the ART specific Soong config 544 module types, and variables are used. 545 """ 546 src = read_test_data("art_Android.bp.input") 547 548 expected = read_test_data("art_host_exports_Android.bp.expected") 549 550 module = MAINLINE_MODULES_BY_APEX["com.android.art"] 551 transformations = module.transformations(mm.S, mm.HostExports) 552 553 self.apply_transformations(src, transformations, mm.S, expected) 554 555 def test_r_build(self): 556 """Tests the transformations that are applied for the R build. 557 558 This uses ipsec as an example of a common mainline module. That would 559 usually apply the mm.SoongConfigBoilerplateInserter transformation but 560 because this is being run for build R that transformation should not be 561 applied. 562 """ 563 src = read_test_data("ipsec_for_r_Android.bp") 564 565 # There should be no changes made. 566 expected = src 567 568 module = MAINLINE_MODULES_BY_APEX["com.android.ipsec"] 569 transformations = module.transformations(mm.R, mm.Sdk) 570 571 self.apply_transformations(src, transformations, mm.R, expected) 572 573 def test_additional_transformation(self): 574 """Tests additional transformation. 575 576 This uses ipsec as an example of a common case for adding information 577 in Android.bp file. 578 This checks will append the information in Android.bp for a regular module. 579 """ 580 581 @dataclasses.dataclass(frozen=True) 582 class TestTransformation(mm.FileTransformation): 583 """Transforms an Android.bp file by appending testing message.""" 584 585 test_content: str = "" 586 587 def apply(self, producer, path, build_release): 588 with open(path, "a+", encoding="utf8") as file: 589 self._apply_transformation(producer, file, build_release) 590 591 def _apply_transformation(self, producer, file, build_release): 592 if build_release >= mm.Tiramisu: 593 file.write(self.test_content) 594 595 src = read_test_data("ipsec_Android.bp.input") 596 597 expected = read_test_data( 598 "ipsec_tiramisu_Android.bp.additional.expected") 599 test_transformation = TestTransformation( 600 "Android.bp", test_content="\n// Adding by test") 601 module = MAINLINE_MODULES_BY_APEX["com.android.ipsec"] 602 module = dataclasses.replace( 603 module, apex=module.apex, 604 first_release=module.first_release, 605 additional_transformations=[test_transformation]) 606 transformations = module.transformations(mm.Tiramisu, mm.Sdk) 607 self.apply_transformations(src, transformations, mm.Tiramisu, expected) 608 609 610class TestFilterModules(unittest.TestCase): 611 612 def test_no_filter(self): 613 all_modules = mm.MAINLINE_MODULES + mm.BUNDLED_MAINLINE_MODULES 614 modules = mm.filter_modules(all_modules, None) 615 self.assertEqual(modules, all_modules) 616 617 def test_with_filter(self): 618 modules = mm.filter_modules(mm.MAINLINE_MODULES, "com.android.art") 619 expected = MAINLINE_MODULES_BY_APEX["com.android.art"] 620 self.assertEqual(modules, [expected]) 621 622 623class TestModuleProperties(unittest.TestCase): 624 625 def test_unbundled(self): 626 for module in mm.MAINLINE_MODULES: 627 with self.subTest(module=module): 628 self.assertFalse(module.is_bundled()) 629 630 def test_bundled(self): 631 for module in (mm.BUNDLED_MAINLINE_MODULES + 632 mm.PLATFORM_SDKS_FOR_MAINLINE): 633 with self.subTest(module=module): 634 self.assertTrue(module.is_bundled()) 635 self.assertEqual(module.first_release, mm.LATEST) 636 637 638if __name__ == "__main__": 639 unittest.main(verbosity=2) 640