diff --git a/.github/workflows/build-mos.yml b/.github/workflows/build-mos.yml index ee454f24..30ab6bc5 100644 --- a/.github/workflows/build-mos.yml +++ b/.github/workflows/build-mos.yml @@ -15,8 +15,8 @@ jobs: fail-fast: false matrix: config: - - { "name": "x86_64 limine", "arch": "x86_64", "bootwait": 20 } - - { "name": "RISC-V limine", "arch": "riscv64", "bootwait": 15 } + - { "name": "x86_64", "arch": "x86_64", "bootwait": 20 } + - { "name": "RISC-V", "arch": "riscv64", "bootwait": 15 } build_type: [Debug, Release] steps: @@ -78,6 +78,15 @@ jobs: name: MOS-${{matrix.build_type}}-${{matrix.config.arch}} path: build/uefi-files + - name: Download OVMF UEFI Firmware + if: ${{matrix.config.arch}} == 'riscv64' + run: | + cd build + export OVMF_VERSION=edk2-stable202405-r1 + wget "https://github.com/rust-osdev/ovmf-prebuilt/releases/download/edk2-$OVMF_VERSION/edk2-$OVMF_VERSION-bin.tar.xz" + tar -xvf edk2-$OVMF_VERSION-bin.tar.xz + mv $OVMF_VERSION-bin/riscv64/code.fd /opt/ovmf-riscv64.fd + - name: Test run: | cd build diff --git a/tools/testing/main.py b/tools/testing/main.py index 857dc973..a83d77cc 100755 --- a/tools/testing/main.py +++ b/tools/testing/main.py @@ -8,7 +8,7 @@ import logging import os from time import sleep -from utils import ScopedTimer, QEMU_ARCH_ARGS, QemuDeadError, QemuProcessBuilder +from utils import ScopedTimer, QEMU_ARCH_ARGS, TestFailedError, QemuProcessBuilder from models import * @@ -164,6 +164,8 @@ def main(): try: logging.info('Waiting for QEMU to boot...') sleep(args.boot_wait) # wait for QEMU to boot + if not QEMU_IO.isalive(): + raise TestFailedError('QEMU process terminated unexpectedly') logging.info('Starting tests...') @@ -180,6 +182,7 @@ def main(): logging.info(f'Received response: {response}') else: logging.error(f'Test {test} failed') + raise TestFailedError(f'Test {test} failed') sleep(1) logging.info('Test completed, waiting for QEMU to shutdown...') @@ -189,7 +192,7 @@ def main(): if QEMU_IO.error_killed: logging.error(f'Timed out after {args.timeout} seconds') return 1 - except QemuDeadError: + except TestFailedError: logging.error('QEMU process terminated unexpectedly') except KeyboardInterrupt: logging.error('Interrupted by user') diff --git a/tools/testing/models/__init__.py b/tools/testing/models/__init__.py index 247022e2..9c17cef8 100644 --- a/tools/testing/models/__init__.py +++ b/tools/testing/models/__init__.py @@ -5,7 +5,7 @@ import logging from typing import Literal -from utils import QemuProcess, QemuDeadError +from utils import QemuProcess, TestFailedError _default_encoder = json.JSONEncoder().default @@ -26,14 +26,14 @@ def __str__(self) -> str: return self.__repr__() -def do_call(qemu: QemuProcess, rpc_type: str, data: dict) -> dict: +def do_call(qemu: QemuProcess, rpc_type: str, data: dict) -> dict | None: qemu.writeln(json.dumps({'type': rpc_type + '.request', 'object': data})) logging.debug(f'Sent request: {rpc_type}, {data}') while True: line = qemu.pop_output() if line is None: - return {} # no more output + return None # no more output if not (line.startswith('{') and line.endswith('}')): continue # ignore non-json lines @@ -60,11 +60,11 @@ def rpc_type(self): raise NotImplementedError def call(self, qemu: QemuProcess) -> Response | None: - try: - resp_dict = do_call(qemu, self.rpc_type, self.__dict__) - return self.Response(self, **resp_dict) if resp_dict else None - except QemuDeadError: - return None + resp_dict = do_call(qemu, self.rpc_type, self.__dict__) + if not resp_dict: + raise TestFailedError('Qemu process terminated') + + return self.Response(self, **resp_dict) REDIRECT_TARGET_TYPE = Literal['file', 'fd'] diff --git a/tools/testing/utils/QemuProcess.py b/tools/testing/utils/QemuProcess.py index 55a86c27..72a5b13c 100644 --- a/tools/testing/utils/QemuProcess.py +++ b/tools/testing/utils/QemuProcess.py @@ -8,7 +8,7 @@ from ptyprocess import PtyProcess -class QemuDeadError(Exception): +class TestFailedError(Exception): pass @@ -39,7 +39,7 @@ def _encode_command(self, command): def writeln(self, line): if not self.isalive(): - raise QemuDeadError('Process is terminated') + raise TestFailedError('Process is terminated') logging.debug(f'sending line: {line}') self.write(self._encode_command(line + '\n')) @@ -65,7 +65,7 @@ def pop_output(self) -> str | None: except IndexError: sleep(0.1) - raise QemuDeadError('Process is terminated') + raise TestFailedError('Process is terminated') def forcefully_terminate(self): self.error_killed = True