Make auto_gen_test_config available to Bazel.

In the Bazel rule, the actual AndroidManifest.xml file isn't available
in the providers of the android_binary dependency. And for good reason,
we should also rely on aapt2 to dump the manifest contents from the
final packaged APK anyway, but this auto gen script doesn't support
reading the output of aapt2 dump.

This CL adds a simple reader of the output of `aapt2 dump xmltree`, and
enabled if the xmltree content is passed to this tool instead of
AndroidManifest.xml.

Also fixup auto_gen_test_config_test.py. The test was completely failing.

Test: atest auto_gen_test_config_test
Test: presubmits

Change-Id: I7fecd927d0ed7847b6463d964b3698f4164b0177
This commit is contained in:
Jingwen Chen
2023-09-18 07:19:11 +00:00
parent 5922b630c5
commit f3406e64f7
4 changed files with 208 additions and 39 deletions

View File

@@ -17,6 +17,7 @@
"""A tool to generate TradeFed test config file.
"""
import re
import os
import shutil
import sys
@@ -44,9 +45,9 @@ def main(argv):
"""
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 @@ def main(argv):
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()