Merge "Make auto_gen_test_config available to Bazel." into main
diff --git a/tools/Android.bp b/tools/Android.bp
index bea0602..b8ab162 100644
--- a/tools/Android.bp
+++ b/tools/Android.bp
@@ -82,3 +82,17 @@
}
}
}
+
+python_test_host {
+ name: "auto_gen_test_config_test",
+ main: "auto_gen_test_config_test.py",
+ srcs: [
+ "auto_gen_test_config.py",
+ "auto_gen_test_config_test.py",
+ ],
+ auto_gen_config: true,
+ test_suites: ["general-tests"],
+ test_options: {
+ unit_test: true,
+ },
+}
diff --git a/tools/BUILD.bazel b/tools/BUILD.bazel
index 2dbb585..9ec0dce 100644
--- a/tools/BUILD.bazel
+++ b/tools/BUILD.bazel
@@ -26,3 +26,10 @@
python_version = "PY3",
visibility = ["//visibility:public"],
)
+
+py_binary(
+ name = "auto_gen_test_config",
+ srcs = ["auto_gen_test_config.py"],
+ python_version = "PY3",
+ visibility = ["//visibility:public"],
+)
diff --git a/tools/auto_gen_test_config.py b/tools/auto_gen_test_config.py
index ce64160..0bf47c6 100755
--- a/tools/auto_gen_test_config.py
+++ b/tools/auto_gen_test_config.py
@@ -17,6 +17,7 @@
"""A tool to generate TradeFed test config file.
"""
+import re
import os
import shutil
import sys
@@ -44,9 +45,9 @@
"""
if len(argv) != 4 and len(argv) != 6:
sys.stderr.write(
- 'Invalid arguments. The script requires 4 arguments for file paths: '
- 'target_config android_manifest empty_config '
- 'instrumentation_test_config_template '
+ f'Invalid arguments: {argv}. The script requires 4 arguments for file paths: '
+ 'target_config, android_manifest (or the xmltree dump), empty_config, '
+ 'instrumentation_test_config_template, '
'and 2 optional arguments for extra configs: '
'--extra-configs \'EXTRA_CONFIGS\'.\n')
return 1
@@ -57,27 +58,62 @@
instrumentation_test_config_template = argv[3]
extra_configs = '\n'.join(argv[5].split('\\n')) if len(argv) == 6 else ''
- manifest = parse(android_manifest)
- instrumentation_elements = manifest.getElementsByTagName('instrumentation')
- manifest_elements = manifest.getElementsByTagName('manifest')
- if len(instrumentation_elements) != 1 or len(manifest_elements) != 1:
- # Failed to locate instrumentation or manifest element in AndroidManifest.
- # file. Empty test config file will be created.
- shutil.copyfile(empty_config, target_config)
- return 0
-
module = os.path.splitext(os.path.basename(target_config))[0]
- instrumentation = instrumentation_elements[0]
- manifest = manifest_elements[0]
- if ATTRIBUTE_LABEL in instrumentation.attributes:
- label = instrumentation.attributes[ATTRIBUTE_LABEL].value
- else:
+
+ # If the AndroidManifest.xml is not available, but the APK is, this tool also
+ # accepts the output of `aapt2 dump xmltree <apk> AndroidManifest.xml` written
+ # into a file. This is a custom structured aapt2 output - not raw XML!
+ if android_manifest.endswith(".xmltree"):
label = module
- runner = instrumentation.attributes[ATTRIBUTE_RUNNER].value
- package = manifest.attributes[ATTRIBUTE_PACKAGE].value
+ with open(android_manifest, encoding="utf-8") as manifest:
+ # e.g. A: package="android.test.example.helloworld" (Raw: "android.test.example.helloworld")
+ # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ pattern = re.compile(r"\(Raw:\s\"(.*)\"\)$")
+ curr_element = None
+ for line in manifest.readlines():
+ curr_line = line.strip()
+ if curr_line.startswith("E:"):
+ # e.g. "E: instrumentation (line=9)"
+ # ^^^^^^^^^^^^^^^
+ curr_element = curr_line.split(" ")[1]
+ if curr_element == "instrumentation":
+ if ATTRIBUTE_RUNNER in curr_line:
+ runner = re.findall(pattern, curr_line)[0]
+ if ATTRIBUTE_LABEL in curr_line:
+ label = re.findall(pattern, curr_line)[0]
+ if curr_element == "manifest":
+ if ATTRIBUTE_PACKAGE in curr_line:
+ package = re.findall(pattern, curr_line)[0]
+
+ if not (runner and label and package):
+ # Failed to locate instrumentation or manifest element in AndroidManifest.
+ # file. Empty test config file will be created.
+ shutil.copyfile(empty_config, target_config)
+ return 0
+
+ else:
+ # If the AndroidManifest.xml file is directly available, read it as an XML file.
+ manifest = parse(android_manifest)
+ instrumentation_elements = manifest.getElementsByTagName('instrumentation')
+ manifest_elements = manifest.getElementsByTagName('manifest')
+ if len(instrumentation_elements) != 1 or len(manifest_elements) != 1:
+ # Failed to locate instrumentation or manifest element in AndroidManifest.
+ # file. Empty test config file will be created.
+ shutil.copyfile(empty_config, target_config)
+ return 0
+
+ instrumentation = instrumentation_elements[0]
+ manifest = manifest_elements[0]
+ if ATTRIBUTE_LABEL in instrumentation.attributes:
+ label = instrumentation.attributes[ATTRIBUTE_LABEL].value
+ else:
+ label = module
+ runner = instrumentation.attributes[ATTRIBUTE_RUNNER].value
+ package = manifest.attributes[ATTRIBUTE_PACKAGE].value
+
test_type = ('InstrumentationTest'
- if runner.endswith('.InstrumentationTestRunner')
- else 'AndroidJUnitTest')
+ if runner.endswith('.InstrumentationTestRunner')
+ else 'AndroidJUnitTest')
with open(instrumentation_test_config_template) as template:
config = template.read()
diff --git a/tools/auto_gen_test_config_test.py b/tools/auto_gen_test_config_test.py
index 51a8583..ce97723 100644
--- a/tools/auto_gen_test_config_test.py
+++ b/tools/auto_gen_test_config_test.py
@@ -30,6 +30,24 @@
</manifest>
"""
+XMLTREE_JUNIT_TEST = """N: android=http://schemas.android.com/apk/res/android (line=2)
+ E: manifest (line=2)
+ A: package="com.android.my.tests.x" (Raw: "com.android.my.tests.x")
+ E: instrumentation (line=9)
+ A: http://schemas.android.com/apk/res/android:label(0x01010001)="TestModule" (Raw: "TestModule")
+ A: http://schemas.android.com/apk/res/android:name(0x01010003)="androidx.test.runner.AndroidJUnitRunner" (Raw: "androidx.test.runner.AndroidJUnitRunner")
+ A: http://schemas.android.com/apk/res/android:targetPackage(0x01010021)="com.android.my.tests" (Raw: "com.android.my.tests")
+"""
+
+XMLTREE_INSTRUMENTATION_TEST = """N: android=http://schemas.android.com/apk/res/android (line=2)
+ E: manifest (line=2)
+ A: package="com.android.my.tests.x" (Raw: "com.android.my.tests.x")
+ E: instrumentation (line=9)
+ A: http://schemas.android.com/apk/res/android:label(0x01010001)="TestModule" (Raw: "TestModule")
+ A: http://schemas.android.com/apk/res/android:name(0x01010003)="android.test.InstrumentationTestRunner" (Raw: "android.test.InstrumentationTestRunner")
+ A: http://schemas.android.com/apk/res/android:targetPackage(0x01010021)="com.android.my.tests" (Raw: "com.android.my.tests")
+"""
+
MANIFEST_JUNIT_TEST = """<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.my.tests.x">
@@ -45,12 +63,12 @@
<instrumentation
android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.android.my.tests"
- android:label="My Tests" />
+ android:label="TestModule" />
</manifest>
"""
EXPECTED_JUNIT_TEST_CONFIG = """<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2023 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.
@@ -66,19 +84,23 @@
-->
<!-- This test config file is auto-generated. -->
<configuration description="Runs TestModule.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="TestModule.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="com.android.my.tests.x" />
+ {EXTRA_TEST_RUNNER_CONFIGS}<option name="package" value="com.android.my.tests.x" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
"""
EXPECTED_INSTRUMENTATION_TEST_CONFIG = """<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2023 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.
@@ -93,23 +115,74 @@
limitations under the License.
-->
<!-- This test config file is auto-generated. -->
-<configuration description="Runs My Tests.">
+<configuration description="Runs TestModule.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
<option name="test-file-name" value="TestModule.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.InstrumentationTest" >
- <option name="package" value="com.android.my.tests.x" />
+ {EXTRA_TEST_RUNNER_CONFIGS}<option name="package" value="com.android.my.tests.x" />
<option name="runner" value="android.test.InstrumentationTestRunner" />
</test>
</configuration>
"""
-TOOLS_DIR = os.path.dirname(os.path.dirname(__file__))
-EMPTY_TEST_CONFIG = os.path.join(
- TOOLS_DIR, '..', 'core', 'empty_test_config.xml')
-INSTRUMENTATION_TEST_CONFIG_TEMPLATE = os.path.join(
- TOOLS_DIR, '..', 'core', 'instrumentation_test_config_template.xml')
+EMPTY_TEST_CONFIG_CONTENT = """<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 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.
+-->
+<!-- No AndroidTest.xml was provided and the manifest does not include
+ instrumentation, hence this apk is not instrumentable.
+-->
+<configuration description="Empty Configuration" />
+"""
+
+INSTRUMENTATION_TEST_CONFIG_TEMPLATE_CONTENT = """<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<!-- This test config file is auto-generated. -->
+<configuration description="Runs {LABEL}.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-instrumentation" />
+{EXTRA_CONFIGS}
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="{MODULE}.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.{TEST_TYPE}" >
+ {EXTRA_TEST_RUNNER_CONFIGS}<option name="package" value="{PACKAGE}" />
+ <option name="runner" value="{RUNNER}" />
+ </test>
+</configuration>
+"""
class AutoGenTestConfigUnittests(unittest.TestCase):
@@ -120,6 +193,16 @@
self.test_dir = tempfile.mkdtemp()
self.config_file = os.path.join(self.test_dir, TEST_MODULE + '.config')
self.manifest_file = os.path.join(self.test_dir, 'AndroidManifest.xml')
+ self.xmltree_file = os.path.join(self.test_dir, TEST_MODULE + '.xmltree')
+ self.empty_test_config_file = os.path.join(self.test_dir, 'empty.config')
+ self.instrumentation_test_config_template_file = os.path.join(
+ self.test_dir, 'instrumentation.config')
+
+ with open(self.empty_test_config_file, 'w') as f:
+ f.write(EMPTY_TEST_CONFIG_CONTENT)
+
+ with open(self.instrumentation_test_config_template_file, 'w') as f:
+ f.write(INSTRUMENTATION_TEST_CONFIG_TEMPLATE_CONTENT)
def tearDown(self):
"""Cleanup the test directory."""
@@ -133,11 +216,11 @@
argv = [self.config_file,
self.manifest_file,
- EMPTY_TEST_CONFIG,
- INSTRUMENTATION_TEST_CONFIG_TEMPLATE]
+ self.empty_test_config_file,
+ self.instrumentation_test_config_template_file]
auto_gen_test_config.main(argv)
with open(self.config_file) as config_file:
- with open(EMPTY_TEST_CONFIG) as empty_config:
+ with open(self.empty_test_config_file) as empty_config:
self.assertEqual(config_file.read(), empty_config.read())
def testCreateJUnitTestConfig(self):
@@ -148,8 +231,8 @@
argv = [self.config_file,
self.manifest_file,
- EMPTY_TEST_CONFIG,
- INSTRUMENTATION_TEST_CONFIG_TEMPLATE]
+ self.empty_test_config_file,
+ self.instrumentation_test_config_template_file]
auto_gen_test_config.main(argv)
with open(self.config_file) as config_file:
self.assertEqual(config_file.read(), EXPECTED_JUNIT_TEST_CONFIG)
@@ -162,8 +245,37 @@
argv = [self.config_file,
self.manifest_file,
- EMPTY_TEST_CONFIG,
- INSTRUMENTATION_TEST_CONFIG_TEMPLATE]
+ self.empty_test_config_file,
+ self.instrumentation_test_config_template_file]
+ auto_gen_test_config.main(argv)
+ with open(self.config_file) as config_file:
+ self.assertEqual(
+ config_file.read(), EXPECTED_INSTRUMENTATION_TEST_CONFIG)
+
+ def testCreateJUnitTestConfigWithXMLTree(self):
+ """Test creating test config for AndroidJUnitTest.
+ """
+ with open(self.xmltree_file, 'w') as f:
+ f.write(XMLTREE_JUNIT_TEST)
+
+ argv = [self.config_file,
+ self.xmltree_file,
+ self.empty_test_config_file,
+ self.instrumentation_test_config_template_file]
+ auto_gen_test_config.main(argv)
+ with open(self.config_file) as config_file:
+ self.assertEqual(config_file.read(), EXPECTED_JUNIT_TEST_CONFIG)
+
+ def testCreateInstrumentationTestConfigWithXMLTree(self):
+ """Test creating test config for InstrumentationTest.
+ """
+ with open(self.xmltree_file, 'w') as f:
+ f.write(XMLTREE_INSTRUMENTATION_TEST)
+
+ argv = [self.config_file,
+ self.xmltree_file,
+ self.empty_test_config_file,
+ self.instrumentation_test_config_template_file]
auto_gen_test_config.main(argv)
with open(self.config_file) as config_file:
self.assertEqual(