Add support for CTS to ART run-tests running with TradeFed.

Introduce support for an (optional) test metadata file
(`test-metadata.json`), containing (optional) information about the
test suite(s) a test belongs to (in addition to the test suites
defined in `art-run-test-defaults`). If present, propagate that
information to the `test_suites` property of that ART run-test, and if
this property contains "cts", use a test configuration template
containing additional options to (also) make the test part of ART CTS.

Test: Together with CL adding `art-run-test-048-reflect-v8` to CTS:
        m cts \
          && cts-tradefed run commandAndExit cts \
               --module art-run-test-048-reflect-v8
Test: atest art-run-test-048-reflect-v8 --user-type secondary_user
Bug: 182167496
Change-Id: I2211aaffe6daee377a14e86e14945bb08dd2aa10
diff --git a/test/Android.bp b/test/Android.bp
index 2b7a1ba..c0a363e 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -469,7 +469,7 @@
     ],
 }
 
-// Same as above, but with a longer timeout.
+// Same as `art-run-test-target-template`, but with a longer timeout.
 filegroup {
     name: "art-run-test-target-slow-template",
     srcs: [
@@ -477,6 +477,15 @@
     ],
 }
 
+// Same as `art-run-test-target-template`, but contains additional
+// options to also make the test part of ART CTS.
+filegroup {
+    name: "art-run-test-target-cts-template",
+    srcs: [
+        "art-run-test-target-cts-template.xml",
+    ],
+}
+
 // Test configuration template for ART run-tests on target expected to run
 // successfully, and as such *not* tagged as part of TradeFed's
 // `art-target-run-test` test suite via the `test-suite-tag`. This is as
diff --git a/test/art-run-test-target-cts-template.xml b/test/art-run-test-target-cts-template.xml
new file mode 100644
index 0000000..4ce885c
--- /dev/null
+++ b/test/art-run-test-target-cts-template.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     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.
+-->
+<!-- Note: This test config for {MODULE} is generated from a template. -->
+<configuration description="Test module config for {MODULE}">
+    <option name="test-suite-tag" value="art-target-run-test" />
+    <option name="config-descriptor:metadata" key="mainline-param" value="com.google.android.art.apex" />
+
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <!-- TODO: Use option `push-file` instead of deprecated option
+             `push`. -->
+        <option name="push" value="{MODULE}.jar->/data/local/tmp/{MODULE}/{MODULE}.jar" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.ArtRunTest">
+        <option name="run-test-name" value="{MODULE}" />
+        <option name="classpath" value="/data/local/tmp/{MODULE}/{MODULE}.jar" />
+    </test>
+
+    <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
+         one of the Mainline modules below is present on the device used for testing. -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <!-- ART Mainline Module (internal version). -->
+        <option name="mainline-module-package-name" value="com.google.android.art" />
+        <!-- ART Mainline Module (external (AOSP) version). -->
+        <option name="mainline-module-package-name" value="com.android.art" />
+    </object>
+
+    <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. -->
+    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
+</configuration>
diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files
index eae2324..7ddffe6 100755
--- a/test/utils/regen-test-files
+++ b/test/utils/regen-test-files
@@ -435,16 +435,33 @@
     run_test_path = os.path.join(self.art_test_dir, run_test)
     bp_file = os.path.join(run_test_path, "Android.bp")
 
+    # Optional test metadata (JSON file).
+    metadata_file = os.path.join(run_test_path, "test-metadata.json")
+    metadata = {}
+    if os.path.exists(metadata_file):
+      with open(metadata_file, "r") as f:
+        metadata = json.load(f)
+
     run_test_module_name = ART_RUN_TEST_MODULE_NAME_PREFIX + run_test
 
+    # Set the test configuration template.
     if self.is_runnable(run_test):
-      if self.is_slow(run_test):
-        test_config_template= "art-run-test-target-slow-template"
+      if "cts" in metadata.get("test_suites", []):
+        test_config_template = "art-run-test-target-cts-template"
+      elif self.is_slow(run_test):
+        test_config_template = "art-run-test-target-slow-template"
       else:
         test_config_template = "art-run-test-target-template"
     else:
       test_config_template = "art-run-test-target-no-test-suite-tag-template"
 
+    # Define `test_suites`, if present in the test's metadata.
+    test_suites = ""
+    if metadata.get("test_suites"):
+      test_suites = f"""\
+
+          test_suites: {json.dumps(metadata.get("test_suites"))},"""
+
     if is_checker_test(run_test):
       include_src = """\
 
@@ -485,7 +502,7 @@
           data: [
               ":{run_test_module_name}-expected-stdout",
               ":{run_test_module_name}-expected-stderr",
-          ],{include_src}
+          ],{test_suites}{include_src}
       }}
 
       // Test's expected standard output.