Add test for soong/testing/test_spec.

This CL adds test for test_spec.go and all_test_specs.go (singleton).

Bug: 296873595
Test: m nothing --no-skip-soong-tests -j96

Change-Id: I5010c68512e75d1b9a337c02da86faac15e376fe
diff --git a/java/Android.bp b/java/Android.bp
index 29c0957..cf96871 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -113,6 +113,7 @@
         "sdk_library_test.go",
         "system_modules_test.go",
         "systemserver_classpath_fragment_test.go",
+        "test_spec_test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/java/test_spec_test.go b/java/test_spec_test.go
new file mode 100644
index 0000000..22a8e60
--- /dev/null
+++ b/java/test_spec_test.go
@@ -0,0 +1,132 @@
+package java
+
+import (
+	"strings"
+	"testing"
+
+	"android/soong/android"
+	soongTesting "android/soong/testing"
+	"android/soong/testing/test_spec_proto"
+	"google.golang.org/protobuf/proto"
+)
+
+func TestTestSpec(t *testing.T) {
+	bp := `test_spec {
+		name: "module-name",
+		teamId: "12345",
+		tests: [
+			"java-test-module-name-one",
+			"java-test-module-name-two"
+		]
+	}
+
+	java_test {
+		name: "java-test-module-name-one",
+	}
+
+	java_test {
+		name: "java-test-module-name-two",
+	}`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests(
+		"module-name", "",
+	).Module().(*soongTesting.TestSpecModule)
+
+	// Check that the provider has the right contents
+	data := result.ModuleProvider(
+		module, soongTesting.TestSpecProviderKey,
+	).(soongTesting.TestSpecProviderData)
+	if !strings.HasSuffix(
+		data.IntermediatePath.String(), "/intermediateTestSpecMetadata.pb",
+	) {
+		t.Errorf(
+			"Missing intermediates path in provider: %s",
+			data.IntermediatePath.String(),
+		)
+	}
+
+	buildParamsSlice := module.BuildParamsForTests()
+	var metadata = ""
+	for _, params := range buildParamsSlice {
+		if params.Rule.String() == "android/soong/android.writeFile" {
+			metadata = params.Args["content"]
+		}
+	}
+
+	metadataList := make([]*test_spec_proto.TestSpec_OwnershipMetadata, 0, 2)
+	teamId := "12345"
+	bpFilePath := "Android.bp"
+	targetNames := []string{
+		"java-test-module-name-one", "java-test-module-name-two",
+	}
+
+	for _, test := range targetNames {
+		targetName := test
+		metadata := test_spec_proto.TestSpec_OwnershipMetadata{
+			TrendyTeamId: &teamId,
+			TargetName:   &targetName,
+			Path:         &bpFilePath,
+		}
+		metadataList = append(metadataList, &metadata)
+	}
+	testSpecMetadata := test_spec_proto.TestSpec{OwnershipMetadataList: metadataList}
+	protoData, _ := proto.Marshal(&testSpecMetadata)
+	rawData := string(protoData)
+	formattedData := strings.ReplaceAll(rawData, "\n", "\\n")
+	expectedMetadata := "'" + formattedData + "\\n'"
+
+	if metadata != expectedMetadata {
+		t.Errorf(
+			"Retrieved metadata: %s is not equal to expectedMetadata: %s", metadata,
+			expectedMetadata,
+		)
+	}
+
+	// Tests for all_test_spec singleton.
+	singleton := result.SingletonForTests("all_test_specs")
+	rule := singleton.Rule("all_test_specs_rule")
+	expectedCmd := "out/soong/host/linux-x86/bin/metadata -rule test_spec -inputFile out/soong/all_test_spec_paths.rsp -outputFile out/soong/ownership/all_test_specs.pb"
+	expectedOutputFile := "out/soong/ownership/all_test_specs.pb"
+	expectedInputFile := "out/soong/.intermediates/module-name/intermediateTestSpecMetadata.pb"
+	if !strings.Contains(
+		strings.TrimSpace(rule.Output.String()),
+		expectedOutputFile,
+	) {
+		t.Errorf(
+			"Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s",
+			rule.Output.String(), expectedOutputFile,
+		)
+	}
+
+	if !strings.Contains(
+		strings.TrimSpace(rule.Inputs[0].String()),
+		expectedInputFile,
+	) {
+		t.Errorf(
+			"Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s",
+			rule.Inputs[0].String(), expectedInputFile,
+		)
+	}
+
+	if !strings.Contains(
+		strings.TrimSpace(rule.RuleParams.Command),
+		expectedCmd,
+	) {
+		t.Errorf(
+			"Retrieved cmd: %s is not equal to expectedCmd: %s",
+			rule.RuleParams.Command, expectedCmd,
+		)
+	}
+}
+
+func runTest(
+	t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
+) *android.TestResult {
+	return android.GroupFixturePreparers(
+		soongTesting.PrepareForTestWithTestSpecBuildComponents,
+		PrepareForIntegrationTestWithJava,
+	).
+		ExtendWithErrorHandler(errorHandler).
+		RunTestWithBp(t, bp)
+}
diff --git a/testing/Android.bp b/testing/Android.bp
index 85e6a8b..18dccb3 100644
--- a/testing/Android.bp
+++ b/testing/Android.bp
@@ -15,6 +15,7 @@
         "all_test_specs.go",
         "test_spec.go",
         "init.go",
+        "test.go",
     ],
     pluginFor: ["soong_build"],
 }
diff --git a/testing/all_test_specs.go b/testing/all_test_specs.go
index 2ecf15f..9d4645b 100644
--- a/testing/all_test_specs.go
+++ b/testing/all_test_specs.go
@@ -21,10 +21,10 @@
 	var intermediateMetadataPaths android.Paths
 
 	ctx.VisitAllModules(func(module android.Module) {
-		if !ctx.ModuleHasProvider(module, testSpecProviderKey) {
+		if !ctx.ModuleHasProvider(module, TestSpecProviderKey) {
 			return
 		}
-		intermediateMetadataPaths = append(intermediateMetadataPaths, ctx.ModuleProvider(module, testSpecProviderKey).(testSpecProviderData).IntermediatePath)
+		intermediateMetadataPaths = append(intermediateMetadataPaths, ctx.ModuleProvider(module, TestSpecProviderKey).(TestSpecProviderData).IntermediatePath)
 	})
 
 	rspFile := android.PathForOutput(ctx, fileContainingFilePaths)
diff --git a/testing/test.go b/testing/test.go
new file mode 100644
index 0000000..44824e4
--- /dev/null
+++ b/testing/test.go
@@ -0,0 +1,21 @@
+// Copyright 2023 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 testing
+
+import (
+	"android/soong/android"
+)
+
+var PrepareForTestWithTestSpecBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
diff --git a/testing/test_spec.go b/testing/test_spec.go
index 1ad2768..c370f71 100644
--- a/testing/test_spec.go
+++ b/testing/test_spec.go
@@ -78,11 +78,11 @@
 }
 
 // Provider published by TestSpec
-type testSpecProviderData struct {
+type TestSpecProviderData struct {
 	IntermediatePath android.WritablePath
 }
 
-var testSpecProviderKey = blueprint.NewProvider(testSpecProviderData{})
+var TestSpecProviderKey = blueprint.NewProvider(TestSpecProviderData{})
 
 type TestModuleProviderData struct {
 }
@@ -120,7 +120,7 @@
 	android.WriteFileRule(ctx, intermediatePath, string(protoData))
 
 	ctx.SetProvider(
-		testSpecProviderKey, testSpecProviderData{
+		TestSpecProviderKey, TestSpecProviderData{
 			IntermediatePath: intermediatePath,
 		},
 	)