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 19import argparse 20import json 21import sys 22from xml.dom import minidom 23 24 25from manifest import get_children_with_tag 26from manifest import parse_manifest 27from manifest import parse_test_config 28from manifest import write_xml 29 30KNOWN_PREPARERS = ['com.android.tradefed.targetprep.TestAppInstallSetup', 31 'com.android.tradefed.targetprep.suite.SuiteApkInstaller'] 32 33KNOWN_TEST_RUNNERS = ['com.android.tradefed.testtype.AndroidJUnitTest'] 34 35MAINLINE_CONTROLLER = 'com.android.tradefed.testtype.suite.module.MainlineTestModuleController' 36 37def parse_args(): 38 """Parse commandline arguments.""" 39 40 parser = argparse.ArgumentParser() 41 parser.add_argument('--manifest', default='', dest='manifest', 42 help=('AndroidManifest.xml that contains the original package name')) 43 parser.add_argument('--package-name', default='', dest='package_name', 44 help=('overwrite package fields in the test config')) 45 parser.add_argument('--test-file-name', default='', dest='test_file_name', 46 help=('overwrite test file name in the test config')) 47 parser.add_argument('--orig-test-file-name', default='', dest='orig_test_file_name', 48 help=('Use with test-file-name to only override a single apk')) 49 parser.add_argument('--mainline-package-name', default='', dest='mainline_package_name', 50 help=('overwrite mainline module package name in the test config')) 51 parser.add_argument('--test-runner-options', default='', dest='test_runner_options', 52 help=('Add test runner options in the test config')) 53 parser.add_argument('input', help='input test config file') 54 parser.add_argument('output', help='output test config file') 55 return parser.parse_args() 56 57 58def overwrite_package_name(test_config_doc, manifest_doc, package_name): 59 60 manifest = parse_manifest(manifest_doc) 61 original_package = manifest.getAttribute('package') 62 63 test_config = parse_test_config(test_config_doc) 64 tests = get_children_with_tag(test_config, 'test') 65 66 for test in tests: 67 options = get_children_with_tag(test, 'option') 68 for option in options: 69 if option.getAttribute('name') == "package" and option.getAttribute('value') == original_package: 70 option.setAttribute('value', package_name) 71 72def overwrite_test_file_name(test_config_doc, test_file_name): 73 74 test_config = parse_test_config(test_config_doc) 75 tests = get_children_with_tag(test_config, 'target_preparer') 76 77 for test in tests: 78 if test.getAttribute('class') in KNOWN_PREPARERS: 79 options = get_children_with_tag(test, 'option') 80 for option in options: 81 if option.getAttribute('name') == "test-file-name": 82 option.setAttribute('value', test_file_name) 83 84def overwrite_single_test_file_name(test_config_doc, orig_test_file_name, new_test_file_name): 85 86 test_config = parse_test_config(test_config_doc) 87 tests = get_children_with_tag(test_config, 'target_preparer') 88 89 for test in tests: 90 if test.getAttribute('class') in KNOWN_PREPARERS: 91 options = get_children_with_tag(test, 'option') 92 for option in options: 93 if option.getAttribute('name') == "test-file-name" and option.getAttribute('value') == orig_test_file_name: 94 option.setAttribute('value', new_test_file_name) 95 96def overwrite_mainline_module_package_name(test_config_doc, mainline_package_name): 97 98 test_config = parse_test_config(test_config_doc) 99 100 for obj in get_children_with_tag(test_config, 'object'): 101 if obj.getAttribute('class') == MAINLINE_CONTROLLER: 102 for option in get_children_with_tag(obj, 'option'): 103 if option.getAttribute('name') == "mainline-module-package-name": 104 option.setAttribute('value', mainline_package_name) 105 106def add_test_runner_options_toplevel(test_config_doc, test_runner_options): 107 108 test_config = parse_test_config(test_config_doc) 109 110 test_config.appendChild(test_config_doc.createComment("Options from Android.bp")) 111 test_config.appendChild(test_config_doc.createTextNode("\n")) 112 for new_option in json.loads(test_runner_options): 113 option = test_config_doc.createElement("option") 114 # name and value are mandatory, 115 name = new_option.get('Name') 116 if not name: 117 raise RuntimeError('"name" must set in test_runner_option"') 118 value = new_option.get('Value') 119 if not value: 120 raise RuntimeError('"value" must set in test_runner_option"') 121 option.setAttribute('name', name) # 'include-filter') 122 option.setAttribute('value', value) # 'android.test.example.devcodelab.DevCodelabTest#testHelloFail') 123 key = new_option.get('Key') 124 if key: 125 option.setAttribute('key', key) # 'include-filter') 126 # add tab and newline for readability 127 test_config.appendChild(test_config_doc.createTextNode(" ")) 128 test_config.appendChild(option) 129 test_config.appendChild(test_config_doc.createTextNode("\n")) 130 131def main(): 132 """Program entry point.""" 133 try: 134 args = parse_args() 135 136 doc = minidom.parse(args.input) 137 138 if args.package_name: 139 if not args.manifest: 140 raise RuntimeError('--manifest flag required for --package-name') 141 manifest_doc = minidom.parse(args.manifest) 142 overwrite_package_name(doc, manifest_doc, args.package_name) 143 144 if args.test_file_name: 145 if args.orig_test_file_name: 146 overwrite_single_test_file_name(doc, args.orig_test_file_name, args.test_file_name) 147 else: 148 # You probably never want to override the test_file_name if there 149 # are several in the xml, but this is currently only used on generated 150 # AndroidTest.xml where there is only a single test-file-name (no data) 151 overwrite_test_file_name(doc, args.test_file_name) 152 153 if args.mainline_package_name: 154 overwrite_mainline_module_package_name(doc, args.mainline_package_name) 155 156 if args.test_runner_options: 157 add_test_runner_options_toplevel(doc, args.test_runner_options) 158 159 with open(args.output, 'w') as f: 160 write_xml(f, doc) 161 162 # pylint: disable=broad-except 163 except Exception as err: 164 print('error: ' + str(err), file=sys.stderr) 165 sys.exit(-1) 166 167if __name__ == '__main__': 168 main() 169