From 0f8bbc7c1e2c2f6fec0b17753ac0d9c4a3ad4317 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Fri, 22 May 2026 20:12:14 -0500 Subject: fix(test): fail clearly when the VM forward port is taken A test run launched qemu without first checking the SSH forward port, so a collision with another VM already holding it surfaced only as an opaque "Failed to start VM," with qemu unable to bind and no hint why. I added a port_in_use check in run_test before the launch: it errors with the port number and the SSH_PORT override to set, records the failure, and moves on. The check lives in run_test, not start_vm, because start_vm runs in a command substitution (vm_pid=$(start_vm ...)) where this harness's non-exiting error() would be captured as the PID instead of failing the run. The pure half, port_listening_in, takes an `ss -tln` snapshot as a string so it's unit-testable. --- scripts/test-install.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'scripts') diff --git a/scripts/test-install.sh b/scripts/test-install.sh index 8cfe2ec..4220d20 100755 --- a/scripts/test-install.sh +++ b/scripts/test-install.sh @@ -142,6 +142,20 @@ cleanup_disks() { rm -f "$VM_DIR"/test-"${test_name}"-disk*.qcow2 } +# Pure predicate: does this `ss -tln` snapshot show already +# listening? Kept separate from the live ss query (port_in_use) so it's +# unit-testable with fixture output. The ": " match anchors on the +# colon and trailing space so 2222 doesn't match 12222 or 22222. +port_listening_in() { + local port="$1" ss_output="$2" + grep -q ":${port} " <<<"$ss_output" +} + +# Live check: is currently bound by a listening socket? +port_in_use() { + port_listening_in "$1" "$(ss -tln 2>/dev/null)" +} + # Start VM and return PID start_vm() { local test_name="$1" @@ -863,6 +877,19 @@ run_test() { step "Creating VM disks..." create_disks "$disk_count" "$config_name" + # Fail clearly if the forward port is taken (another VM?) before launching, + # rather than letting qemu fail to bind and report an opaque "Failed to + # start VM". Runs here, not inside start_vm — start_vm is command- + # substituted (vm_pid=$(...)), where error()'s output would be captured as + # the PID instead of failing the run. + if port_in_use "$SSH_PORT"; then + error "Port $SSH_PORT already in use (another VM?). Set SSH_PORT= and retry." + cleanup_disks "$config_name" + TESTS_FAILED=$((TESTS_FAILED + 1)) + FAILED_TESTS+=("$config_name") + return 1 + fi + step "Starting VM..." local vm_pid vm_pid=$(start_vm "$config_name" "$disk_count") -- cgit v1.2.3