From c2ca1ee83db947430af149b9524ce9268f264723 Mon Sep 17 00:00:00 2001 From: Ivan Lozano Date: Tue, 9 Nov 2021 16:23:40 -0500 Subject: [PATCH] rust: Add Recovery Snapshot Soong tests for rust. Bug: 197866992 Test: m nothing Change-Id: I4b5401cf2ffa0dbcc6fea60f90bad4c47a9d5e6b --- cc/testing.go | 8 + cc/vendor_snapshot_test.go | 16 +- rust/rust_test.go | 21 ++- rust/testing.go | 3 + rust/vendor_snapshot_test.go | 351 +++++++++++++++++++++++++++++++++++ 5 files changed, 385 insertions(+), 14 deletions(-) diff --git a/cc/testing.go b/cc/testing.go index b0a220cff..3bf936d43 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -763,3 +763,11 @@ func GetOutputPaths(ctx *android.TestContext, variant string, moduleNames []stri } return paths } + +func AssertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool, variant string) { + t.Helper() + m := ctx.ModuleForTests(name, variant).Module().(LinkableInterface) + if m.ExcludeFromRecoverySnapshot() != expected { + t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected) + } +} diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go index ca2f56924..b5022c8d2 100644 --- a/cc/vendor_snapshot_test.go +++ b/cc/vendor_snapshot_test.go @@ -1020,14 +1020,6 @@ func TestVendorSnapshotSanitizer(t *testing.T) { assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a") } -func assertExcludeFromRecoverySnapshotIs(t *testing.T, ctx *android.TestContext, name string, expected bool) { - t.Helper() - m := ctx.ModuleForTests(name, recoveryVariant).Module().(*Module) - if m.ExcludeFromRecoverySnapshot() != expected { - t.Errorf("expected %q ExcludeFromRecoverySnapshot to be %t", m.String(), expected) - } -} - func TestVendorSnapshotExclude(t *testing.T) { // This test verifies that the exclude_from_vendor_snapshot property @@ -1371,13 +1363,13 @@ func TestRecoverySnapshotExclude(t *testing.T) { android.FailIfErrored(t, errs) // Test an include and exclude framework module. - assertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false) - assertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true) - assertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true) + AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, recoveryVariant) + AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, recoveryVariant) + AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, recoveryVariant) // A recovery module is excluded, but by its path, not the // exclude_from_recovery_snapshot property. - assertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false) + AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, recoveryVariant) // Verify the content of the recovery snapshot. diff --git a/rust/rust_test.go b/rust/rust_test.go index 80f693eb6..d50922e30 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -79,8 +79,10 @@ func testRustVndk(t *testing.T, bp string) *android.TestContext { } const ( - sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared" - rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std" + sharedVendorVariant = "android_vendor.29_arm64_armv8-a_shared" + rlibVendorVariant = "android_vendor.29_arm64_armv8-a_rlib_rlib-std" + sharedRecoveryVariant = "android_recovery_arm64_armv8-a_shared" + rlibRecoveryVariant = "android_recovery_arm64_armv8-a_rlib_rlib-std" ) func testRustVndkFs(t *testing.T, bp string, fs android.MockFS) *android.TestContext { @@ -101,7 +103,22 @@ func testRustVndkFsVersions(t *testing.T, bp string, fs android.MockFS, device_v ), ).RunTestWithBp(t, bp) return result.TestContext +} +func testRustRecoveryFsVersions(t *testing.T, bp string, fs android.MockFS, device_version, vndk_version, recovery_version string) *android.TestContext { + skipTestIfOsNotSupported(t) + result := android.GroupFixturePreparers( + prepareForRustTest, + fs.AddToFixture(), + android.FixtureModifyProductVariables( + func(variables android.FixtureProductVariables) { + variables.DeviceVndkVersion = StringPtr(device_version) + variables.RecoverySnapshotVersion = StringPtr(recovery_version) + variables.Platform_vndk_version = StringPtr(vndk_version) + }, + ), + ).RunTestWithBp(t, bp) + return result.TestContext } // testRustCov returns a TestContext in which a basic environment has been diff --git a/rust/testing.go b/rust/testing.go index 94cdd9dcd..e7fb9fa2b 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -135,6 +135,7 @@ func GatherRequiredDepsForTest() string { apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", vendor_available: true, + recovery_available: true, llndk: { symbol_file: "liblog.map.txt", }, @@ -161,6 +162,7 @@ func GatherRequiredDepsForTest() string { host_supported: true, vendor_available: true, vendor_ramdisk_available: true, + recovery_available: true, native_coverage: false, sysroot: true, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], @@ -173,6 +175,7 @@ func GatherRequiredDepsForTest() string { host_supported: true, vendor_available: true, vendor_ramdisk_available: true, + recovery_available: true, native_coverage: false, apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go index 60ddb653f..c772b96d8 100644 --- a/rust/vendor_snapshot_test.go +++ b/rust/vendor_snapshot_test.go @@ -994,3 +994,354 @@ func TestVendorSnapshotUse(t *testing.T) { t.Errorf("bin must not have variant %#v, but it does", sharedVariant) } } + +func TestRecoverySnapshotCapture(t *testing.T) { + bp := ` + rust_ffi { + name: "librecovery", + recovery: true, + srcs: ["foo.rs"], + crate_name: "recovery", + } + + rust_ffi { + name: "librecovery_available", + recovery_available: true, + srcs: ["foo.rs"], + crate_name: "recovery_available", + } + + rust_library_rlib { + name: "librecovery_rlib", + recovery: true, + srcs: ["foo.rs"], + crate_name: "recovery_rlib", + } + + rust_library_rlib { + name: "librecovery_available_rlib", + recovery_available: true, + srcs: ["foo.rs"], + crate_name: "recovery_available_rlib", + } + + rust_binary { + name: "recovery_bin", + recovery: true, + srcs: ["foo.rs"], + } + + rust_binary { + name: "recovery_available_bin", + recovery_available: true, + srcs: ["foo.rs"], + } + +` + // Check Recovery snapshot output. + + ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "", "29", "current") + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") + + var jsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + // For shared libraries, all recovery:true and recovery_available modules are captured. + sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) + jsonFiles = append(jsonFiles, + filepath.Join(sharedDir, "librecovery.so.json"), + filepath.Join(sharedDir, "librecovery_available.so.json")) + + // For static libraries, all recovery:true and recovery_available modules are captured. + staticVariant := fmt.Sprintf("android_recovery_%s_%s_static", archType, archVariant) + staticDir := filepath.Join(snapshotVariantPath, archDir, "static") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.a", staticDir, staticVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.a", staticDir, staticVariant) + jsonFiles = append(jsonFiles, + filepath.Join(staticDir, "librecovery.a.json"), + filepath.Join(staticDir, "librecovery_available.a.json")) + + // For rlib libraries, all recovery:true and recovery_available modules are captured. + rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant) + jsonFiles = append(jsonFiles, + filepath.Join(rlibDir, "librecovery_rlib.rlib.json"), + filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json")) + + // For binary executables, all recovery:true and recovery_available modules are captured. + if archType == "arm64" { + binaryVariant := fmt.Sprintf("android_recovery_%s_%s", archType, archVariant) + binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary") + cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_bin", "recovery_bin", binaryDir, binaryVariant) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "recovery_available_bin", "recovery_available_bin", binaryDir, binaryVariant) + jsonFiles = append(jsonFiles, + filepath.Join(binaryDir, "recovery_bin.json"), + filepath.Join(binaryDir, "recovery_available_bin.json")) + } + } + + for _, jsonFile := range jsonFiles { + // verify all json files exist + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("%q expected but not found", jsonFile) + } + } +} + +func TestRecoverySnapshotExclude(t *testing.T) { + // This test verifies that the exclude_from_recovery_snapshot property + // makes its way from the Android.bp source file into the module data + // structure. It also verifies that modules are correctly included or + // excluded in the recovery snapshot based on their path (framework or + // vendor) and the exclude_from_recovery_snapshot property. + + frameworkBp := ` + rust_ffi_shared { + name: "libinclude", + srcs: ["src/include.rs"], + recovery_available: true, + crate_name: "include", + } + rust_ffi_shared { + name: "libexclude", + srcs: ["src/exclude.rs"], + recovery: true, + exclude_from_recovery_snapshot: true, + crate_name: "exclude", + } + rust_ffi_shared { + name: "libavailable_exclude", + srcs: ["src/exclude.rs"], + recovery_available: true, + exclude_from_recovery_snapshot: true, + crate_name: "available_exclude", + } + rust_library_rlib { + name: "libinclude_rlib", + srcs: ["src/include.rs"], + recovery_available: true, + crate_name: "include_rlib", + } + rust_library_rlib { + name: "libexclude_rlib", + srcs: ["src/exclude.rs"], + recovery: true, + exclude_from_recovery_snapshot: true, + crate_name: "exclude_rlib", + } + rust_library_rlib { + name: "libavailable_exclude_rlib", + srcs: ["src/exclude.rs"], + recovery_available: true, + exclude_from_recovery_snapshot: true, + crate_name: "available_exclude_rlib", + } + ` + + vendorProprietaryBp := ` + rust_ffi_shared { + name: "librecovery", + srcs: ["recovery.rs"], + recovery: true, + crate_name: "recovery", + } + rust_library_rlib { + name: "librecovery_rlib", + srcs: ["recovery.rs"], + recovery: true, + crate_name: "recovery_rlib", + } + ` + + mockFS := map[string][]byte{ + "framework/Android.bp": []byte(frameworkBp), + "framework/include.rs": nil, + "framework/exclude.rs": nil, + "device/Android.bp": []byte(vendorProprietaryBp), + "device/recovery.rs": nil, + } + + ctx := testRustRecoveryFsVersions(t, "", mockFS, "", "29", "current") + + // Test an include and exclude framework module. + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude", false, sharedRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude", true, sharedRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude", true, sharedRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libinclude_rlib", false, rlibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libexclude_rlib", true, rlibRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "libavailable_exclude_rlib", true, rlibRecoveryVariant) + + // A recovery module is excluded, but by its path not the exclude_from_recovery_snapshot property + // ('device/' and 'vendor/' are default excluded). See snapshot/recovery_snapshot.go for more detail. + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery", false, sharedRecoveryVariant) + cc.AssertExcludeFromRecoverySnapshotIs(t, ctx, "librecovery_rlib", false, rlibRecoveryVariant) + + // Verify the content of the recovery snapshot. + + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") + + var includeJsonFiles []string + var excludeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) + rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + + // Included modules + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "libinclude_rlib", "libinclude_rlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "libinclude_rlib.rlib.json")) + + // Excluded modules + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude", "libavailable_exclude.so", sharedDir, sharedVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libavailable_exclude.so.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libexclude_rlib", "libexclude_rlib.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libexclude_rlib.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json")) + cc.CheckSnapshotExclude(t, ctx, snapshotSingleton, "libavailable_exclude_rlib", "libavailable_exclude_rlib.rlib", rlibDir, rlibVariant) + excludeJsonFiles = append(excludeJsonFiles, filepath.Join(rlibDir, "libavailable_exclude_rlib.rlib.json")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found", jsonFile) + } + } + + // Verify that each json file for an excluded module has no rule. + for _, jsonFile := range excludeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil { + t.Errorf("exclude json file %q found", jsonFile) + } + } +} + +func TestRecoverySnapshotDirected(t *testing.T) { + bp := ` + rust_ffi_shared { + name: "librecovery", + recovery: true, + crate_name: "recovery", + srcs: ["foo.rs"], + } + + rust_ffi_shared { + name: "librecovery_available", + recovery_available: true, + crate_name: "recovery_available", + srcs: ["foo.rs"], + } + + rust_library_rlib { + name: "librecovery_rlib", + recovery: true, + crate_name: "recovery", + srcs: ["foo.rs"], + } + + rust_library_rlib { + name: "librecovery_available_rlib", + recovery_available: true, + crate_name: "recovery_available", + srcs: ["foo.rs"], + } + + /* TODO: Uncomment when Rust supports the "prefer" property for prebuilts + rust_library_rlib { + name: "libfoo_rlib", + recovery: true, + crate_name: "foo", + } + + rust_prebuilt_rlib { + name: "libfoo_rlib", + recovery: true, + prefer: true, + srcs: ["libfoo.rlib"], + crate_name: "foo", + } + */ +` + ctx := testRustRecoveryFsVersions(t, bp, rustMockedFiles, "current", "29", "current") + ctx.Config().TestProductVariables.RecoverySnapshotModules = make(map[string]bool) + ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery"] = true + ctx.Config().TestProductVariables.RecoverySnapshotModules["librecovery_rlib"] = true + ctx.Config().TestProductVariables.DirectedRecoverySnapshot = true + + // Check recovery snapshot output. + snapshotDir := "recovery-snapshot" + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") + snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") + + var includeJsonFiles []string + + for _, arch := range [][]string{ + []string{"arm64", "armv8-a"}, + } { + archType := arch[0] + archVariant := arch[1] + archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant) + + sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant) + rlibVariant := fmt.Sprintf("android_recovery_%s_%s_rlib_rlib-std", archType, archVariant) + sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared") + rlibDir := filepath.Join(snapshotVariantPath, archDir, "rlib") + + // Included modules + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json")) + cc.CheckSnapshot(t, ctx, snapshotSingleton, "librecovery_rlib", "librecovery_rlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_rlib.rlib.json")) + + // TODO: When Rust supports the "prefer" property for prebuilts, perform this check. + /* + // Check that snapshot captures "prefer: true" prebuilt + cc.CheckSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo_rlib", "libfoo_rlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo_rlib.rlib.json")) + */ + + // Excluded modules. Modules not included in the directed recovery snapshot + // are still included as fake modules. + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json")) + cc.CheckSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available_rlib", "librecovery_available_rlib.rlib", rlibDir, rlibVariant) + includeJsonFiles = append(includeJsonFiles, filepath.Join(rlibDir, "librecovery_available_rlib.rlib.json")) + } + + // Verify that each json file for an included module has a rule. + for _, jsonFile := range includeJsonFiles { + if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil { + t.Errorf("include json file %q not found, %#v", jsonFile, includeJsonFiles) + } + } +}