"""build_cmdline is pure — table-test it hard.""" from pathlib import Path import pytest from fastmcp.exceptions import ToolError from mcqemu.launcher import VMPaths, build_cmdline from mcqemu.models import VMConfig def paths() -> VMPaths: return VMPaths( qmp_socket=Path("/run/t/qmp.sock"), qga_socket=Path("/run/t/qga.sock"), pidfile=Path("/run/t/pid"), qemu_log=Path("/state/t/qemu.log"), serial_log=Path("/state/t/serial.log"), uefi_vars=Path("/state/t/uefi-vars.fd"), ) def argstr(args: list[str]) -> str: return " ".join(args) def test_defaults_kvm(): cfg = VMConfig(name="t") args = build_cmdline(cfg, paths(), accel="kvm", disk_formats={}) s = argstr(args) assert args[0] == "qemu-system-x86_64" assert "-machine q35,accel=kvm" in s assert "-cpu host" in s assert "-m 2048" in s and "-smp 2" in s assert "-display none" in s assert "-daemonize" in s assert "-qmp unix:/run/t/qmp.sock,server=on,wait=off" in s assert "org.qemu.guest_agent.0" in s assert "-device virtio-tablet-pci" in s assert "-netdev user,id=net0 -device virtio-net-pci,netdev=net0" in s def test_tcg_uses_cpu_max(): cfg = VMConfig(name="t", arch="riscv64") args = build_cmdline(cfg, paths(), accel="tcg", disk_formats={}) s = argstr(args) assert args[0] == "qemu-system-riscv64" assert "-machine virt,accel=tcg" in s assert "-cpu max" in s def test_unknown_arch_machine_falls_back_to_accel_flag(): cfg = VMConfig(name="t", arch="m68k") s = argstr(build_cmdline(cfg, paths(), accel="tcg", disk_formats={})) assert "-accel tcg" in s assert "-machine" not in s def test_disks_get_probed_format(): cfg = VMConfig(name="t", disks=["/vms/a.qcow2", "/vms/b.raw"]) s = argstr( build_cmdline( cfg, paths(), accel="kvm", disk_formats={"/vms/a.qcow2": "qcow2", "/vms/b.raw": "raw"}, ) ) assert "-drive file=/vms/a.qcow2,if=virtio,format=qcow2" in s assert "-drive file=/vms/b.raw,if=virtio,format=raw" in s def test_iso_with_disk_boots_once_from_cdrom(): cfg = VMConfig(name="t", disks=["/vms/a.qcow2"], iso="/isos/x.iso") s = argstr(build_cmdline(cfg, paths(), accel="kvm", disk_formats={"/vms/a.qcow2": "qcow2"})) assert "media=cdrom,readonly=on" in s assert "-boot once=d" in s def test_iso_alone_no_boot_flag(): cfg = VMConfig(name="t", iso="/isos/x.iso") s = argstr(build_cmdline(cfg, paths(), accel="kvm", disk_formats={})) assert "-boot" not in s def test_port_forwards(): cfg = VMConfig(name="t", port_forwards=["2222:22", "8080:80"]) s = argstr(build_cmdline(cfg, paths(), accel="kvm", disk_formats={})) assert "hostfwd=tcp::2222-:22" in s assert "hostfwd=tcp::8080-:80" in s def test_bad_port_forward_raises(): cfg = VMConfig(name="t", port_forwards=["22->2222"]) with pytest.raises(ToolError, match="port forward"): build_cmdline(cfg, paths(), accel="kvm", disk_formats={}) def test_no_net(): cfg = VMConfig(name="t", no_net=True) s = argstr(build_cmdline(cfg, paths(), accel="kvm", disk_formats={})) assert "-nic none" in s assert "-netdev" not in s def test_uefi_pflash_x86(): cfg = VMConfig(name="t", firmware="uefi") s = argstr(build_cmdline(cfg, paths(), accel="kvm", disk_formats={})) assert "if=pflash,format=raw,readonly=on,file=/usr/share/edk2/x64/OVMF_CODE.4m.fd" in s assert "if=pflash,format=raw,file=/state/t/uefi-vars.fd" in s def test_uefi_bios_mode_aarch64(): cfg = VMConfig(name="t", arch="aarch64", firmware="uefi") s = argstr(build_cmdline(cfg, paths(), accel="tcg", disk_formats={})) assert "-bios /usr/share/edk2/aarch64/QEMU_EFI.fd" in s assert "pflash" not in s def test_uefi_unsupported_arch_raises(): cfg = VMConfig(name="t", arch="m68k", firmware="uefi") with pytest.raises(ToolError, match="UEFI"): build_cmdline(cfg, paths(), accel="tcg", disk_formats={}) def test_extra_args_appended_last(): cfg = VMConfig(name="t", extra_args=["-vga", "std"]) args = build_cmdline(cfg, paths(), accel="kvm", disk_formats={}) assert args[-2:] == ["-vga", "std"]