|  | // 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", | 
|  | }, | 
|  | } | 
|  | }), | 
|  | android.PrepareForNativeBridgeEnabled, | 
|  | 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", | 
|  | "device/sample/etc/apns-full-conf.xml:system/foo/file.txt", | 
|  | "device/sample/etc/apns-full-conf.xml:system/foo/apns-full-conf.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 property", | 
|  | true, | 
|  | checkModuleProp(generatedModule0, func(actual interface{}) bool { | 
|  | if p, ok := actual.(*etc.PrebuiltEtcProperties); ok { | 
|  | srcs := p.Srcs.GetOrDefault(eval, nil) | 
|  | return len(srcs) == 1 && | 
|  | srcs[0] == "apns-full-conf.xml" | 
|  | } | 
|  | return false | 
|  | }), | 
|  | ) | 
|  | android.AssertBoolEquals( | 
|  | t, | 
|  | "module expected to set correct dsts property", | 
|  | true, | 
|  | checkModuleProp(generatedModule0, func(actual interface{}) bool { | 
|  | if p, ok := actual.(*etc.PrebuiltDstsProperties); ok { | 
|  | dsts := p.Dsts.GetOrDefault(eval, nil) | 
|  | return 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 property", | 
|  | true, | 
|  | checkModuleProp(generatedModule1, func(actual interface{}) bool { | 
|  | if p, ok := actual.(*etc.PrebuiltEtcProperties); ok { | 
|  | srcs := p.Srcs.GetOrDefault(eval, nil) | 
|  | return len(srcs) == 1 && | 
|  | srcs[0] == "apns-full-conf.xml" | 
|  | } | 
|  | return false | 
|  | }), | 
|  | ) | 
|  | android.AssertBoolEquals( | 
|  | t, | 
|  | "module expected to set correct dsts property", | 
|  | true, | 
|  | checkModuleProp(generatedModule1, func(actual interface{}) bool { | 
|  | if p, ok := actual.(*etc.PrebuiltDstsProperties); ok { | 
|  | dsts := p.Dsts.GetOrDefault(eval, nil) | 
|  | return len(dsts) == 1 && | 
|  | dsts[0] == "apns-conf-2.xml" | 
|  | } | 
|  | return false | 
|  | }), | 
|  | ) | 
|  | } |