1import json 2import os 3import re 4import shutil 5import subprocess 6from xml.dom import minidom 7from xml.etree import ElementTree 8 9 10SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__)) 11TEST_JSON = 'tests.json' 12TEST_JSON_PATH = os.path.join(SCRIPT_DIR, TEST_JSON) 13 14 15def write_one_cc_test(test_details, f): 16 stringified_sources = map(lambda s: f'"{s}"', test_details['srcs']) 17 stringified_data = map(lambda s: f'"{s}"', test_details.get('data', [])) 18 stringified_cflags = map(lambda s: f'"{s}"', test_details.get('cflags', [])) 19 20 default = "ocl-test-defaults" 21 if test_details.get('image_type', False): 22 default = "ocl-test-image-defaults" 23 24 rtti = test_details.get('rtti', False) 25 26 cc_test_string = """ 27cc_test {{ 28 name: "{}", 29 srcs: [ {} ], 30 data: [ {} ], 31 cflags: [ {} ], 32 defaults: [ "{}" ], 33 rtti: {}, 34 gtest: false 35}} 36 37""".format(test_details['binary_name'], 38 ", ".join(stringified_sources), 39 ", ".join(stringified_data), 40 ", ".join(stringified_cflags), 41 default, 42 (str(rtti)).lower()) 43 44 empty_field_regex = re.compile("^\s*\w+: \[\s*\],?$") 45 cc_test_string = '\n'.join([line for line in cc_test_string.split('\n') 46 if not empty_field_regex.match(line)]) 47 f.write(cc_test_string) 48 49 50# Return value indicates whether the output should be formatted with bpfmt 51def generate_android_bp() -> bool: 52 android_bp_head_path = os.path.join(SCRIPT_DIR, 'android_bp_head') 53 android_bp_tail_path = os.path.join(SCRIPT_DIR, 'android_bp_tail') 54 55 with open('Android.bp', 'w') as android_bp: 56 with open(android_bp_head_path, 'r') as android_bp_head: 57 android_bp.write(android_bp_head.read()) 58 59 with open(TEST_JSON_PATH) as f: 60 tests = json.load(f) 61 for test in tests: 62 write_one_cc_test(test, android_bp) 63 64 with open(android_bp_tail_path, 'r') as android_bp_tail: 65 android_bp.write(android_bp_tail.read()) 66 67 if shutil.which('bpfmt') is not None: 68 subprocess.run(['bpfmt', '-w', 'Android.bp']) 69 return True 70 71 return False 72 73 74def create_subelement_with_attribs(element, tag, attribs): 75 subelement = ElementTree.SubElement(element, tag) 76 77 for key, value in attribs.items(): 78 subelement.attrib[key] = value 79 80 return subelement 81 82 83def generate_push_file_rules(configuration): 84 create_subelement_with_attribs(configuration, 'target_preparer', 85 { 'class': "com.android.tradefed.targetprep.RootTargetPreparer" }) 86 file_pusher = create_subelement_with_attribs(configuration, 'target_preparer', 87 { 'class': "com.android.compatibility.common.tradefed.targetprep.FilePusher" }) 88 create_subelement_with_attribs(file_pusher, 'option', 89 { 'name': "cleanup", 'value': "true" }) 90 create_subelement_with_attribs(file_pusher, 'option', 91 { 'name': "append-bitness", 'value': "true" }) 92 93 with open(TEST_JSON_PATH, "r") as f: 94 tests = json.load(f) 95 96 for test in tests: 97 if test.get('manual_only', False): 98 continue 99 100 create_subelement_with_attribs(file_pusher, 'option', 101 { 102 'name': "push-file", 103 'key': test['binary_name'], 104 'value': "/data/nativetest64/unrestricted/{}".format(test['binary_name']) 105 }) 106 107 108def generate_test_rules(configuration): 109 with open(TEST_JSON_PATH, "r") as f: 110 tests = json.load(f) 111 112 for test in tests: 113 if test.get('manual_only', False): 114 continue 115 116 test_rule = create_subelement_with_attribs(configuration, 'test', 117 { 'class': "com.android.tradefed.testtype.python.PythonBinaryHostTest" }) 118 119 create_subelement_with_attribs(test_rule, 'option', 120 { 'name': "par-file-name", 'value': "opencl_cts" }) 121 create_subelement_with_attribs(test_rule, 'option', 122 { 'name': "inject-android-serial", 'value': "true" }) 123 create_subelement_with_attribs(test_rule, 'option', 124 { 'name': "test-timeout", 'value': test.get('timeout', "30m") }) 125 create_subelement_with_attribs(test_rule, 'option', 126 { 'name': "python-options", 'value': test["test_name"] }) 127 create_subelement_with_attribs(test_rule, 'option', 128 { 'name': "python-options", 129 'value': "/data/nativetest64/unrestricted/{}".format(test['binary_name']) }) 130 131 for arg in test.get('arguments', []): 132 create_subelement_with_attribs(test_rule, 'option', 133 { 'name': "python-options", 'value': arg }) 134 135 136def generate_test_xml(): 137 configuration = ElementTree.Element('configuration') 138 configuration.attrib['description'] = "Config to run OpenCL CTS" 139 140 logcat = ElementTree.SubElement(configuration, 'option') 141 logcat.attrib['name'] = "logcat-on-failure" 142 logcat.attrib['value'] = "false" 143 144 generate_push_file_rules(configuration) 145 generate_test_rules(configuration) 146 147 stringified_configuration = ElementTree.tostring(configuration, 'utf-8') 148 reparsed_configuration = minidom.parseString(stringified_configuration) 149 with open('test_opencl_cts.xml', 'w') as f: 150 f.write(reparsed_configuration.toprettyxml(indent=" "*4)) 151 152 153def main(): 154 android_bp_formatted = generate_android_bp() 155 generate_test_xml() 156 157 print("Don't forget to move -") 158 print(" Android.bp -> {ANDROID_ROOT}/external/OpenCL-CTS/Android.bp") 159 print(" test_opencl_cts.xml -> {ANDROID_ROOT}/external/OpenCL-CTS/scripts/test_opencl_cts.xml") 160 if not android_bp_formatted: 161 print("then run the blueprint autoformatter:") 162 print(" bpfmt -w {ANDROID_ROOT}/external/OpenCL-CTS/Android.bp") 163 164 165if __name__ == '__main__': 166 main() 167