qemu and build: review fixes across the rig driver, boot script, and fetch helpers
Bounded waits and validated arguments in run.sh and ui-drive.sh, a seeded settings directory and root-only staged rootfs permissions with their own tests, qmp.py and imgtools.py hardening, the fetch scripts checking what they download, and ASCII typography throughout. Each fix carries its test under qemu/tests or tests/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N3G6m9Aw5RyVY4ZowtKzEj
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regression tests for build/fetch-buildroot-tarball.sh's retry/verify path.
|
||||
#
|
||||
# The script had never been exercised by anything (nothing calls it yet --
|
||||
# see its own header) or by a test, so its retry-on-mismatch, cleanup, and
|
||||
# already-verified short-circuit had never actually run. It also fetched with
|
||||
# no --connect-timeout/--max-time, so a connection that opens and then stalls
|
||||
# (a blackholed route, a hung proxy) would block forever instead of retrying;
|
||||
# issue tracked separately.
|
||||
#
|
||||
# Runs the real script (copied into a fixture dir so its own HERE-relative pin
|
||||
# lookup finds a pin we control) with a fake curl first on PATH, so no network
|
||||
# is used and the outcome of each attempt is exact.
|
||||
set -uo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "$0")" && pwd)"
|
||||
SCRIPT="$HERE/../../build/fetch-buildroot-tarball.sh"
|
||||
[ -f "$SCRIPT" ] || { echo "FAIL: script not found at $SCRIPT"; exit 1; }
|
||||
|
||||
FAIL=0
|
||||
ok() { printf '[PASS] %s\n' "$1"; }
|
||||
bad() { printf '[FAIL] %s\n' "$1"; FAIL=1; }
|
||||
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
WANT_SHA="$(printf 'good-bytes' | sha256sum | awk '{print $1}')"
|
||||
|
||||
# A private copy of the real script plus a pin file we control, in its own
|
||||
# directory: the script resolves its pin relative to itself, so this is the
|
||||
# shipping file under test, not a reimplementation of it.
|
||||
setup() { # setup <case-name> -> prints the fixture dir
|
||||
local dir="$TMP/$1"
|
||||
mkdir -p "$dir/bin"
|
||||
cp "$SCRIPT" "$dir/fetch-buildroot-tarball.sh"
|
||||
printf '%s buildroot-2025.02.8.tar.xz\n' "$WANT_SHA" \
|
||||
> "$dir/buildroot-2025.02.8.tar.xz.sha256"
|
||||
printf '%s' "$dir"
|
||||
}
|
||||
|
||||
run() { # run <dir> <dest> -> stdout+stderr on stdout, $? in $RC
|
||||
local dir="$1" dest="$2"
|
||||
OUT="$(PATH="$dir/bin:$PATH" bash "$dir/fetch-buildroot-tarball.sh" "$dest" 2>&1)"
|
||||
RC=$?
|
||||
}
|
||||
|
||||
# --- case A: destination already matches the pin -> curl never runs -------
|
||||
dir="$(setup case-a)"
|
||||
printf 'good-bytes' > "$dir/dest.tar.xz"
|
||||
cat > "$dir/bin/curl" <<'FAKE'
|
||||
#!/bin/sh
|
||||
echo "curl should not have run" >&2
|
||||
exit 1
|
||||
FAKE
|
||||
chmod +x "$dir/bin/curl"
|
||||
run "$dir" "$dir/dest.tar.xz"
|
||||
if [ "$RC" -eq 0 ] && printf '%s' "$OUT" | grep -q 'already present and verified'; then
|
||||
ok "already-verified destination: curl never invoked"
|
||||
else
|
||||
bad "already-verified destination: curl never invoked (rc=$RC, out=$OUT)"
|
||||
fi
|
||||
|
||||
# --- case B: fails once, succeeds on retry -> verified, no extra attempts -
|
||||
dir="$(setup case-b)"
|
||||
cat > "$dir/bin/curl" <<FAKE
|
||||
#!/bin/sh
|
||||
cnt_file="$dir/curl-calls"
|
||||
n=0
|
||||
[ -f "\$cnt_file" ] && n=\$(cat "\$cnt_file")
|
||||
n=\$((n + 1))
|
||||
echo "\$n" > "\$cnt_file"
|
||||
out="" prev=""
|
||||
for a in "\$@"; do
|
||||
[ "\$prev" = "-o" ] && out="\$a"
|
||||
prev="\$a"
|
||||
done
|
||||
if [ "\$n" -lt 2 ]; then printf 'bad-bytes' > "\$out"
|
||||
else printf 'good-bytes' > "\$out"
|
||||
fi
|
||||
FAKE
|
||||
chmod +x "$dir/bin/curl"
|
||||
run "$dir" "$dir/dest.tar.xz"
|
||||
calls="$(cat "$dir/curl-calls" 2>/dev/null || echo 0)"
|
||||
if [ "$RC" -eq 0 ] && [ "$calls" -eq 2 ] && printf '%s' "$OUT" | grep -q 'sha256 verified'; then
|
||||
ok "mismatch then match: verified on attempt 2, stops retrying"
|
||||
else
|
||||
bad "mismatch then match: verified on attempt 2, stops retrying (rc=$RC calls=$calls out=$OUT)"
|
||||
fi
|
||||
|
||||
# --- case C: every attempt mismatches -> fails closed, no partial file left
|
||||
dir="$(setup case-c)"
|
||||
cat > "$dir/bin/curl" <<'FAKE'
|
||||
#!/bin/sh
|
||||
out="" prev=""
|
||||
for a in "$@"; do
|
||||
[ "$prev" = "-o" ] && out="$a"
|
||||
prev="$a"
|
||||
done
|
||||
printf 'always-bad' > "$out"
|
||||
FAKE
|
||||
chmod +x "$dir/bin/curl"
|
||||
run "$dir" "$dir/dest.tar.xz"
|
||||
if [ "$RC" -ne 0 ] && printf '%s' "$OUT" | grep -q 'FATAL: could not fetch'; then
|
||||
ok "persistent mismatch: exits nonzero with FATAL"
|
||||
else
|
||||
bad "persistent mismatch: exits nonzero with FATAL (rc=$RC, out=$OUT)"
|
||||
fi
|
||||
if [ ! -e "$dir/dest.tar.xz" ]; then
|
||||
ok "persistent mismatch: no partial/corrupt tarball left at the destination"
|
||||
else
|
||||
bad "persistent mismatch: no partial/corrupt tarball left at the destination"
|
||||
fi
|
||||
attempts="$(printf '%s' "$OUT" | grep -c '== fetching')"
|
||||
if [ "$attempts" -eq 3 ]; then
|
||||
ok "persistent mismatch: exactly 3 attempts"
|
||||
else
|
||||
bad "persistent mismatch: exactly 3 attempts (got $attempts)"
|
||||
fi
|
||||
|
||||
# --- guard: the fetch carries a connect and overall timeout ---------------
|
||||
# Without these, --retry never fires (it only re-attempts a transfer curl has
|
||||
# already decided failed) and a connection that opens then stalls blocks
|
||||
# forever -- exactly the routing failure this workspace sees from some hosts.
|
||||
if grep -q -- '--connect-timeout' "$SCRIPT" && grep -q -- '--max-time' "$SCRIPT"; then
|
||||
ok "fetch carries --connect-timeout and --max-time"
|
||||
else
|
||||
bad "fetch carries --connect-timeout and --max-time"
|
||||
fi
|
||||
|
||||
if [ "$FAIL" -eq 0 ]; then
|
||||
echo "ALL FETCH-BUILDROOT-TARBALL TESTS PASSED"
|
||||
else
|
||||
echo "FETCH-BUILDROOT-TARBALL TESTS FAILED"
|
||||
fi
|
||||
exit "$FAIL"
|
||||
Reference in New Issue
Block a user