diff options
| author | Lena <lena@omega> | 2026-08-01 00:00:00 +0000 |
|---|---|---|
| committer | Lena <lena@omega> | 2026-08-01 00:00:00 +0000 |
| commit | c235cb62beefd03087e7cfc7f7f55f0c7c6601c9 (patch) | |
| tree | 2776f86d9226d55c78e3d735764fcd9ecbe5e08e /tests/argv | |
| download | vmm-master.tar.gz | |
A QEMU/KVM virtual machine manager in one POSIX shell script. Each
VM is a directory of plain files under $VMMDIR, configured by a
hand-edited KEY=VALUE file that is parsed rather than sourced, so
nothing in it can inject a raw QEMU argument.
Control is a QMP FIFO pair inside that directory, guarded by its
permissions alone; nothing binds a TCP port. The tests are TAP
without a framework and boot real guests where the host allows.
Diffstat (limited to 'tests/argv')
| -rw-r--r-- | tests/argv | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/tests/argv b/tests/argv new file mode 100644 index 0000000..628d621 --- /dev/null +++ b/tests/argv @@ -0,0 +1,151 @@ +# The QEMU argv, as printed by dryrun. + +"$VMM" create av1 64M >/dev/null 2>&1 +IMG=$VMMDIR/av1/disk.qcow2 + +cfg av1 <<EOF +HOSTFWD="2222:22" +EOF +outputs 'hostfwd=tcp:127.0.0.1:2222-:22' "two field HOSTFWD binds loopback" dryrun av1 +outputs "-vnc 'none'" "GRAPHICS=no still arms -vnc none" dryrun av1 +outputs 'free-page-reporting=on' "balloon is on by default" dryrun av1 +outputs 'strict=on' "the boot list is a restriction, not a hint" dryrun av1 +outputs "sandbox 'on,.*spawn=deny" "the sandbox denies spawning" dryrun av1 +outputs 'panic=pause' "a panicking guest is paused, not killed" dryrun av1 +omits 'aio=io_uring' "the disk uses qemu's default AIO backend" dryrun av1 + +cfg av1 <<EOF +HOSTFWD="0.0.0.0:2222:22" +EOF +outputs 'hostfwd=tcp:0.0.0.0:2222-:22' "three field HOSTFWD honours the address" dryrun av1 + +cfg av1 <<EOF +HOSTFWD="2222:22,0.0.0.0:8080:80" +EOF +outputs 'hostfwd=tcp:127.0.0.1:2222-:22,hostfwd=tcp:0.0.0.0:8080-:80' \ + "both HOSTFWD forms in one value" dryrun av1 + +cfg av1 <<EOF +BALLOON=no +EOF +omits balloon "BALLOON=no omits the device" dryrun av1 + +cfg av1 <<EOF +NETWORK=hostonly +EOF +outputs 'restrict=on' "NETWORK=hostonly restricts the guest" dryrun av1 + +cfg av1 <<EOF +NETWORK=no +EOF +outputs "-nic 'none'" "NETWORK=no gives no NIC" dryrun av1 + +# The CDROM hangs off virtio-scsi, which every machine type has, and not +# off an IDE bus, which only x86 has. +cfg av1 <<EOF +CDROM="$IMG" +BOOT_ORDER=dc +EOF +outputs 'scsi-cd' "the CDROM is a SCSI device" dryrun av1 +outputs 'bus=scsi0.0,bootindex=1' "the CDROM takes its place in the boot order" dryrun av1 + +# A comma in the fixed disk path must be doubled, not passed through. +COMMA_DIR=$WORK/vms,comma +VMMDIR="$COMMA_DIR" "$VMM" create avc 64M >/dev/null 2>&1 +out=$(VMMDIR="$COMMA_DIR" "$VMM" dryrun avc 2>&1) && got=0 || got=$? +if [ "$got" = 0 ] && printf '%s\n' "$out" | grep -q 'vms,,comma'; then + ok "a comma in VMMDIR is escaped" +else + notok "a comma in VMMDIR is escaped" "exit $got: $out" +fi + +: > "$VMMDIR/av1/config" + +# Two VMs must not share a MAC. +"$VMM" create av2 64M >/dev/null 2>&1 +m1=$("$VMM" dryrun av1 2>/dev/null | sed -n 's/.*mac=\([0-9a-f:]*\).*/\1/p') +m2=$("$VMM" dryrun av2 2>/dev/null | sed -n 's/.*mac=\([0-9a-f:]*\).*/\1/p') +if [ -n "$m1" ] && [ "$m1" != "$m2" ]; then + ok "each VM gets its own MAC" +else + notok "each VM gets its own MAC" "av1=$m1 av2=$m2" +fi + +# dryrun output must be pasteable, so every argument is single quoted. +outputs "'node-name=disk0f,driver=file,filename=$IMG" \ + "dryrun shell-quotes its argv" dryrun av1 + +# A malformed uuid must never reach QEMU or be silently regenerated. +cp "$VMMDIR/av1/uuid" "$WORK/uuid.bak" +: > "$VMMDIR/av1/uuid" +refuses 'uuid is missing or malformed' "an empty uuid is refused" dryrun av1 +refuses 'uuid is missing or malformed' "start does not repair an empty uuid" start av1 +holds "a refused start leaves the empty uuid untouched" \ + test ! -s "$VMMDIR/av1/uuid" +printf 'zzzzzzzz-1111-2222-3333-444444444444\n' > "$VMMDIR/av1/uuid" +refuses 'uuid is missing or malformed' "a non-hex uuid is refused" dryrun av1 +printf '12345678-1111-2222-3333-44444444444z\n' > "$VMMDIR/av1/uuid" +refuses 'uuid is missing or malformed' "every uuid group is validated" dryrun av1 +cp "$WORK/uuid.bak" "$VMMDIR/av1/uuid" + +# Graphics means a display and an absolute pointer. Guest agents and +# clipboard sharing are separate policy and do not belong on this argv. +cfg av1 <<EOF +GRAPHICS=vnc +EOF +outputs 'usb-tablet' "VNC includes an absolute pointer" dryrun av1 +omits 'vdagent' "VNC includes no guest agent" dryrun av1 +omits 'virtio-serial' "VNC includes no unused agent transport" dryrun av1 + +cfg av1 <<EOF +GRAPHICS=spice +EOF +outputs 'spice.sock' "SPICE names its display socket" dryrun av1 +omits 'clipboard' "SPICE does not enable clipboard sharing" dryrun av1 +omits 'spicevmc' "SPICE includes no guest agent" dryrun av1 + +: > "$VMMDIR/av1/config" + +# dryrun launches nothing, so it must work on a host with no qemu at all. +# The README promises it as a config checker anywhere. +BIN=$WORK/dryrun-bin +mkdir -p "$BIN" +for b in uname cat sed tr grep od awk; do + ln -sf "$(command -v "$b")" "$BIN/$b" +done +holds "dryrun works with no qemu installed" \ + env PATH="$BIN" "$VMM" dryrun av1 + +# What dryrun prints is what start runs, so the printed argv must boot a +# guest vmm then recognises as that VM. The CDROM path carries a comma, +# which reaches QEMU whole only if the doubling is right. +if command -v "qemu-system-$(uname -m)" >/dev/null 2>&1; then + : > "$WORK/comma,name.iso" + "$VMM" create av3 64M >/dev/null 2>&1 + cfg av3 <<EOF +MEM=256 +CPUS=1 +HWACCEL=no +CDROM="$WORK/comma,name.iso" +BOOT_ORDER=cd +EOF + "$VMM" dryrun av3 > "$WORK/av3.sh" + sh "$WORK/av3.sh" > "$WORK/av3.out" 2>&1 & + pasted=$! + i=0 + while [ ! -s "$VMMDIR/av3/pid" ] && [ "$i" -lt 15 ]; do + sleep 1 + i=$((i + 1)) + done + out=$("$VMM" status av3 2>&1) && got=0 || got=$? + if [ "$got" = 0 ]; then + ok "the argv dryrun prints boots a guest vmm knows" + else + notok "the argv dryrun prints boots a guest vmm knows" \ + "status exit $got: $out" "$(tail -n 5 "$WORK/av3.out")" + fi + exits 0 "and vmm stops what dryrun started" kill av3 + wait "$pasted" 2>/dev/null || : +else + skip 2 "no qemu for the host architecture" +fi |