| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python | 
|  | 2 | # | 
|  | 3 | # Copyright (C) 2019 The Android Open Source Project | 
|  | 4 | # | 
|  | 5 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 6 | # you may not use this file except in compliance with the License. | 
|  | 7 | # You may obtain a copy of the License at | 
|  | 8 | # | 
|  | 9 | #      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 10 | # | 
|  | 11 | # Unless required by applicable law or agreed to in writing, software | 
|  | 12 | # distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 14 | # See the License for the specific language governing permissions and | 
|  | 15 | # limitations under the License. | 
|  | 16 | # | 
|  | 17 | """A tool for modifying values in a test config.""" | 
|  | 18 |  | 
|  | 19 | from __future__ import print_function | 
|  | 20 |  | 
|  | 21 | import argparse | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 22 | import json | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 23 | import sys | 
|  | 24 | from xml.dom import minidom | 
|  | 25 |  | 
|  | 26 |  | 
|  | 27 | from manifest import get_children_with_tag | 
|  | 28 | from manifest import parse_manifest | 
|  | 29 | from manifest import parse_test_config | 
|  | 30 | from manifest import write_xml | 
|  | 31 |  | 
| Rahul Sabnis | 48a8f0d | 2022-04-19 18:00:10 -0700 | [diff] [blame] | 32 | KNOWN_PREPARERS = ['com.android.tradefed.targetprep.TestAppInstallSetup', | 
|  | 33 | 'com.android.tradefed.targetprep.suite.SuiteApkInstaller'] | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 34 |  | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 35 | KNOWN_TEST_RUNNERS = ['com.android.tradefed.testtype.AndroidJUnitTest'] | 
|  | 36 |  | 
| Seth Moore | c6f4b53 | 2023-02-02 13:22:26 -0800 | [diff] [blame] | 37 | MAINLINE_CONTROLLER = 'com.android.tradefed.testtype.suite.module.MainlineTestModuleController' | 
|  | 38 |  | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 39 | def parse_args(): | 
|  | 40 | """Parse commandline arguments.""" | 
|  | 41 |  | 
|  | 42 | parser = argparse.ArgumentParser() | 
|  | 43 | parser.add_argument('--manifest', default='', dest='manifest', | 
|  | 44 | help=('AndroidManifest.xml that contains the original package name')) | 
|  | 45 | parser.add_argument('--package-name', default='', dest='package_name', | 
|  | 46 | help=('overwrite package fields in the test config')) | 
| Jaewoong Jung | 3998234 | 2020-01-14 10:27:18 -0800 | [diff] [blame] | 47 | parser.add_argument('--test-file-name', default='', dest='test_file_name', | 
|  | 48 | help=('overwrite test file name in the test config')) | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 49 | parser.add_argument('--orig-test-file-name', default='', dest='orig_test_file_name', | 
|  | 50 | help=('Use with test-file-name to only override a single apk')) | 
| Seth Moore | c6f4b53 | 2023-02-02 13:22:26 -0800 | [diff] [blame] | 51 | parser.add_argument('--mainline-package-name', default='', dest='mainline_package_name', | 
|  | 52 | help=('overwrite mainline module package name in the test config')) | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 53 | parser.add_argument('--test-runner-options', default='', dest='test_runner_options', | 
|  | 54 | help=('Add test runner options in the test config')) | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 55 | parser.add_argument('input', help='input test config file') | 
|  | 56 | parser.add_argument('output', help='output test config file') | 
|  | 57 | return parser.parse_args() | 
|  | 58 |  | 
|  | 59 |  | 
|  | 60 | def overwrite_package_name(test_config_doc, manifest_doc, package_name): | 
|  | 61 |  | 
|  | 62 | manifest = parse_manifest(manifest_doc) | 
|  | 63 | original_package = manifest.getAttribute('package') | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 64 |  | 
|  | 65 | test_config = parse_test_config(test_config_doc) | 
|  | 66 | tests = get_children_with_tag(test_config, 'test') | 
|  | 67 |  | 
|  | 68 | for test in tests: | 
|  | 69 | options = get_children_with_tag(test, 'option') | 
|  | 70 | for option in options: | 
|  | 71 | if option.getAttribute('name') == "package" and option.getAttribute('value') == original_package: | 
|  | 72 | option.setAttribute('value', package_name) | 
|  | 73 |  | 
| Jaewoong Jung | 3998234 | 2020-01-14 10:27:18 -0800 | [diff] [blame] | 74 | def overwrite_test_file_name(test_config_doc, test_file_name): | 
|  | 75 |  | 
|  | 76 | test_config = parse_test_config(test_config_doc) | 
|  | 77 | tests = get_children_with_tag(test_config, 'target_preparer') | 
|  | 78 |  | 
|  | 79 | for test in tests: | 
| Rahul Sabnis | 48a8f0d | 2022-04-19 18:00:10 -0700 | [diff] [blame] | 80 | if test.getAttribute('class') in KNOWN_PREPARERS: | 
| Jaewoong Jung | 3998234 | 2020-01-14 10:27:18 -0800 | [diff] [blame] | 81 | options = get_children_with_tag(test, 'option') | 
|  | 82 | for option in options: | 
|  | 83 | if option.getAttribute('name') == "test-file-name": | 
|  | 84 | option.setAttribute('value', test_file_name) | 
|  | 85 |  | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 86 | def overwrite_single_test_file_name(test_config_doc, orig_test_file_name, new_test_file_name): | 
|  | 87 |  | 
|  | 88 | test_config = parse_test_config(test_config_doc) | 
|  | 89 | tests = get_children_with_tag(test_config, 'target_preparer') | 
|  | 90 |  | 
|  | 91 | for test in tests: | 
|  | 92 | if test.getAttribute('class') in KNOWN_PREPARERS: | 
|  | 93 | options = get_children_with_tag(test, 'option') | 
|  | 94 | for option in options: | 
|  | 95 | if option.getAttribute('name') == "test-file-name" and option.getAttribute('value') == orig_test_file_name: | 
|  | 96 | option.setAttribute('value', new_test_file_name) | 
|  | 97 |  | 
| Seth Moore | c6f4b53 | 2023-02-02 13:22:26 -0800 | [diff] [blame] | 98 | def overwrite_mainline_module_package_name(test_config_doc, mainline_package_name): | 
|  | 99 |  | 
|  | 100 | test_config = parse_test_config(test_config_doc) | 
|  | 101 |  | 
|  | 102 | for obj in get_children_with_tag(test_config, 'object'): | 
|  | 103 | if obj.getAttribute('class') == MAINLINE_CONTROLLER: | 
|  | 104 | for option in get_children_with_tag(obj, 'option'): | 
|  | 105 | if option.getAttribute('name') == "mainline-module-package-name": | 
|  | 106 | option.setAttribute('value', mainline_package_name) | 
|  | 107 |  | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 108 | def add_test_runner_options_toplevel(test_config_doc, test_runner_options): | 
|  | 109 |  | 
|  | 110 | test_config = parse_test_config(test_config_doc) | 
|  | 111 |  | 
|  | 112 | test_config.appendChild(test_config_doc.createComment("Options from Android.bp")) | 
|  | 113 | test_config.appendChild(test_config_doc.createTextNode("\n")) | 
|  | 114 | for new_option in json.loads(test_runner_options): | 
|  | 115 | option = test_config_doc.createElement("option") | 
|  | 116 | # name and value are mandatory, | 
|  | 117 | name = new_option.get('Name') | 
|  | 118 | if not name: | 
|  | 119 | raise RuntimeError('"name" must set in test_runner_option"') | 
|  | 120 | value = new_option.get('Value') | 
|  | 121 | if not value: | 
|  | 122 | raise RuntimeError('"value" must set in test_runner_option"') | 
|  | 123 | option.setAttribute('name', name) # 'include-filter') | 
|  | 124 | option.setAttribute('value', value) # 'android.test.example.devcodelab.DevCodelabTest#testHelloFail') | 
|  | 125 | key = new_option.get('Key') | 
|  | 126 | if key: | 
|  | 127 | option.setAttribute('key', key) # 'include-filter') | 
|  | 128 | # add tab and newline for readability | 
|  | 129 | test_config.appendChild(test_config_doc.createTextNode("    ")) | 
|  | 130 | test_config.appendChild(option) | 
|  | 131 | test_config.appendChild(test_config_doc.createTextNode("\n")) | 
|  | 132 |  | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 133 | def main(): | 
|  | 134 | """Program entry point.""" | 
|  | 135 | try: | 
|  | 136 | args = parse_args() | 
|  | 137 |  | 
|  | 138 | doc = minidom.parse(args.input) | 
|  | 139 |  | 
|  | 140 | if args.package_name: | 
|  | 141 | if not args.manifest: | 
|  | 142 | raise RuntimeError('--manifest flag required for --package-name') | 
|  | 143 | manifest_doc = minidom.parse(args.manifest) | 
|  | 144 | overwrite_package_name(doc, manifest_doc, args.package_name) | 
|  | 145 |  | 
| Jaewoong Jung | 3998234 | 2020-01-14 10:27:18 -0800 | [diff] [blame] | 146 | if args.test_file_name: | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 147 | if args.orig_test_file_name: | 
|  | 148 | overwrite_single_test_file_name(doc, args.orig_test_file_name, args.test_file_name) | 
|  | 149 | else: | 
|  | 150 | # You probably never want to override the test_file_name if there | 
|  | 151 | # are several in the xml, but this is currently only used on generated | 
|  | 152 | # AndroidTest.xml where there is only a single test-file-name (no data) | 
|  | 153 | overwrite_test_file_name(doc, args.test_file_name) | 
| Jaewoong Jung | 3998234 | 2020-01-14 10:27:18 -0800 | [diff] [blame] | 154 |  | 
| Seth Moore | c6f4b53 | 2023-02-02 13:22:26 -0800 | [diff] [blame] | 155 | if args.mainline_package_name: | 
|  | 156 | overwrite_mainline_module_package_name(doc, args.mainline_package_name) | 
|  | 157 |  | 
| Ronald Braunstein | fce4316 | 2024-02-02 12:37:20 -0800 | [diff] [blame] | 158 | if args.test_runner_options: | 
|  | 159 | add_test_runner_options_toplevel(doc, args.test_runner_options) | 
|  | 160 |  | 
| Cole Faust | c41dd72 | 2021-11-09 15:08:26 -0800 | [diff] [blame] | 161 | with open(args.output, 'w') as f: | 
| Jaewoong Jung | e5cd4e1 | 2019-11-22 14:34:55 -0800 | [diff] [blame] | 162 | write_xml(f, doc) | 
|  | 163 |  | 
|  | 164 | # pylint: disable=broad-except | 
|  | 165 | except Exception as err: | 
|  | 166 | print('error: ' + str(err), file=sys.stderr) | 
|  | 167 | sys.exit(-1) | 
|  | 168 |  | 
|  | 169 | if __name__ == '__main__': | 
|  | 170 | main() |