summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPer Larsen <perlarsen@google.com>2022-10-23 07:16:52 +0000
committerPer Larsen <perlarsen@google.com>2022-10-26 23:53:29 +0000
commit8c14214df0f061b2bb6a5aa2302a0fedf2da17a0 (patch)
treeb74241f0212707f0616cbbf9002bea6edc1a4aca
parent9007753b8bb2ecc367f553d2a62d75f7f1402787 (diff)
downloadgeneric-arm64-8c14214df0f061b2bb6a5aa2302a0fedf2da17a0.tar.gz
project/qemu: Make state explicit in Runner
Make it explicit whether the qemu.Runner is off, in the bootloader, or in Android. Launch and reboot methods now take a target state. Finally, the run_test function in run.py ensures that the Runner is in the correct target state for the test to run. Bug: 242077104 Change-Id: I8467d2054ce401625d5e97a40018ba02fd723741
-rw-r--r--project/qemu/qemu.py42
-rwxr-xr-xproject/qemu/run.py30
2 files changed, 59 insertions, 13 deletions
diff --git a/project/qemu/qemu.py b/project/qemu/qemu.py
index b0c3c53..76a1d8b 100644
--- a/project/qemu/qemu.py
+++ b/project/qemu/qemu.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
"""Run Trusty under QEMU in different configurations"""
+import enum
import errno
import fcntl
import json
@@ -310,6 +311,13 @@ class RunnerSession:
self.temp_files.append(tmp.name)
return tmp
+
+class RunnerState(enum.Enum):
+ OFF = 0,
+ BOOTLOADER = 1,
+ ANDROID = 2,
+
+
class Runner(object):
"""Executes tests in QEMU"""
@@ -339,6 +347,7 @@ class Runner(object):
self.qemu_arch_options = None
self.default_timeout = 60 * 10 # 10 Minutes
self.session: RunnerSession = None
+ self.state = RunnerState.OFF
# If we're not verbose or interactive, squelch command output
if verbose or self.interactive:
@@ -770,7 +779,7 @@ class Runner(object):
return args
- def launch(self, boot_test_only):
+ def launch(self, target_state):
"""Launches the QEMU execution.
If interactive is specified, it will leave the user connected
@@ -792,6 +801,10 @@ class Runner(object):
android tests are launched. Specifically, we might stop execution
in the bootloader and have it wait for a command to boot android.
"""
+ assert self.state == RunnerState.OFF
+ assert target_state in [RunnerState.BOOTLOADER,
+ RunnerState.ANDROID], target_state
+
self.session = RunnerSession()
args = self.universal_args()
@@ -813,8 +826,9 @@ class Runner(object):
# Create socket for communication channel
args += self.msg_channel_up()
- if boot_test_only:
+ if target_state == RunnerState.BOOTLOADER:
self.session.args = args
+ self.state = target_state
return
# Logging and terminal monitor
@@ -863,6 +877,8 @@ class Runner(object):
# Bring ADB up talking to the command port
self.adb_up(self.session.ports[1])
+
+ self.state = target_state
except:
self.session.has_error = True
raise
@@ -874,7 +890,10 @@ class Runner(object):
Calls to launch and shutdown must be correctly paired no matter whether
the launch steps and calls to adb succeed or fail.
"""
- assert self.session, "No session; was shutdown call preceded by launch?"
+ if self.state == RunnerState.OFF:
+ return
+
+ assert self.session is not None
# Clean up generated device tree
for temp_file in self.session.temp_files:
@@ -900,10 +919,21 @@ class Runner(object):
self.adb_down(self.session.ports[1])
self.session = None
+ self.state = RunnerState.OFF
if unclean_exit:
raise RunnerGenericError("QEMU did not exit cleanly")
+ def reboot(self, target_state):
+ self.shutdown()
+
+ try:
+ self.launch(target_state)
+ except:
+ self.shutdown()
+ raise
+
+
def run(self, boot_tests=[], android_tests=[], timeout=None):
"""Run boot or android tests.
@@ -926,13 +956,15 @@ class Runner(object):
If android_tests is provided, a Linux and Android dir must be
provided in the config.
"""
- boot_tests = boot_tests if boot_tests else []
+ assert self.state == RunnerState.OFF
+ target_state = (RunnerState.BOOTLOADER if boot_tests else
+ RunnerState.ANDROID)
android_tests = android_tests if android_tests else []
self.config.check_config(self.interactive, boot_tests, android_tests)
timeout = timeout if timeout else self.default_timeout
try:
- self.launch(bool(boot_tests))
+ self.launch(target_state)
match (boot_tests, android_tests):
case ([], []):
diff --git a/project/qemu/run.py b/project/qemu/run.py
index 643255e..9c92ef8 100755
--- a/project/qemu/run.py
+++ b/project/qemu/run.py
@@ -46,23 +46,37 @@ def _check_args(args):
assert not args.disable_rpmb, args
+def _prepare_runner_for_test(runner, args):
+ """Check if the runner is in the correct state (BOOTLOADER, ANDROID)
+ to run a given test and reboot the emulator if it is not.
+
+ TODO: Remove the unconditional reboot after boot tests once the test harness
+ no longers requires it.
+ """
+ if args.boot_test:
+ target_state = qemu.RunnerState.BOOTLOADER
+ elif args.shell_command:
+ target_state = qemu.RunnerState.ANDROID
+ else:
+ raise qemu_error.ConfigError(
+ "Command must request exactly one Android or boot test to run")
+
+ # Due to limitations in the test runner, always reboot between boot tests
+ if (runner.state != target_state or
+ runner.state == qemu.RunnerState.BOOTLOADER):
+ runner.reboot(target_state)
+
+
def run_test(runner: qemu.Runner, cmd: List[str]) -> int:
args = build_argparser().parse_args(cmd)
_check_args(args)
-
- # make sure runner was started with rpmb in the state needed for test
- assert args.disable_rpmb == (not runner.use_rpmb)
+ _prepare_runner_for_test(runner, args)
timeout = args.timeout if args.timeout else runner.default_timeout
if args.boot_test:
- runner.launch(boot_test_only=True)
return runner.boottest_run(args.boot_test, timeout)
elif args.shell_command:
- runner.launch(boot_test_only=False)
return runner.androidtest_run(args.shell_command, timeout)
- else:
- raise qemu_error.ConfigError(
- "Command must request exactly one Android or boot test to run")
def shutdown(runner: Optional[qemu.Runner]):