1// Copyright 2018 Google Inc. All rights reserved. 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 15package etc 16 17import ( 18 "fmt" 19 "os" 20 "path/filepath" 21 "testing" 22 23 "github.com/google/blueprint/proptools" 24 25 "android/soong/android" 26 "android/soong/snapshot" 27) 28 29func TestMain(m *testing.M) { 30 os.Exit(m.Run()) 31} 32 33var prepareForPrebuiltEtcTest = android.GroupFixturePreparers( 34 android.PrepareForTestWithArchMutator, 35 PrepareForTestWithPrebuiltEtc, 36 android.FixtureMergeMockFs(android.MockFS{ 37 "foo.conf": nil, 38 "bar.conf": nil, 39 "baz.conf": nil, 40 }), 41) 42 43var prepareForPrebuiltEtcSnapshotTest = android.GroupFixturePreparers( 44 prepareForPrebuiltEtcTest, 45 android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { 46 snapshot.VendorSnapshotImageSingleton.Init(ctx) 47 snapshot.RecoverySnapshotImageSingleton.Init(ctx) 48 }), 49 android.FixtureModifyConfig(func(config android.Config) { 50 config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current") 51 config.TestProductVariables.RecoverySnapshotVersion = proptools.StringPtr("current") 52 }), 53) 54 55func TestPrebuiltEtcVariants(t *testing.T) { 56 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 57 prebuilt_etc { 58 name: "foo.conf", 59 src: "foo.conf", 60 } 61 prebuilt_etc { 62 name: "bar.conf", 63 src: "bar.conf", 64 recovery_available: true, 65 } 66 prebuilt_etc { 67 name: "baz.conf", 68 src: "baz.conf", 69 recovery: true, 70 } 71 `) 72 73 foo_variants := result.ModuleVariantsForTests("foo.conf") 74 if len(foo_variants) != 1 { 75 t.Errorf("expected 1, got %#v", foo_variants) 76 } 77 78 bar_variants := result.ModuleVariantsForTests("bar.conf") 79 if len(bar_variants) != 2 { 80 t.Errorf("expected 2, got %#v", bar_variants) 81 } 82 83 baz_variants := result.ModuleVariantsForTests("baz.conf") 84 if len(baz_variants) != 1 { 85 t.Errorf("expected 1, got %#v", bar_variants) 86 } 87} 88 89func TestPrebuiltEtcOutputPath(t *testing.T) { 90 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 91 prebuilt_etc { 92 name: "foo.conf", 93 src: "foo.conf", 94 filename: "foo.installed.conf", 95 } 96 `) 97 98 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 99 android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePath.Base()) 100} 101 102func TestPrebuiltEtcGlob(t *testing.T) { 103 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 104 prebuilt_etc { 105 name: "my_foo", 106 src: "foo.*", 107 } 108 prebuilt_etc { 109 name: "my_bar", 110 src: "bar.*", 111 filename_from_src: true, 112 } 113 `) 114 115 p := result.Module("my_foo", "android_arm64_armv8-a").(*PrebuiltEtc) 116 android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePath.Base()) 117 118 p = result.Module("my_bar", "android_arm64_armv8-a").(*PrebuiltEtc) 119 android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePath.Base()) 120} 121 122func TestPrebuiltEtcAndroidMk(t *testing.T) { 123 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 124 prebuilt_etc { 125 name: "foo", 126 src: "foo.conf", 127 owner: "abc", 128 filename_from_src: true, 129 required: ["modA", "moduleB"], 130 host_required: ["hostModA", "hostModB"], 131 target_required: ["targetModA"], 132 } 133 `) 134 135 expected := map[string][]string{ 136 "LOCAL_MODULE": {"foo"}, 137 "LOCAL_MODULE_CLASS": {"ETC"}, 138 "LOCAL_MODULE_OWNER": {"abc"}, 139 "LOCAL_INSTALLED_MODULE_STEM": {"foo.conf"}, 140 "LOCAL_REQUIRED_MODULES": {"modA", "moduleB"}, 141 "LOCAL_HOST_REQUIRED_MODULES": {"hostModA", "hostModB"}, 142 "LOCAL_TARGET_REQUIRED_MODULES": {"targetModA"}, 143 "LOCAL_SOONG_MODULE_TYPE": {"prebuilt_etc"}, 144 } 145 146 mod := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc) 147 entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] 148 for k, expectedValue := range expected { 149 if value, ok := entries.EntryMap[k]; ok { 150 android.AssertDeepEquals(t, k, expectedValue, value) 151 } else { 152 t.Errorf("No %s defined, saw %q", k, entries.EntryMap) 153 } 154 } 155} 156 157func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) { 158 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 159 prebuilt_etc { 160 name: "foo.conf", 161 src: "foo.conf", 162 relative_install_path: "bar", 163 } 164 `) 165 166 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 167 expected := "out/soong/target/product/test_device/system/etc/bar" 168 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 169} 170 171func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) { 172 prepareForPrebuiltEtcTest. 173 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("relative_install_path is set. Cannot set sub_dir")). 174 RunTestWithBp(t, ` 175 prebuilt_etc { 176 name: "foo.conf", 177 src: "foo.conf", 178 sub_dir: "bar", 179 relative_install_path: "bar", 180 } 181 `) 182} 183 184func TestPrebuiltEtcHost(t *testing.T) { 185 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 186 prebuilt_etc_host { 187 name: "foo.conf", 188 src: "foo.conf", 189 } 190 `) 191 192 buildOS := result.Config.BuildOS.String() 193 p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) 194 if !p.Host() { 195 t.Errorf("host bit is not set for a prebuilt_etc_host module.") 196 } 197} 198 199func TestPrebuiltEtcAllowMissingDependencies(t *testing.T) { 200 result := android.GroupFixturePreparers( 201 prepareForPrebuiltEtcTest, 202 android.PrepareForTestDisallowNonExistentPaths, 203 android.FixtureModifyConfig( 204 func(config android.Config) { 205 config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) 206 }), 207 ).RunTestWithBp(t, ` 208 prebuilt_etc { 209 name: "foo.conf", 210 filename_from_src: true, 211 arch: { 212 x86: { 213 src: "x86.conf", 214 }, 215 }, 216 } 217 `) 218 219 android.AssertStringEquals(t, "expected error rule", "android/soong/android.Error", 220 result.ModuleForTests("foo.conf", "android_arm64_armv8-a").Output("foo.conf").Rule.String()) 221} 222 223func TestPrebuiltRootInstallDirPath(t *testing.T) { 224 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 225 prebuilt_root { 226 name: "foo.conf", 227 src: "foo.conf", 228 filename: "foo.conf", 229 } 230 `) 231 232 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 233 expected := "out/soong/target/product/test_device/system" 234 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 235} 236 237func TestPrebuiltRootInstallDirPathValidate(t *testing.T) { 238 prepareForPrebuiltEtcTest.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("filename cannot contain separator")).RunTestWithBp(t, ` 239 prebuilt_root { 240 name: "foo.conf", 241 src: "foo.conf", 242 filename: "foo/bar.conf", 243 } 244 `) 245} 246 247func TestPrebuiltUserShareInstallDirPath(t *testing.T) { 248 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 249 prebuilt_usr_share { 250 name: "foo.conf", 251 src: "foo.conf", 252 sub_dir: "bar", 253 } 254 `) 255 256 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 257 expected := "out/soong/target/product/test_device/system/usr/share/bar" 258 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 259} 260 261func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { 262 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 263 prebuilt_usr_share_host { 264 name: "foo.conf", 265 src: "foo.conf", 266 sub_dir: "bar", 267 } 268 `) 269 270 buildOS := result.Config.BuildOS.String() 271 p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) 272 expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "usr", "share", "bar") 273 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 274} 275 276func TestPrebuiltFontInstallDirPath(t *testing.T) { 277 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 278 prebuilt_font { 279 name: "foo.conf", 280 src: "foo.conf", 281 } 282 `) 283 284 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 285 expected := "out/soong/target/product/test_device/system/fonts" 286 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 287} 288 289func TestPrebuiltFirmwareDirPath(t *testing.T) { 290 targetPath := "out/soong/target/product/test_device" 291 tests := []struct { 292 description string 293 config string 294 expectedPath string 295 }{{ 296 description: "prebuilt: system firmware", 297 config: ` 298 prebuilt_firmware { 299 name: "foo.conf", 300 src: "foo.conf", 301 }`, 302 expectedPath: filepath.Join(targetPath, "system/etc/firmware"), 303 }, { 304 description: "prebuilt: vendor firmware", 305 config: ` 306 prebuilt_firmware { 307 name: "foo.conf", 308 src: "foo.conf", 309 soc_specific: true, 310 sub_dir: "sub_dir", 311 }`, 312 expectedPath: filepath.Join(targetPath, "vendor/firmware/sub_dir"), 313 }} 314 for _, tt := range tests { 315 t.Run(tt.description, func(t *testing.T) { 316 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config) 317 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 318 android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath) 319 }) 320 } 321} 322 323func TestPrebuiltDSPDirPath(t *testing.T) { 324 targetPath := "out/soong/target/product/test_device" 325 tests := []struct { 326 description string 327 config string 328 expectedPath string 329 }{{ 330 description: "prebuilt: system dsp", 331 config: ` 332 prebuilt_dsp { 333 name: "foo.conf", 334 src: "foo.conf", 335 }`, 336 expectedPath: filepath.Join(targetPath, "system/etc/dsp"), 337 }, { 338 description: "prebuilt: vendor dsp", 339 config: ` 340 prebuilt_dsp { 341 name: "foo.conf", 342 src: "foo.conf", 343 soc_specific: true, 344 sub_dir: "sub_dir", 345 }`, 346 expectedPath: filepath.Join(targetPath, "vendor/dsp/sub_dir"), 347 }} 348 for _, tt := range tests { 349 t.Run(tt.description, func(t *testing.T) { 350 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config) 351 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 352 android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath) 353 }) 354 } 355} 356 357func TestPrebuiltRFSADirPath(t *testing.T) { 358 targetPath := "out/soong/target/product/test_device" 359 tests := []struct { 360 description string 361 config string 362 expectedPath string 363 }{{ 364 description: "prebuilt: system rfsa", 365 config: ` 366 prebuilt_rfsa { 367 name: "foo.conf", 368 src: "foo.conf", 369 }`, 370 expectedPath: filepath.Join(targetPath, "system/lib/rfsa"), 371 }, { 372 description: "prebuilt: vendor rfsa", 373 config: ` 374 prebuilt_rfsa { 375 name: "foo.conf", 376 src: "foo.conf", 377 soc_specific: true, 378 sub_dir: "sub_dir", 379 }`, 380 expectedPath: filepath.Join(targetPath, "vendor/lib/rfsa/sub_dir"), 381 }} 382 for _, tt := range tests { 383 t.Run(tt.description, func(t *testing.T) { 384 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config) 385 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 386 android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath) 387 }) 388 } 389} 390 391func checkIfSnapshotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) { 392 checkIfSnapshotExistAsExpected(t, result, image, moduleName, true) 393} 394 395func checkIfSnapshotNotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) { 396 checkIfSnapshotExistAsExpected(t, result, image, moduleName, false) 397} 398 399func checkIfSnapshotExistAsExpected(t *testing.T, result *android.TestResult, image string, moduleName string, expectToExist bool) { 400 snapshotSingleton := result.SingletonForTests(image + "-snapshot") 401 archType := "arm64" 402 archVariant := "armv8-a" 403 archDir := fmt.Sprintf("arch-%s", archType) 404 405 snapshotDir := fmt.Sprintf("%s-snapshot", image) 406 snapshotVariantPath := filepath.Join(snapshotDir, archType) 407 outputDir := filepath.Join(snapshotVariantPath, archDir, "etc") 408 imageVariant := "" 409 if image == "recovery" { 410 imageVariant = "recovery_" 411 } 412 mod := result.ModuleForTests(moduleName, fmt.Sprintf("android_%s%s_%s", imageVariant, archType, archVariant)) 413 outputFiles := mod.OutputFiles(t, "") 414 if len(outputFiles) != 1 { 415 t.Errorf("%q must have single output\n", moduleName) 416 return 417 } 418 snapshotPath := filepath.Join(outputDir, moduleName) 419 420 if expectToExist { 421 out := snapshotSingleton.Output(snapshotPath) 422 423 if out.Input.String() != outputFiles[0].String() { 424 t.Errorf("The input of snapshot %q must be %q, but %q", "prebuilt_vendor", out.Input.String(), outputFiles[0]) 425 } 426 427 snapshotJsonPath := snapshotPath + ".json" 428 429 if snapshotSingleton.MaybeOutput(snapshotJsonPath).Rule == nil { 430 t.Errorf("%q expected but not found", snapshotJsonPath) 431 } 432 } else { 433 out := snapshotSingleton.MaybeOutput(snapshotPath) 434 if out.Rule != nil { 435 t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0]) 436 } 437 } 438} 439 440func TestPrebuiltTakeSnapshot(t *testing.T) { 441 var testBp = ` 442 prebuilt_etc { 443 name: "prebuilt_vendor", 444 src: "foo.conf", 445 vendor: true, 446 } 447 448 prebuilt_etc { 449 name: "prebuilt_vendor_indirect", 450 src: "foo.conf", 451 vendor: true, 452 } 453 454 prebuilt_etc { 455 name: "prebuilt_recovery", 456 src: "bar.conf", 457 recovery: true, 458 } 459 460 prebuilt_etc { 461 name: "prebuilt_recovery_indirect", 462 src: "bar.conf", 463 recovery: true, 464 } 465 ` 466 467 t.Run("prebuilt: vendor and recovery snapshot", func(t *testing.T) { 468 result := prepareForPrebuiltEtcSnapshotTest.RunTestWithBp(t, testBp) 469 470 checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor") 471 checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor_indirect") 472 checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery") 473 checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery_indirect") 474 }) 475 476 t.Run("prebuilt: directed snapshot", func(t *testing.T) { 477 prepareForPrebuiltEtcDirectedSnapshotTest := android.GroupFixturePreparers( 478 prepareForPrebuiltEtcSnapshotTest, 479 android.FixtureModifyConfig(func(config android.Config) { 480 config.TestProductVariables.DirectedVendorSnapshot = true 481 config.TestProductVariables.VendorSnapshotModules = make(map[string]bool) 482 config.TestProductVariables.VendorSnapshotModules["prebuilt_vendor"] = true 483 config.TestProductVariables.DirectedRecoverySnapshot = true 484 config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool) 485 config.TestProductVariables.RecoverySnapshotModules["prebuilt_recovery"] = true 486 }), 487 ) 488 489 result := prepareForPrebuiltEtcDirectedSnapshotTest.RunTestWithBp(t, testBp) 490 491 checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor") 492 checkIfSnapshotNotTaken(t, result, "vendor", "prebuilt_vendor_indirect") 493 checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery") 494 checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect") 495 }) 496} 497