Move autogenerated test config into Soong

Move autogenerating the test config for Soong modules into Soong
for java_test and android_test modules.

Bug: 70770641
Test: m checkbuild
Test: atest CtsUiRenderingTestCases
Change-Id: I02593add0407ef694b91c14cf27411a4f3cc4745
diff --git a/Android.bp b/Android.bp
index 83ec569..2f7b051 100644
--- a/Android.bp
+++ b/Android.bp
@@ -120,6 +120,7 @@
         "soong-android",
         "soong-cc-config",
         "soong-genrule",
+        "soong-tradefed",
     ],
     srcs: [
         "cc/androidmk.go",
@@ -218,6 +219,7 @@
         "soong-android",
         "soong-genrule",
         "soong-java-config",
+        "soong-tradefed",
     ],
     srcs: [
         "java/aapt2.go",
@@ -296,6 +298,21 @@
 }
 
 bootstrap_go_package {
+    name: "soong-tradefed",
+    pkgPath: "android/soong/tradefed",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "tradefed/autogen.go",
+        "tradefed/config.go",
+        "tradefed/makevars.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
+bootstrap_go_package {
     name: "soong-xml",
     pkgPath: "android/soong/xml",
     deps: [
diff --git a/cc/androidmk.go b/cc/androidmk.go
index c510d98..7595db1 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -250,9 +250,8 @@
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
 				strings.Join(benchmark.Properties.Test_suites, " "))
 		}
-		if benchmark.Properties.Test_config != nil {
-			fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=",
-				benchmark.Properties.Test_config)
+		if benchmark.testConfig != nil {
+			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", benchmark.testConfig.String())
 		}
 		fmt.Fprintln(w, "LOCAL_NATIVE_BENCHMARK := true")
 	})
@@ -272,9 +271,8 @@
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
 				strings.Join(test.Properties.Test_suites, " "))
 		}
-		if test.Properties.Test_config != nil {
-			fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=",
-				test.Properties.Test_config)
+		if test.testConfig != nil {
+			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String())
 		}
 	})
 
diff --git a/cc/test.go b/cc/test.go
index 49fc57b..b67341e 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -20,6 +20,7 @@
 	"strings"
 
 	"android/soong/android"
+	"android/soong/tradefed"
 )
 
 type TestProperties struct {
@@ -202,6 +203,7 @@
 	*baseCompiler
 	Properties TestBinaryProperties
 	data       android.Paths
+	testConfig android.Path
 }
 
 func (test *testBinary) linkerProps() []interface{} {
@@ -217,6 +219,7 @@
 
 func (test *testBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
 	android.ExtractSourcesDeps(ctx, test.Properties.Data)
+	android.ExtractSourceDeps(ctx, test.Properties.Test_config)
 
 	deps = test.testDecorator.linkerDeps(ctx, deps)
 	deps = test.binaryDecorator.linkerDeps(ctx, deps)
@@ -231,6 +234,7 @@
 
 func (test *testBinary) install(ctx ModuleContext, file android.Path) {
 	test.data = ctx.ExpandSources(test.Properties.Data, nil)
+	test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config)
 
 	test.binaryDecorator.baseInstaller.dir = "nativetest"
 	test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
@@ -319,6 +323,7 @@
 	*binaryDecorator
 	Properties BenchmarkProperties
 	data       android.Paths
+	testConfig android.Path
 }
 
 func (benchmark *benchmarkDecorator) linkerInit(ctx BaseModuleContext) {
@@ -338,6 +343,8 @@
 
 func (benchmark *benchmarkDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
 	android.ExtractSourcesDeps(ctx, benchmark.Properties.Data)
+	android.ExtractSourceDeps(ctx, benchmark.Properties.Test_config)
+
 	deps = benchmark.binaryDecorator.linkerDeps(ctx, deps)
 	deps.StaticLibs = append(deps.StaticLibs, "libgoogle-benchmark")
 	return deps
@@ -345,6 +352,8 @@
 
 func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) {
 	benchmark.data = ctx.ExpandSources(benchmark.Properties.Data, nil)
+	benchmark.testConfig = tradefed.AutoGenNativeBenchmarkTestConfig(ctx, benchmark.Properties.Test_config)
+
 	benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
 	benchmark.binaryDecorator.baseInstaller.install(ctx, file)
diff --git a/java/androidmk.go b/java/androidmk.go
index 544322e..4eae81e 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -106,10 +106,11 @@
 		if len(j.testProperties.Test_suites) > 0 {
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
 				strings.Join(j.testProperties.Test_suites, " "))
+		} else {
+			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
 		}
-		if j.testProperties.Test_config != nil {
-			fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=",
-				*j.testProperties.Test_config)
+		if j.testConfig != nil {
+			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", j.testConfig.String())
 		}
 	})
 
@@ -247,10 +248,11 @@
 		if len(a.testProperties.Test_suites) > 0 {
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
 				strings.Join(a.testProperties.Test_suites, " "))
+		} else {
+			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE := null-suite")
 		}
-		if a.testProperties.Test_config != nil {
-			fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=",
-				*a.testProperties.Test_config)
+		if a.testConfig != nil {
+			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", a.testConfig.String())
 		}
 	})
 
diff --git a/java/app.go b/java/app.go
index ef591b7..0ca7a2b 100644
--- a/java/app.go
+++ b/java/app.go
@@ -22,6 +22,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/tradefed"
 )
 
 func init() {
@@ -221,6 +222,8 @@
 	appTestProperties appTestProperties
 
 	testProperties testProperties
+
+	testConfig android.Path
 }
 
 func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -231,6 +234,13 @@
 	}
 
 	a.generateAndroidBuildActions(ctx)
+
+	a.testConfig = tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config, a.manifestPath)
+}
+
+func (a *AndroidTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	android.ExtractSourceDeps(ctx, a.testProperties.Test_config)
+	a.AndroidApp.DepsMutator(ctx)
 }
 
 func AndroidTestFactory() android.Module {
diff --git a/java/java.go b/java/java.go
index c912368..8fe4f35 100644
--- a/java/java.go
+++ b/java/java.go
@@ -29,6 +29,7 @@
 
 	"android/soong/android"
 	"android/soong/java/config"
+	"android/soong/tradefed"
 )
 
 func init() {
@@ -1362,6 +1363,14 @@
 	Library
 
 	testProperties testProperties
+
+	testConfig android.Path
+}
+
+func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config)
+
+	j.Library.GenerateAndroidBuildActions(ctx)
 }
 
 func (j *Test) DepsMutator(ctx android.BottomUpMutatorContext) {
@@ -1369,6 +1378,7 @@
 	if BoolDefault(j.testProperties.Junit, true) {
 		ctx.AddDependency(ctx.Module(), staticLibTag, "junit")
 	}
+	android.ExtractSourceDeps(ctx, j.testProperties.Test_config)
 }
 
 func TestFactory() android.Module {
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
new file mode 100644
index 0000000..dd2e355
--- /dev/null
+++ b/tradefed/autogen.go
@@ -0,0 +1,121 @@
+// Copyright 2018 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 tradefed
+
+import (
+	"strings"
+
+	"github.com/google/blueprint"
+
+	"android/soong/android"
+)
+
+func getTestConfig(ctx android.ModuleContext, prop *string) android.Path {
+	if p := ctx.ExpandOptionalSource(prop, "test_config"); p.Valid() {
+		return p.Path()
+	} else if p := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml"); p.Valid() {
+		return p.Path()
+	}
+	return nil
+}
+
+var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
+	Command:     "sed 's&{MODULE}&${name}&g' $template > $out",
+	CommandDeps: []string{"$template"},
+}, "name", "template")
+
+func testConfigPath(ctx android.ModuleContext, prop *string) (path android.Path, autogenPath android.WritablePath) {
+	if p := getTestConfig(ctx, prop); p != nil {
+		return p, nil
+	} else if !strings.HasPrefix(ctx.ModuleDir(), "cts/") {
+		outputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".config")
+
+		return outputFile, outputFile
+	} else {
+		// CTS modules can be used for test data, so test config files must be
+		// explicitly created using AndroidTest.xml
+		// TODO(b/112602712): remove the path check
+		return nil, nil
+	}
+}
+
+func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string) {
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        autogenTestConfig,
+		Description: "test config",
+		Output:      output,
+		Args: map[string]string{
+			"name":     ctx.ModuleName(),
+			"template": template,
+		},
+	})
+}
+
+func AutoGenNativeTestConfig(ctx android.ModuleContext, prop *string) android.Path {
+	path, autogenPath := testConfigPath(ctx, prop)
+	if autogenPath != nil {
+		if ctx.Device() {
+			autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}")
+		} else {
+			autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}")
+		}
+	}
+	return path
+}
+
+func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, prop *string) android.Path {
+	path, autogenPath := testConfigPath(ctx, prop)
+	if autogenPath != nil {
+		autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}")
+	}
+	return path
+}
+
+func AutoGenJavaTestConfig(ctx android.ModuleContext, prop *string) android.Path {
+	path, autogenPath := testConfigPath(ctx, prop)
+	if autogenPath != nil {
+		if ctx.Device() {
+			autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}")
+		} else {
+			autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}")
+		}
+	}
+	return path
+}
+
+var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
+	Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} ${InstrumentationTestConfigTemplate}",
+	CommandDeps: []string{
+		"${AutoGenTestConfigScript}",
+		"${EmptyTestConfig}",
+		"${InstrumentationTestConfigTemplate}",
+	},
+}, "name")
+
+func AutoGenInstrumentationTestConfig(ctx android.ModuleContext, prop *string, manifest android.Path) android.Path {
+	path, autogenPath := testConfigPath(ctx, prop)
+	if autogenPath != nil {
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        autogenInstrumentationTest,
+			Description: "test config",
+			Input:       manifest,
+			Output:      autogenPath,
+			Args: map[string]string{
+				"name": ctx.ModuleName(),
+			},
+		})
+	}
+	return path
+}
diff --git a/tradefed/config.go b/tradefed/config.go
new file mode 100644
index 0000000..2c432d0
--- /dev/null
+++ b/tradefed/config.go
@@ -0,0 +1,35 @@
+// Copyright 2018 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 tradefed
+
+import (
+	"android/soong/android"
+)
+
+var (
+	pctx = android.NewPackageContext("android/soong/tradefed")
+)
+
+func init() {
+	pctx.SourcePathVariable("AutoGenTestConfigScript", "build/make/tools/auto_gen_test_config.py")
+	pctx.SourcePathVariable("InstrumentationTestConfigTemplate", "build/make/core/instrumentation_test_config_template.xml")
+	pctx.SourcePathVariable("JavaTestConfigTemplate", "build/make/core/java_test_config_template.xml")
+	pctx.SourcePathVariable("JavaHostTestConfigTemplate", "build/make/core/java_host_test_config_template.xml")
+	pctx.SourcePathVariable("NativeBenchmarkTestConfigTemplate", "build/make/core/native_benchmark_test_config_template.xml")
+	pctx.SourcePathVariable("NativeHostTestConfigTemplate", "build/make/core/native_host_test_config_template.xml")
+	pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
+
+	pctx.SourcePathVariable("EmptyTestConfig", "build/make/core/empty_test_config.xml")
+}
diff --git a/tradefed/makevars.go b/tradefed/makevars.go
new file mode 100644
index 0000000..3ec7997
--- /dev/null
+++ b/tradefed/makevars.go
@@ -0,0 +1,35 @@
+// Copyright 2018 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 tradefed
+
+import (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
+}
+
+func makeVarsProvider(ctx android.MakeVarsContext) {
+	ctx.Strict("AUTOGEN_TEST_CONFIG_SCRIPT", "${AutoGenTestConfigScript}")
+	ctx.Strict("INSTRUMENTATION_TEST_CONFIG_TEMPLATE", "${InstrumentationTestConfigTemplate}")
+	ctx.Strict("JAVA_HOST_TEST_CONFIG_TEMPLATE", "${JavaHostTestConfigTemplate}")
+	ctx.Strict("JAVA_TEST_CONFIG_TEMPLATE", "${JavaTestConfigTemplate}")
+	ctx.Strict("NATIVE_BENCHMARK_TEST_CONFIG_TEMPLATE", "${NativeBenchmarkTestConfigTemplate}")
+	ctx.Strict("NATIVE_HOST_TEST_CONFIG_TEMPLATE", "${NativeHostTestConfigTemplate}")
+	ctx.Strict("NATIVE_TEST_CONFIG_TEMPLATE", "${NativeTestConfigTemplate}")
+
+	ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")
+}