// Copyright 2024 Google Inc. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package fsgen import ( "android/soong/android" "android/soong/etc" "android/soong/filesystem" "android/soong/java" "testing" "github.com/google/blueprint/proptools" ) var prepareForTestWithFsgenBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents) func TestFileSystemCreatorSystemImageProps(t *testing.T) { result := android.GroupFixturePreparers( android.PrepareForIntegrationTestWithAndroid, android.PrepareForTestWithAndroidBuildComponents, android.PrepareForTestWithAllowMissingDependencies, filesystem.PrepareForTestWithFilesystemBuildComponents, prepareForTestWithFsgenBuildComponents, android.FixtureModifyConfig(func(config android.Config) { config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.BoardAvbEnable = true config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables = map[string]android.PartitionQualifiedVariablesType{ "system": { BoardAvbKeyPath: "external/avb/test/data/testkey_rsa4096.pem", BoardAvbAlgorithm: "SHA256_RSA4096", BoardAvbRollbackIndex: "0", BoardFileSystemType: "ext4", }, } }), android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "external/avb/test/Android.bp": []byte(` filegroup { name: "avb_testkey_rsa4096", srcs: ["data/testkey_rsa4096.pem"], } `), "build/soong/fsgen/Android.bp": []byte(` soong_filesystem_creator { name: "foo", } `), }), ).RunTest(t) fooSystem := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().(interface { FsProps() filesystem.FilesystemProperties }) android.AssertBoolEquals( t, "Property expected to match the product variable 'BOARD_AVB_ENABLE'", true, proptools.Bool(fooSystem.FsProps().Use_avb), ) android.AssertStringEquals( t, "Property the avb_private_key property to be set to the existing filegroup", ":avb_testkey_rsa4096", proptools.String(fooSystem.FsProps().Avb_private_key), ) android.AssertStringEquals( t, "Property expected to match the product variable 'BOARD_AVB_ALGORITHM'", "SHA256_RSA4096", proptools.String(fooSystem.FsProps().Avb_algorithm), ) android.AssertIntEquals( t, "Property expected to match the product variable 'BOARD_AVB_SYSTEM_ROLLBACK_INDEX'", 0, proptools.Int(fooSystem.FsProps().Rollback_index), ) android.AssertStringEquals( t, "Property expected to match the product variable 'BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE'", "ext4", proptools.String(fooSystem.FsProps().Type), ) } func TestFileSystemCreatorSetPartitionDeps(t *testing.T) { result := android.GroupFixturePreparers( android.PrepareForIntegrationTestWithAndroid, android.PrepareForTestWithAndroidBuildComponents, android.PrepareForTestWithAllowMissingDependencies, filesystem.PrepareForTestWithFilesystemBuildComponents, prepareForTestWithFsgenBuildComponents, java.PrepareForTestWithJavaBuildComponents, java.PrepareForTestWithJavaDefaultModules, android.FixtureModifyConfig(func(config android.Config) { config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"bar", "baz"} config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables = map[string]android.PartitionQualifiedVariablesType{ "system": { BoardFileSystemType: "ext4", }, } }), android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` soong_filesystem_creator { name: "foo", } `), }), ).RunTestWithBp(t, ` java_library { name: "bar", srcs: ["A.java"], } java_library { name: "baz", srcs: ["A.java"], product_specific: true, } `) android.AssertBoolEquals( t, "Generated system image expected to depend on system partition installed \"bar\"", true, java.CheckModuleHasDependency(t, result.TestContext, "test_product_generated_system_image", "android_common", "bar"), ) android.AssertBoolEquals( t, "Generated system image expected to not depend on product partition installed \"baz\"", false, java.CheckModuleHasDependency(t, result.TestContext, "test_product_generated_system_image", "android_common", "baz"), ) } func TestFileSystemCreatorDepsWithNamespace(t *testing.T) { result := android.GroupFixturePreparers( android.PrepareForIntegrationTestWithAndroid, android.PrepareForTestWithAndroidBuildComponents, android.PrepareForTestWithAllowMissingDependencies, android.PrepareForTestWithNamespace, android.PrepareForTestWithArchMutator, filesystem.PrepareForTestWithFilesystemBuildComponents, prepareForTestWithFsgenBuildComponents, java.PrepareForTestWithJavaBuildComponents, java.PrepareForTestWithJavaDefaultModules, android.FixtureModifyConfig(func(config android.Config) { config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"bar"} config.TestProductVariables.NamespacesToExport = []string{"a/b"} config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables = map[string]android.PartitionQualifiedVariablesType{ "system": { BoardFileSystemType: "ext4", }, } config.Targets[android.Android] = []android.Target{ {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: "", HostCross: false}, {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: "", HostCross: false}, {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64", HostCross: false}, {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm", HostCross: false}, } }), android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` soong_filesystem_creator { name: "foo", } `), "a/b/Android.bp": []byte(` soong_namespace{ } java_library { name: "bar", srcs: ["A.java"], compile_multilib: "64", } `), "c/d/Android.bp": []byte(` soong_namespace{ } java_library { name: "bar", srcs: ["A.java"], } `), }), ).RunTest(t) var packagingProps android.PackagingProperties for _, prop := range result.ModuleForTests("test_product_generated_system_image", "android_common").Module().GetProperties() { if packagingPropStruct, ok := prop.(*android.PackagingProperties); ok { packagingProps = *packagingPropStruct } } moduleDeps := packagingProps.Multilib.Lib64.Deps eval := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) android.AssertStringListContains( t, "Generated system image expected to depend on \"bar\" defined in \"a/b\" namespace", moduleDeps.GetOrDefault(eval, nil), "//a/b:bar", ) android.AssertStringListDoesNotContain( t, "Generated system image expected to not depend on \"bar\" defined in \"c/d\" namespace", moduleDeps.GetOrDefault(eval, nil), "//c/d:bar", ) } func TestRemoveOverriddenModulesFromDeps(t *testing.T) { result := android.GroupFixturePreparers( android.PrepareForIntegrationTestWithAndroid, android.PrepareForTestWithAndroidBuildComponents, android.PrepareForTestWithAllowMissingDependencies, prepareForTestWithFsgenBuildComponents, java.PrepareForTestWithJavaBuildComponents, android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` soong_filesystem_creator { name: "foo", } `), }), android.FixtureModifyConfig(func(config android.Config) { config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"libfoo", "libbar"} }), ).RunTestWithBp(t, ` java_library { name: "libfoo", } java_library { name: "libbar", required: ["libbaz"], } java_library { name: "libbaz", overrides: ["libfoo"], // overrides libfoo } `) resolvedSystemDeps := result.TestContext.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps["system"] _, libFooInDeps := (*resolvedSystemDeps)["libfoo"] android.AssertBoolEquals(t, "libfoo should not appear in deps because it has been overridden by libbaz. The latter is a required dep of libbar, which is listed in PRODUCT_PACKAGES", false, libFooInDeps) } func TestPrebuiltEtcModuleGen(t *testing.T) { result := android.GroupFixturePreparers( android.PrepareForIntegrationTestWithAndroid, android.PrepareForTestWithAndroidBuildComponents, android.PrepareForTestWithAllowMissingDependencies, filesystem.PrepareForTestWithFilesystemBuildComponents, prepareForTestWithFsgenBuildComponents, android.FixtureModifyConfig(func(config android.Config) { config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles = []string{ "frameworks/base/config/preloaded-classes:system/etc/preloaded-classes", "frameworks/base/data/keyboards/Vendor_0079_Product_0011.kl:system/usr/keylayout/subdir/Vendor_0079_Product_0011.kl", "frameworks/base/data/keyboards/Vendor_0079_Product_18d4.kl:system/usr/keylayout/subdir/Vendor_0079_Product_18d4.kl", "some/non/existing/file.txt:system/etc/file.txt", "device/sample/etc/apns-full-conf.xml:product/etc/apns-conf.xml:google", "device/sample/etc/apns-full-conf.xml:product/etc/apns-conf-2.xml", } config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables = map[string]android.PartitionQualifiedVariablesType{ "system": { BoardFileSystemType: "ext4", }, } }), android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` soong_filesystem_creator { name: "foo", } `), "frameworks/base/config/preloaded-classes": nil, "frameworks/base/data/keyboards/Vendor_0079_Product_0011.kl": nil, "frameworks/base/data/keyboards/Vendor_0079_Product_18d4.kl": nil, "device/sample/etc/apns-full-conf.xml": nil, }), ).RunTest(t) checkModuleProp := func(m android.Module, matcher func(actual interface{}) bool) bool { for _, prop := range m.GetProperties() { if matcher(prop) { return true } } return false } // check generated prebuilt_* module type install path and install partition generatedModule := result.ModuleForTests("system-frameworks_base_config-etc-0", "android_arm64_armv8-a").Module() etcModule, _ := generatedModule.(*etc.PrebuiltEtc) android.AssertStringEquals( t, "module expected to have etc install path", "etc", etcModule.BaseDir(), ) android.AssertBoolEquals( t, "module expected to be installed in system partition", true, !generatedModule.InstallInProduct() && !generatedModule.InstallInVendor() && !generatedModule.InstallInSystemExt(), ) // check generated prebuilt_* module specifies correct relative_install_path property generatedModule = result.ModuleForTests("system-frameworks_base_data_keyboards-usr_keylayout_subdir-0", "android_arm64_armv8-a").Module() etcModule, _ = generatedModule.(*etc.PrebuiltEtc) android.AssertStringEquals( t, "module expected to set correct relative_install_path properties", "subdir", etcModule.SubDir(), ) // check that prebuilt_* module is not generated for non existing source file android.AssertPanicMessageContains( t, "prebuilt_* module not generated for non existing source file", "failed to find module \"system-some_non_existing-etc-0\"", func() { result.ModuleForTests("system-some_non_existing-etc-0", "android_arm64_armv8-a") }, ) // check that duplicate src file can exist in PRODUCT_COPY_FILES and generates separate modules generatedModule0 := result.ModuleForTests("product-device_sample_etc-etc-0", "android_arm64_armv8-a").Module() generatedModule1 := result.ModuleForTests("product-device_sample_etc-etc-1", "android_arm64_armv8-a").Module() // check that generated prebuilt_* module sets correct srcs and dsts property eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) android.AssertBoolEquals( t, "module expected to set correct srcs and dsts properties", true, checkModuleProp(generatedModule0, func(actual interface{}) bool { if p, ok := actual.(*etc.PrebuiltEtcProperties); ok { srcs := p.Srcs.GetOrDefault(eval, nil) dsts := p.Dsts.GetOrDefault(eval, nil) return len(srcs) == 1 && srcs[0] == "apns-full-conf.xml" && len(dsts) == 1 && dsts[0] == "apns-conf.xml" } return false }), ) // check that generated prebuilt_* module sets correct srcs and dsts property eval = generatedModule1.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) android.AssertBoolEquals( t, "module expected to set correct srcs and dsts properties", true, checkModuleProp(generatedModule1, func(actual interface{}) bool { if p, ok := actual.(*etc.PrebuiltEtcProperties); ok { srcs := p.Srcs.GetOrDefault(eval, nil) dsts := p.Dsts.GetOrDefault(eval, nil) return len(srcs) == 1 && srcs[0] == "apns-full-conf.xml" && len(dsts) == 1 && dsts[0] == "apns-conf-2.xml" } return false }), ) }