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 } 144 145 mod := result.Module("foo", "android_arm64_armv8-a").(*PrebuiltEtc) 146 entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] 147 for k, expectedValue := range expected { 148 if value, ok := entries.EntryMap[k]; ok { 149 android.AssertDeepEquals(t, k, expectedValue, value) 150 } else { 151 t.Errorf("No %s defined, saw %q", k, entries.EntryMap) 152 } 153 } 154} 155 156func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) { 157 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 158 prebuilt_etc { 159 name: "foo.conf", 160 src: "foo.conf", 161 relative_install_path: "bar", 162 } 163 `) 164 165 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 166 expected := "out/soong/target/product/test_device/system/etc/bar" 167 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 168} 169 170func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) { 171 prepareForPrebuiltEtcTest. 172 ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("relative_install_path is set. Cannot set sub_dir")). 173 RunTestWithBp(t, ` 174 prebuilt_etc { 175 name: "foo.conf", 176 src: "foo.conf", 177 sub_dir: "bar", 178 relative_install_path: "bar", 179 } 180 `) 181} 182 183func TestPrebuiltEtcHost(t *testing.T) { 184 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 185 prebuilt_etc_host { 186 name: "foo.conf", 187 src: "foo.conf", 188 } 189 `) 190 191 buildOS := result.Config.BuildOS.String() 192 p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) 193 if !p.Host() { 194 t.Errorf("host bit is not set for a prebuilt_etc_host module.") 195 } 196} 197 198func TestPrebuiltRootInstallDirPath(t *testing.T) { 199 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 200 prebuilt_root { 201 name: "foo.conf", 202 src: "foo.conf", 203 filename: "foo.conf", 204 } 205 `) 206 207 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 208 expected := "out/soong/target/product/test_device/system" 209 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 210} 211 212func TestPrebuiltRootInstallDirPathValidate(t *testing.T) { 213 prepareForPrebuiltEtcTest.ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern("filename cannot contain separator")).RunTestWithBp(t, ` 214 prebuilt_root { 215 name: "foo.conf", 216 src: "foo.conf", 217 filename: "foo/bar.conf", 218 } 219 `) 220} 221 222func TestPrebuiltUserShareInstallDirPath(t *testing.T) { 223 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 224 prebuilt_usr_share { 225 name: "foo.conf", 226 src: "foo.conf", 227 sub_dir: "bar", 228 } 229 `) 230 231 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 232 expected := "out/soong/target/product/test_device/system/usr/share/bar" 233 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 234} 235 236func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { 237 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 238 prebuilt_usr_share_host { 239 name: "foo.conf", 240 src: "foo.conf", 241 sub_dir: "bar", 242 } 243 `) 244 245 buildOS := result.Config.BuildOS.String() 246 p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) 247 expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "usr", "share", "bar") 248 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 249} 250 251func TestPrebuiltFontInstallDirPath(t *testing.T) { 252 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` 253 prebuilt_font { 254 name: "foo.conf", 255 src: "foo.conf", 256 } 257 `) 258 259 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 260 expected := "out/soong/target/product/test_device/system/fonts" 261 android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath) 262} 263 264func TestPrebuiltFirmwareDirPath(t *testing.T) { 265 targetPath := "out/soong/target/product/test_device" 266 tests := []struct { 267 description string 268 config string 269 expectedPath string 270 }{{ 271 description: "prebuilt: system firmware", 272 config: ` 273 prebuilt_firmware { 274 name: "foo.conf", 275 src: "foo.conf", 276 }`, 277 expectedPath: filepath.Join(targetPath, "system/etc/firmware"), 278 }, { 279 description: "prebuilt: vendor firmware", 280 config: ` 281 prebuilt_firmware { 282 name: "foo.conf", 283 src: "foo.conf", 284 soc_specific: true, 285 sub_dir: "sub_dir", 286 }`, 287 expectedPath: filepath.Join(targetPath, "vendor/firmware/sub_dir"), 288 }} 289 for _, tt := range tests { 290 t.Run(tt.description, func(t *testing.T) { 291 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config) 292 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 293 android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath) 294 }) 295 } 296} 297 298func TestPrebuiltDSPDirPath(t *testing.T) { 299 targetPath := "out/soong/target/product/test_device" 300 tests := []struct { 301 description string 302 config string 303 expectedPath string 304 }{{ 305 description: "prebuilt: system dsp", 306 config: ` 307 prebuilt_dsp { 308 name: "foo.conf", 309 src: "foo.conf", 310 }`, 311 expectedPath: filepath.Join(targetPath, "system/etc/dsp"), 312 }, { 313 description: "prebuilt: vendor dsp", 314 config: ` 315 prebuilt_dsp { 316 name: "foo.conf", 317 src: "foo.conf", 318 soc_specific: true, 319 sub_dir: "sub_dir", 320 }`, 321 expectedPath: filepath.Join(targetPath, "vendor/dsp/sub_dir"), 322 }} 323 for _, tt := range tests { 324 t.Run(tt.description, func(t *testing.T) { 325 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config) 326 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 327 android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath) 328 }) 329 } 330} 331 332func TestPrebuiltRFSADirPath(t *testing.T) { 333 targetPath := "out/soong/target/product/test_device" 334 tests := []struct { 335 description string 336 config string 337 expectedPath string 338 }{{ 339 description: "prebuilt: system rfsa", 340 config: ` 341 prebuilt_rfsa { 342 name: "foo.conf", 343 src: "foo.conf", 344 }`, 345 expectedPath: filepath.Join(targetPath, "system/lib/rfsa"), 346 }, { 347 description: "prebuilt: vendor rfsa", 348 config: ` 349 prebuilt_rfsa { 350 name: "foo.conf", 351 src: "foo.conf", 352 soc_specific: true, 353 sub_dir: "sub_dir", 354 }`, 355 expectedPath: filepath.Join(targetPath, "vendor/lib/rfsa/sub_dir"), 356 }} 357 for _, tt := range tests { 358 t.Run(tt.description, func(t *testing.T) { 359 result := prepareForPrebuiltEtcTest.RunTestWithBp(t, tt.config) 360 p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) 361 android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath) 362 }) 363 } 364} 365 366func checkIfSnapshotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) { 367 checkIfSnapshotExistAsExpected(t, result, image, moduleName, true) 368} 369 370func checkIfSnapshotNotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) { 371 checkIfSnapshotExistAsExpected(t, result, image, moduleName, false) 372} 373 374func checkIfSnapshotExistAsExpected(t *testing.T, result *android.TestResult, image string, moduleName string, expectToExist bool) { 375 snapshotSingleton := result.SingletonForTests(image + "-snapshot") 376 archType := "arm64" 377 archVariant := "armv8-a" 378 archDir := fmt.Sprintf("arch-%s", archType) 379 380 snapshotDir := fmt.Sprintf("%s-snapshot", image) 381 snapshotVariantPath := filepath.Join(snapshotDir, archType) 382 outputDir := filepath.Join(snapshotVariantPath, archDir, "etc") 383 imageVariant := "" 384 if image == "recovery" { 385 imageVariant = "recovery_" 386 } 387 mod := result.ModuleForTests(moduleName, fmt.Sprintf("android_%s%s_%s", imageVariant, archType, archVariant)) 388 outputFiles := mod.OutputFiles(t, "") 389 if len(outputFiles) != 1 { 390 t.Errorf("%q must have single output\n", moduleName) 391 return 392 } 393 snapshotPath := filepath.Join(outputDir, moduleName) 394 395 if expectToExist { 396 out := snapshotSingleton.Output(snapshotPath) 397 398 if out.Input.String() != outputFiles[0].String() { 399 t.Errorf("The input of snapshot %q must be %q, but %q", "prebuilt_vendor", out.Input.String(), outputFiles[0]) 400 } 401 402 snapshotJsonPath := snapshotPath + ".json" 403 404 if snapshotSingleton.MaybeOutput(snapshotJsonPath).Rule == nil { 405 t.Errorf("%q expected but not found", snapshotJsonPath) 406 } 407 } else { 408 out := snapshotSingleton.MaybeOutput(snapshotPath) 409 if out.Rule != nil { 410 t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0]) 411 } 412 } 413} 414 415func TestPrebuiltTakeSnapshot(t *testing.T) { 416 var testBp = ` 417 prebuilt_etc { 418 name: "prebuilt_vendor", 419 src: "foo.conf", 420 vendor: true, 421 } 422 423 prebuilt_etc { 424 name: "prebuilt_vendor_indirect", 425 src: "foo.conf", 426 vendor: true, 427 } 428 429 prebuilt_etc { 430 name: "prebuilt_recovery", 431 src: "bar.conf", 432 recovery: true, 433 } 434 435 prebuilt_etc { 436 name: "prebuilt_recovery_indirect", 437 src: "bar.conf", 438 recovery: true, 439 } 440 ` 441 442 t.Run("prebuilt: vendor and recovery snapshot", func(t *testing.T) { 443 result := prepareForPrebuiltEtcSnapshotTest.RunTestWithBp(t, testBp) 444 445 checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor") 446 checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor_indirect") 447 checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery") 448 checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery_indirect") 449 }) 450 451 t.Run("prebuilt: directed snapshot", func(t *testing.T) { 452 prepareForPrebuiltEtcDirectedSnapshotTest := android.GroupFixturePreparers( 453 prepareForPrebuiltEtcSnapshotTest, 454 android.FixtureModifyConfig(func(config android.Config) { 455 config.TestProductVariables.DirectedVendorSnapshot = true 456 config.TestProductVariables.VendorSnapshotModules = make(map[string]bool) 457 config.TestProductVariables.VendorSnapshotModules["prebuilt_vendor"] = true 458 config.TestProductVariables.DirectedRecoverySnapshot = true 459 config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool) 460 config.TestProductVariables.RecoverySnapshotModules["prebuilt_recovery"] = true 461 }), 462 ) 463 464 result := prepareForPrebuiltEtcDirectedSnapshotTest.RunTestWithBp(t, testBp) 465 466 checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor") 467 checkIfSnapshotNotTaken(t, result, "vendor", "prebuilt_vendor_indirect") 468 checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery") 469 checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect") 470 }) 471} 472