Update prebuilt_etc available for snapshot

Make prebuilt_etc module available for the snapshot. This change
includes implementing snapshot interface for the prebuilt_etc module so
it can be added to the snapshot from the fake snapshot, or when the
module is specified in the list.

Bug: 192430376
Test: m nothing passed
Test: Checked if the module is included in the snapshot properly
Change-Id: I3574d2a1b8f8f4e5f083f3913e8768f5088d0c46
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 354f6bb..0c5cfe4 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -15,11 +15,15 @@
 package etc
 
 import (
+	"fmt"
 	"os"
 	"path/filepath"
 	"testing"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
+	"android/soong/snapshot"
 )
 
 func TestMain(m *testing.M) {
@@ -36,6 +40,18 @@
 	}),
 )
 
+var prepareForPrebuiltEtcSnapshotTest = android.GroupFixturePreparers(
+	prepareForPrebuiltEtcTest,
+	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+		snapshot.VendorSnapshotImageSingleton.Init(ctx)
+		snapshot.RecoverySnapshotImageSingleton.Init(ctx)
+	}),
+	android.FixtureModifyConfig(func(config android.Config) {
+		config.TestProductVariables.DeviceVndkVersion = proptools.StringPtr("current")
+		config.TestProductVariables.RecoverySnapshotVersion = proptools.StringPtr("current")
+	}),
+)
+
 func TestPrebuiltEtcVariants(t *testing.T) {
 	result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
 		prebuilt_etc {
@@ -346,3 +362,110 @@
 		})
 	}
 }
+
+func checkIfSnapshotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) {
+	checkIfSnapshotExistAsExpected(t, result, image, moduleName, true)
+}
+
+func checkIfSnapshotNotTaken(t *testing.T, result *android.TestResult, image string, moduleName string) {
+	checkIfSnapshotExistAsExpected(t, result, image, moduleName, false)
+}
+
+func checkIfSnapshotExistAsExpected(t *testing.T, result *android.TestResult, image string, moduleName string, expectToExist bool) {
+	snapshotSingleton := result.SingletonForTests(image + "-snapshot")
+	archType := "arm64"
+	archVariant := "armv8-a"
+	archDir := fmt.Sprintf("arch-%s", archType)
+
+	snapshotDir := fmt.Sprintf("%s-snapshot", image)
+	snapshotVariantPath := filepath.Join(snapshotDir, archType)
+	outputDir := filepath.Join(snapshotVariantPath, archDir, "etc")
+	imageVariant := ""
+	if image == "recovery" {
+		imageVariant = "recovery_"
+	}
+	mod := result.ModuleForTests(moduleName, fmt.Sprintf("android_%s%s_%s", imageVariant, archType, archVariant))
+	outputFiles := mod.OutputFiles(t, "")
+	if len(outputFiles) != 1 {
+		t.Errorf("%q must have single output\n", moduleName)
+		return
+	}
+	snapshotPath := filepath.Join(outputDir, moduleName)
+
+	if expectToExist {
+		out := snapshotSingleton.Output(snapshotPath)
+
+		if out.Input.String() != outputFiles[0].String() {
+			t.Errorf("The input of snapshot %q must be %q, but %q", "prebuilt_vendor", out.Input.String(), outputFiles[0])
+		}
+
+		snapshotJsonPath := snapshotPath + ".json"
+
+		if snapshotSingleton.MaybeOutput(snapshotJsonPath).Rule == nil {
+			t.Errorf("%q expected but not found", snapshotJsonPath)
+		}
+	} else {
+		out := snapshotSingleton.MaybeOutput(snapshotPath)
+		if out.Rule != nil {
+			t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0])
+		}
+	}
+}
+
+func TestPrebuiltTakeSnapshot(t *testing.T) {
+	var testBp = `
+	prebuilt_etc {
+		name: "prebuilt_vendor",
+		src: "foo.conf",
+		vendor: true,
+	}
+
+	prebuilt_etc {
+		name: "prebuilt_vendor_indirect",
+		src: "foo.conf",
+		vendor: true,
+	}
+
+	prebuilt_etc {
+		name: "prebuilt_recovery",
+		src: "bar.conf",
+		recovery: true,
+	}
+
+	prebuilt_etc {
+		name: "prebuilt_recovery_indirect",
+		src: "bar.conf",
+		recovery: true,
+	}
+	`
+
+	t.Run("prebuilt: vendor and recovery snapshot", func(t *testing.T) {
+		result := prepareForPrebuiltEtcSnapshotTest.RunTestWithBp(t, testBp)
+
+		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor")
+		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor_indirect")
+		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery")
+		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
+	})
+
+	t.Run("prebuilt: directed snapshot", func(t *testing.T) {
+		prepareForPrebuiltEtcDirectedSnapshotTest := android.GroupFixturePreparers(
+			prepareForPrebuiltEtcSnapshotTest,
+			android.FixtureModifyConfig(func(config android.Config) {
+				config.TestProductVariables.DirectedVendorSnapshot = true
+				config.TestProductVariables.VendorSnapshotModules = make(map[string]bool)
+				config.TestProductVariables.VendorSnapshotModules["prebuilt_vendor"] = true
+				config.TestProductVariables.DirectedRecoverySnapshot = true
+				config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
+				config.TestProductVariables.RecoverySnapshotModules["prebuilt_recovery"] = true
+			}),
+		)
+
+		result := prepareForPrebuiltEtcDirectedSnapshotTest.RunTestWithBp(t, testBp)
+
+		checkIfSnapshotTaken(t, result, "vendor", "prebuilt_vendor")
+		checkIfSnapshotNotTaken(t, result, "vendor", "prebuilt_vendor_indirect")
+		checkIfSnapshotTaken(t, result, "recovery", "prebuilt_recovery")
+		checkIfSnapshotNotTaken(t, result, "recovery", "prebuilt_recovery_indirect")
+	})
+}