aboutsummaryrefslogtreecommitdiff
path: root/tests/argv
diff options
context:
space:
mode:
authorLena <lena@omega>2026-08-01 00:00:00 +0000
committerLena <lena@omega>2026-08-01 00:00:00 +0000
commitc235cb62beefd03087e7cfc7f7f55f0c7c6601c9 (patch)
tree2776f86d9226d55c78e3d735764fcd9ecbe5e08e /tests/argv
downloadvmm-master.tar.gz
Enter vmmHEADmaster
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/argv151
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