Merge "Make auto_gen_test_config available to Bazel." into main
This commit is contained in:
@@ -82,3 +82,17 @@ python_binary_host {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@@ -26,3 +26,10 @@ py_binary(
|
|||||||
python_version = "PY3",
|
python_version = "PY3",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
py_binary(
|
||||||
|
name = "auto_gen_test_config",
|
||||||
|
srcs = ["auto_gen_test_config.py"],
|
||||||
|
python_version = "PY3",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
"""A tool to generate TradeFed test config file.
|
"""A tool to generate TradeFed test config file.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
@@ -44,9 +45,9 @@ def main(argv):
|
|||||||
"""
|
"""
|
||||||
if len(argv) != 4 and len(argv) != 6:
|
if len(argv) != 4 and len(argv) != 6:
|
||||||
sys.stderr.write(
|
sys.stderr.write(
|
||||||
'Invalid arguments. The script requires 4 arguments for file paths: '
|
f'Invalid arguments: {argv}. The script requires 4 arguments for file paths: '
|
||||||
'target_config android_manifest empty_config '
|
'target_config, android_manifest (or the xmltree dump), empty_config, '
|
||||||
'instrumentation_test_config_template '
|
'instrumentation_test_config_template, '
|
||||||
'and 2 optional arguments for extra configs: '
|
'and 2 optional arguments for extra configs: '
|
||||||
'--extra-configs \'EXTRA_CONFIGS\'.\n')
|
'--extra-configs \'EXTRA_CONFIGS\'.\n')
|
||||||
return 1
|
return 1
|
||||||
@@ -57,6 +58,41 @@ def main(argv):
|
|||||||
instrumentation_test_config_template = argv[3]
|
instrumentation_test_config_template = argv[3]
|
||||||
extra_configs = '\n'.join(argv[5].split('\\n')) if len(argv) == 6 else ''
|
extra_configs = '\n'.join(argv[5].split('\\n')) if len(argv) == 6 else ''
|
||||||
|
|
||||||
|
module = os.path.splitext(os.path.basename(target_config))[0]
|
||||||
|
|
||||||
|
# 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
|
||||||
|
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)
|
manifest = parse(android_manifest)
|
||||||
instrumentation_elements = manifest.getElementsByTagName('instrumentation')
|
instrumentation_elements = manifest.getElementsByTagName('instrumentation')
|
||||||
manifest_elements = manifest.getElementsByTagName('manifest')
|
manifest_elements = manifest.getElementsByTagName('manifest')
|
||||||
@@ -66,7 +102,6 @@ def main(argv):
|
|||||||
shutil.copyfile(empty_config, target_config)
|
shutil.copyfile(empty_config, target_config)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
module = os.path.splitext(os.path.basename(target_config))[0]
|
|
||||||
instrumentation = instrumentation_elements[0]
|
instrumentation = instrumentation_elements[0]
|
||||||
manifest = manifest_elements[0]
|
manifest = manifest_elements[0]
|
||||||
if ATTRIBUTE_LABEL in instrumentation.attributes:
|
if ATTRIBUTE_LABEL in instrumentation.attributes:
|
||||||
@@ -75,6 +110,7 @@ def main(argv):
|
|||||||
label = module
|
label = module
|
||||||
runner = instrumentation.attributes[ATTRIBUTE_RUNNER].value
|
runner = instrumentation.attributes[ATTRIBUTE_RUNNER].value
|
||||||
package = manifest.attributes[ATTRIBUTE_PACKAGE].value
|
package = manifest.attributes[ATTRIBUTE_PACKAGE].value
|
||||||
|
|
||||||
test_type = ('InstrumentationTest'
|
test_type = ('InstrumentationTest'
|
||||||
if runner.endswith('.InstrumentationTestRunner')
|
if runner.endswith('.InstrumentationTestRunner')
|
||||||
else 'AndroidJUnitTest')
|
else 'AndroidJUnitTest')
|
||||||
|
@@ -30,6 +30,24 @@ MANIFEST_INVALID = """<?xml version="1.0" encoding="utf-8"?>
|
|||||||
</manifest>
|
</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_JUNIT_TEST = """<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.android.my.tests.x">
|
package="com.android.my.tests.x">
|
||||||
@@ -45,12 +63,12 @@ MANIFEST_INSTRUMENTATION_TEST = """<?xml version="1.0" encoding="utf-8"?>
|
|||||||
<instrumentation
|
<instrumentation
|
||||||
android:name="android.test.InstrumentationTestRunner"
|
android:name="android.test.InstrumentationTestRunner"
|
||||||
android:targetPackage="com.android.my.tests"
|
android:targetPackage="com.android.my.tests"
|
||||||
android:label="My Tests" />
|
android:label="TestModule" />
|
||||||
</manifest>
|
</manifest>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXPECTED_JUNIT_TEST_CONFIG = """<?xml version="1.0" encoding="utf-8"?>
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -66,19 +84,23 @@ EXPECTED_JUNIT_TEST_CONFIG = """<?xml version="1.0" encoding="utf-8"?>
|
|||||||
-->
|
-->
|
||||||
<!-- This test config file is auto-generated. -->
|
<!-- This test config file is auto-generated. -->
|
||||||
<configuration description="Runs TestModule.">
|
<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">
|
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||||
|
<option name="cleanup-apks" value="true" />
|
||||||
<option name="test-file-name" value="TestModule.apk" />
|
<option name="test-file-name" value="TestModule.apk" />
|
||||||
</target_preparer>
|
</target_preparer>
|
||||||
|
|
||||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
<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" />
|
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
|
||||||
</test>
|
</test>
|
||||||
</configuration>
|
</configuration>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
EXPECTED_INSTRUMENTATION_TEST_CONFIG = """<?xml version="1.0" encoding="utf-8"?>
|
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");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -93,23 +115,74 @@ EXPECTED_INSTRUMENTATION_TEST_CONFIG = """<?xml version="1.0" encoding="utf-8"?>
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
-->
|
-->
|
||||||
<!-- This test config file is auto-generated. -->
|
<!-- 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">
|
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||||
|
<option name="cleanup-apks" value="true" />
|
||||||
<option name="test-file-name" value="TestModule.apk" />
|
<option name="test-file-name" value="TestModule.apk" />
|
||||||
</target_preparer>
|
</target_preparer>
|
||||||
|
|
||||||
<test class="com.android.tradefed.testtype.InstrumentationTest" >
|
<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" />
|
<option name="runner" value="android.test.InstrumentationTestRunner" />
|
||||||
</test>
|
</test>
|
||||||
</configuration>
|
</configuration>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
TOOLS_DIR = os.path.dirname(os.path.dirname(__file__))
|
EMPTY_TEST_CONFIG_CONTENT = """<?xml version="1.0" encoding="utf-8"?>
|
||||||
EMPTY_TEST_CONFIG = os.path.join(
|
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||||
TOOLS_DIR, '..', 'core', 'empty_test_config.xml')
|
|
||||||
INSTRUMENTATION_TEST_CONFIG_TEMPLATE = os.path.join(
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
TOOLS_DIR, '..', 'core', 'instrumentation_test_config_template.xml')
|
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):
|
class AutoGenTestConfigUnittests(unittest.TestCase):
|
||||||
@@ -120,6 +193,16 @@ class AutoGenTestConfigUnittests(unittest.TestCase):
|
|||||||
self.test_dir = tempfile.mkdtemp()
|
self.test_dir = tempfile.mkdtemp()
|
||||||
self.config_file = os.path.join(self.test_dir, TEST_MODULE + '.config')
|
self.config_file = os.path.join(self.test_dir, TEST_MODULE + '.config')
|
||||||
self.manifest_file = os.path.join(self.test_dir, 'AndroidManifest.xml')
|
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):
|
def tearDown(self):
|
||||||
"""Cleanup the test directory."""
|
"""Cleanup the test directory."""
|
||||||
@@ -133,11 +216,11 @@ class AutoGenTestConfigUnittests(unittest.TestCase):
|
|||||||
|
|
||||||
argv = [self.config_file,
|
argv = [self.config_file,
|
||||||
self.manifest_file,
|
self.manifest_file,
|
||||||
EMPTY_TEST_CONFIG,
|
self.empty_test_config_file,
|
||||||
INSTRUMENTATION_TEST_CONFIG_TEMPLATE]
|
self.instrumentation_test_config_template_file]
|
||||||
auto_gen_test_config.main(argv)
|
auto_gen_test_config.main(argv)
|
||||||
with open(self.config_file) as config_file:
|
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())
|
self.assertEqual(config_file.read(), empty_config.read())
|
||||||
|
|
||||||
def testCreateJUnitTestConfig(self):
|
def testCreateJUnitTestConfig(self):
|
||||||
@@ -148,8 +231,8 @@ class AutoGenTestConfigUnittests(unittest.TestCase):
|
|||||||
|
|
||||||
argv = [self.config_file,
|
argv = [self.config_file,
|
||||||
self.manifest_file,
|
self.manifest_file,
|
||||||
EMPTY_TEST_CONFIG,
|
self.empty_test_config_file,
|
||||||
INSTRUMENTATION_TEST_CONFIG_TEMPLATE]
|
self.instrumentation_test_config_template_file]
|
||||||
auto_gen_test_config.main(argv)
|
auto_gen_test_config.main(argv)
|
||||||
with open(self.config_file) as config_file:
|
with open(self.config_file) as config_file:
|
||||||
self.assertEqual(config_file.read(), EXPECTED_JUNIT_TEST_CONFIG)
|
self.assertEqual(config_file.read(), EXPECTED_JUNIT_TEST_CONFIG)
|
||||||
@@ -162,8 +245,37 @@ class AutoGenTestConfigUnittests(unittest.TestCase):
|
|||||||
|
|
||||||
argv = [self.config_file,
|
argv = [self.config_file,
|
||||||
self.manifest_file,
|
self.manifest_file,
|
||||||
EMPTY_TEST_CONFIG,
|
self.empty_test_config_file,
|
||||||
INSTRUMENTATION_TEST_CONFIG_TEMPLATE]
|
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)
|
auto_gen_test_config.main(argv)
|
||||||
with open(self.config_file) as config_file:
|
with open(self.config_file) as config_file:
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
Reference in New Issue
Block a user