1#!/bin/sh 2"exec" "`dirname $0`/py3-cmd" "$0" "-c" "`dirname $0`/config.json" "$@" 3 4import argparse 5import logging 6import os 7from typing import List, Optional 8import sys 9 10 11import qemu 12import qemu_error 13 14__all__ = ["init", "run_test", "shutdown"] 15 16 17TRUSTY_PROJECT_FOLDER = os.path.dirname(os.path.realpath(__file__)) 18 19 20def init(*, android=None, instance_dir: os.PathLike, disable_rpmb=False, 21 verbose=False, debug_on_error=False 22) -> qemu.Runner: 23 24 with open(f"{TRUSTY_PROJECT_FOLDER}/config.json", encoding="utf-8") as json: 25 config = qemu.Config(json) 26 27 if android: 28 config.android_image_dir = qemu.find_android_image_dir(android) 29 config.adb = qemu.find_adb_path(android) 30 config.boot_android = True 31 32 runner = qemu.Runner(config, 33 interactive=False, 34 instance_dir=instance_dir, 35 verbose=verbose, 36 rpmb=not disable_rpmb, 37 debug=False, 38 debug_on_error=debug_on_error) 39 return runner 40 41 42def _check_args(args): 43 """Validate arguments passed to run_test.""" 44 assert args.headless, args 45 assert not args.linux, args 46 assert not args.initrd, args 47 assert not args.atf, args 48 assert not args.qemu, args 49 assert not args.arch, args 50 assert not args.debug, args 51 assert not args.extra_linux_args, args 52 assert not args.extra_qemu_flags, args 53 assert not args.disable_rpmb, args 54 55 56def _prepare_runner_for_test(runner, args): 57 """Check if the runner is in the correct state (BOOTLOADER, ANDROID) 58 to run a given test and reboot the emulator if it is not. 59 60 TODO: Remove the unconditional reboot after boot tests once the test harness 61 no longers requires it. 62 """ 63 if args.boot_test: 64 target_state = qemu.RunnerState.BOOTLOADER 65 elif args.shell_command or args.host_command: 66 target_state = qemu.RunnerState.ANDROID 67 else: 68 raise qemu_error.ConfigError( 69 "Command must request exactly one Android, boot test, or" 70 " host command to run" 71 ) 72 73 # Due to limitations in the test runner, always reboot between boot tests 74 if (runner.state != target_state or 75 runner.state == qemu.RunnerState.BOOTLOADER): 76 runner.reboot(target_state, factory_reset=True, full_wipe=False) 77 78def run_test(runner: qemu.Runner, cmd: List[str]) -> int: 79 args = build_argparser().parse_args(cmd) 80 _check_args(args) 81 _prepare_runner_for_test(runner, args) 82 83 timeout = args.timeout if args.timeout else runner.default_timeout 84 if args.boot_test: 85 return runner.boottest_run(args.boot_test, timeout) 86 if args.shell_command: 87 return runner.androidtest_run(args.shell_command, timeout) 88 if args.host_command: 89 return runner.hostcommandtest_run(args.host_command[0], timeout) 90 91 raise qemu.RunnerGenericError( 92 "Command contained neither a boot test nor an Android test to run") 93 94 95def shutdown(runner: Optional[qemu.Runner], 96 factory_reset: bool = True, 97 full_wipe: bool = False): 98 if runner: 99 runner.shutdown(factory_reset, full_wipe) 100 101 102def build_argparser(): 103 argument_parser = argparse.ArgumentParser() 104 argument_parser.add_argument("-c", "--config", type=argparse.FileType("r")) 105 argument_parser.add_argument("--headless", action="store_true") 106 argument_parser.add_argument("-v", "--verbose", action="store_true") 107 argument_parser.add_argument("--debug", action="store_true") 108 argument_parser.add_argument("--debug-on-error", action="store_true") 109 argument_parser.add_argument("--boot-test", action="append") 110 argument_parser.add_argument("--shell-command", action="append") 111 argument_parser.add_argument("--host-command", action="append") 112 argument_parser.add_argument("--android") 113 argument_parser.add_argument("--linux") 114 argument_parser.add_argument("--initrd") 115 argument_parser.add_argument("--instance-dir", type=str, 116 default="/tmp/trusty-qemu-generic-arm64") 117 argument_parser.add_argument("--atf") 118 argument_parser.add_argument("--qemu") 119 argument_parser.add_argument("--arch") 120 argument_parser.add_argument("--disable-rpmb", action="store_true") 121 argument_parser.add_argument("--timeout", type=int) 122 argument_parser.add_argument('-n', '--extra-linux-args', nargs='+', default=[]) 123 argument_parser.add_argument("extra_qemu_flags", nargs="*") 124 return argument_parser 125 126 127def main(): 128 args = build_argparser().parse_args() 129 log_level = logging.DEBUG if args.verbose else logging.WARN 130 logging.basicConfig(level=log_level) 131 132 config = qemu.Config(args.config) 133 if args.android: 134 config.android_image_dir = qemu.find_android_image_dir(args.android) 135 config.adb = qemu.find_adb_path(args.android) 136 config.boot_android = True 137 if args.linux: 138 config.linux = args.linux 139 if args.initrd: 140 config.initrd = args.initrd 141 if args.atf: 142 config.atf = args.atf 143 if args.qemu: 144 config.qemu = args.qemu 145 if args.arch: 146 config.arch = args.arch 147 if args.extra_linux_args: 148 config.extra_linux_args = args.extra_linux_args 149 if args.extra_qemu_flags: 150 config.extra_qemu_flags += args.extra_qemu_flags 151 152 runner = qemu.Runner(config, 153 interactive=not args.headless, 154 instance_dir=args.instance_dir, 155 verbose=args.verbose, 156 rpmb=not args.disable_rpmb, 157 debug=args.debug, 158 debug_on_error=args.debug_on_error) 159 160 try: 161 results = runner.run(args.boot_test, args.shell_command, 162 args.host_command, args.timeout) 163 print("Command results: " + repr(results)) 164 165 if any(results): 166 sys.exit(1) 167 else: 168 sys.exit(0) 169 except qemu_error.RunnerError as exn: 170 print(exn) 171 sys.exit(2) 172 173 174if __name__ == "__main__": 175 main() 176