#!/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 -> 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 -> 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" < "\$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"