diff --git a/AGENTS.md b/AGENTS.md index 3eb8d936..6c15068f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,6 +26,10 @@ the operational checklist: toolchain, invariants, and how to ship a change. check`, or `PATH="/src:$PATH"` for a manual run. - Give new `.test` scripts `set -e`: the older ones predate the rule, so several `local-crawl.sh` calls with no `set -e` report PASS on any non-last failure. +- Run teardown with errexit off: `trap 'set +e; cleanup' EXIT`. Under `set -e` a + failing cleanup command becomes the test's exit status (#773). Keep the other + signals on their own `trap` line, or errexit stays off for the rest of the run. + The guard also resets `$?`, so save it first if teardown reads it. - Never assert with `cmd | grep -q MARKER && fail`. Under `pipefail` the pipeline is non-zero both when `cmd` fails and when `grep -q` matches early and SIGPIPEs it, so the `&&` never fires and a probe that proved nothing reads diff --git a/tests/01_engine-changes.test b/tests/01_engine-changes.test index 28953d7e..aff30e23 100644 --- a/tests/01_engine-changes.test +++ b/tests/01_engine-changes.test @@ -4,7 +4,8 @@ set -euo pipefail tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_changes_st.XXXXXX") || exit 1 -trap 'rm -rf "$tmpdir"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmpdir"' EXIT +trap 'rm -rf "$tmpdir"' HUP INT QUIT PIPE TERM # No pipe into grep: SIGPIPE would mask a failing exit status. expect_ok() { diff --git a/tests/01_engine-cmdline.test b/tests/01_engine-cmdline.test index 2fd24ea1..52767b6e 100755 --- a/tests/01_engine-cmdline.test +++ b/tests/01_engine-cmdline.test @@ -11,7 +11,8 @@ set -euo pipefail tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_cmdline.XXXXXX") || exit 1 -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM echo 'hello' >"$tmp/index.html" diff --git a/tests/01_engine-cookieimport.test b/tests/01_engine-cookieimport.test index 58571d16..b0ff0ae5 100755 --- a/tests/01_engine-cookieimport.test +++ b/tests/01_engine-cookieimport.test @@ -7,6 +7,6 @@ set -euo pipefail # cookies *@*.txt) from a long, non-ASCII folder through the UTF-8/long-path # file wrappers (#133,#630). dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=cookieimport "$dir" | grep -q "cookieimport:.*OK" diff --git a/tests/01_engine-direnum.test b/tests/01_engine-direnum.test index 18043bec..63476b66 100755 --- a/tests/01_engine-direnum.test +++ b/tests/01_engine-direnum.test @@ -6,6 +6,6 @@ set -euo pipefail # Drives -#test=direnum: enumerate a long+non-ASCII directory through the # opendir/readdir wrappers, checking each child round-trips as UTF-8 (#133,#630). dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=direnum "$dir" | grep -q "direnum:.*OK" diff --git a/tests/01_engine-doitlog.test b/tests/01_engine-doitlog.test index 8016df24..f3de4a6b 100644 --- a/tests/01_engine-doitlog.test +++ b/tests/01_engine-doitlog.test @@ -28,7 +28,8 @@ case "$bin" in esac tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_doitlog.XXXXXX") || exit 1 -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM site="$tmp/site" out="$tmp/out" diff --git a/tests/01_engine-filelist.test b/tests/01_engine-filelist.test index 2e78a44f..f5e36791 100644 --- a/tests/01_engine-filelist.test +++ b/tests/01_engine-filelist.test @@ -8,7 +8,8 @@ set -euo pipefail tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_filelist.XXXXXX") || exit 1 -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM echo 'hi' >"$tmp/index.html" diff --git a/tests/01_engine-footer-overflow.test b/tests/01_engine-footer-overflow.test index 2884c879..6db0cc97 100755 --- a/tests/01_engine-footer-overflow.test +++ b/tests/01_engine-footer-overflow.test @@ -18,7 +18,7 @@ MINGW* | MSYS* | CYGWIN*) exit 77 ;; esac dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # A few-hundred-char file path (kept well under the URL length limit) makes the # {path} field long. diff --git a/tests/01_engine-fsize.test b/tests/01_engine-fsize.test index a3b4e0cf..3a119e06 100644 --- a/tests/01_engine-fsize.test +++ b/tests/01_engine-fsize.test @@ -6,7 +6,7 @@ set -euo pipefail dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT rc=0 out=$(httrack -#test=fsize "$dir") || rc=$? diff --git a/tests/01_engine-growsize.test b/tests/01_engine-growsize.test index 687728da..d12d4e74 100644 --- a/tests/01_engine-growsize.test +++ b/tests/01_engine-growsize.test @@ -10,7 +10,8 @@ echo "$out" test "$out" == "growsize self-test OK" tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_growsize.XXXXXX") -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM echo 'hi' >"$tmp/index.html" printf -- '-*/zzmarker*\n' >"$tmp/rules.txt" diff --git a/tests/01_engine-longpath-io.test b/tests/01_engine-longpath-io.test index 5d7e170c..433a62cb 100644 --- a/tests/01_engine-longpath-io.test +++ b/tests/01_engine-longpath-io.test @@ -6,6 +6,6 @@ set -euo pipefail # Drives -#test=longpath: a >MAX_PATH round trip exercising hts_pathToUCS2's # \\?\ prefixing on Windows (#133); a positive control on POSIX. dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=longpath "$dir" | grep -q "longpath:.*OK" diff --git a/tests/01_engine-makeindex.test b/tests/01_engine-makeindex.test index 44ec9812..36e4904c 100755 --- a/tests/01_engine-makeindex.test +++ b/tests/01_engine-makeindex.test @@ -6,7 +6,7 @@ set -euo pipefail # hts_finish_makeindex writes the footer and gates the refresh meta on a single # first link (guards the macro->function extraction). dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=makeindex "$dir" run | grep -q "makeindex self-test OK" diff --git a/tests/01_engine-mirror-io.test b/tests/01_engine-mirror-io.test index f49a29c3..8c03e9b7 100755 --- a/tests/01_engine-mirror-io.test +++ b/tests/01_engine-mirror-io.test @@ -7,6 +7,6 @@ set -euo pipefail # (>MAX_PATH) and non-ASCII, exercising the mirror I/O wrappers the engine's # raw file ops now route to on Windows (#133, #630). Positive control on POSIX. dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=mirrorio "$dir" | grep -q "mirrorio:.*OK" diff --git a/tests/01_engine-parse.test b/tests/01_engine-parse.test index 962b5dcf..1bc04f4e 100755 --- a/tests/01_engine-parse.test +++ b/tests/01_engine-parse.test @@ -7,7 +7,8 @@ set -euo pipefail tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_parse.XXXXXX") || exit 1 -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM # a minimal valid 1x1 GIF, reused for every referenced asset gif() { diff --git a/tests/01_engine-rcfile.test b/tests/01_engine-rcfile.test index 4b01f5d4..f87b151e 100755 --- a/tests/01_engine-rcfile.test +++ b/tests/01_engine-rcfile.test @@ -30,7 +30,8 @@ case "$bin" in esac tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_rcfile.XXXXXX") || exit 1 -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM # HTS_HTTRACKRC is ".httrackrc" on POSIX but "httrackrc" on Windows: write both, # each platform reads the one it knows. diff --git a/tests/01_engine-reconcile.test b/tests/01_engine-reconcile.test index 9404adeb..dd3f5574 100644 --- a/tests/01_engine-reconcile.test +++ b/tests/01_engine-reconcile.test @@ -7,7 +7,7 @@ set -eu dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT out=$(httrack -#test=reconcile "$dir") diff --git a/tests/01_engine-savename.test b/tests/01_engine-savename.test index 72bbbe17..7c8a7de8 100755 --- a/tests/01_engine-savename.test +++ b/tests/01_engine-savename.test @@ -12,7 +12,7 @@ httrack_bin=$(cd "$(dirname "$(command -v httrack)")" && pwd)/httrack # scratch dir: body= and cached= write temp files (st-savename-body.tmp, hts-cache/) scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT cd "$scratch" run() { diff --git a/tests/01_engine-structcheck.test b/tests/01_engine-structcheck.test index b820a723..c1ee6ad5 100644 --- a/tests/01_engine-structcheck.test +++ b/tests/01_engine-structcheck.test @@ -6,7 +6,7 @@ set -euo pipefail dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=structcheck "$dir" | grep -q "structcheck self-test OK" diff --git a/tests/01_engine-threadwait.test b/tests/01_engine-threadwait.test index 58de10db..2b04581d 100644 --- a/tests/01_engine-threadwait.test +++ b/tests/01_engine-threadwait.test @@ -4,7 +4,8 @@ set -euo pipefail tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_threadwait_st.XXXXXX") || exit 1 -trap 'rm -rf "$tmpdir"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmpdir"' EXIT +trap 'rm -rf "$tmpdir"' HUP INT QUIT PIPE TERM # No pipe into grep: SIGPIPE would mask a failing exit status. expect_ok() { diff --git a/tests/01_engine-topindex.test b/tests/01_engine-topindex.test index 67286327..d53f9f1d 100755 --- a/tests/01_engine-topindex.test +++ b/tests/01_engine-topindex.test @@ -6,7 +6,7 @@ set -euo pipefail # hts_buildtopindex takes a system-charset path but verif_backblue below it # expects utf-8, mangling a non-ASCII project dir on Windows (#216, #217). dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=topindex "$dir" run | grep -q "topindex self-test OK" diff --git a/tests/01_zlib-acceptencoding.test b/tests/01_zlib-acceptencoding.test index 9f6fc39d..a3f664f4 100755 --- a/tests/01_zlib-acceptencoding.test +++ b/tests/01_zlib-acceptencoding.test @@ -5,7 +5,7 @@ set -euo pipefail # Accept-Encoding (#450): advertise gzip+deflate; decode gzip/zlib/raw-deflate. dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=acceptencoding "$dir" run | grep -q "acceptencoding self-test OK" diff --git a/tests/01_zlib-cache-corrupt.test b/tests/01_zlib-cache-corrupt.test index 7c6d963e..00064f5e 100644 --- a/tests/01_zlib-cache-corrupt.test +++ b/tests/01_zlib-cache-corrupt.test @@ -7,7 +7,7 @@ set -eu dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # the smashed-header case logs expected "Corrupted cache entry" warnings on # stdout; the verdict is the last line diff --git a/tests/01_zlib-cache-golden.test b/tests/01_zlib-cache-golden.test index 7997768d..2741f167 100644 --- a/tests/01_zlib-cache-golden.test +++ b/tests/01_zlib-cache-golden.test @@ -27,7 +27,7 @@ test -e "$fixture/hts-cache/new.zip" || { } dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # Read against a private copy so the source tree is never touched (a read # session does not write, but copying keeps the test hermetic). Create the dir diff --git a/tests/01_zlib-cache-legacy.test b/tests/01_zlib-cache-legacy.test index 9363270f..c025076e 100644 --- a/tests/01_zlib-cache-legacy.test +++ b/tests/01_zlib-cache-legacy.test @@ -6,7 +6,7 @@ set -eu dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # the refusal errors land on stdout (no log file); pin them and the verdict out=$(httrack -#test=cache-legacy "$dir" 2>/dev/null) diff --git a/tests/01_zlib-cache-writefail.test b/tests/01_zlib-cache-writefail.test index 5d276b76..9b3b72fa 100644 --- a/tests/01_zlib-cache-writefail.test +++ b/tests/01_zlib-cache-writefail.test @@ -11,7 +11,7 @@ set -eu dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT out=$(httrack -#test=cache-writefail "$dir") diff --git a/tests/01_zlib-cache.test b/tests/01_zlib-cache.test index ade2d056..e960cd28 100755 --- a/tests/01_zlib-cache.test +++ b/tests/01_zlib-cache.test @@ -18,7 +18,7 @@ set -eu dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # The working directory is a required argument; without it the test prints a # usage line to stderr and returns non-zero. diff --git a/tests/01_zlib-contentcodings.test b/tests/01_zlib-contentcodings.test index baa0f54a..406f2d54 100755 --- a/tests/01_zlib-contentcodings.test +++ b/tests/01_zlib-contentcodings.test @@ -5,7 +5,7 @@ set -euo pipefail # brotli/zstd decode, unknown codings, and the decoded-size budget. dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT httrack -O /dev/null -#test=contentcodings "$dir" run | grep -q "contentcodings self-test OK" diff --git a/tests/01_zlib-repair-shift.test b/tests/01_zlib-repair-shift.test index 5062164d..9bfec2ea 100644 --- a/tests/01_zlib-repair-shift.test +++ b/tests/01_zlib-repair-shift.test @@ -11,7 +11,7 @@ set -eu dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT out=$(httrack -#test=zip-repair-shift "$dir") diff --git a/tests/01_zlib-savename-cached.test b/tests/01_zlib-savename-cached.test index ec4c1342..412319c9 100644 --- a/tests/01_zlib-savename-cached.test +++ b/tests/01_zlib-savename-cached.test @@ -10,7 +10,7 @@ set -euo pipefail httrack_bin=$(cd "$(dirname "$(command -v httrack)")" && pwd)/httrack scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT cd "$scratch" name() { diff --git a/tests/01_zlib-warc-cdx.test b/tests/01_zlib-warc-cdx.test index 69aff28c..07216ad1 100755 --- a/tests/01_zlib-warc-cdx.test +++ b/tests/01_zlib-warc-cdx.test @@ -9,7 +9,7 @@ set -euo pipefail httrack_bin=$(cd "$(dirname "$(command -v httrack)")" && pwd)/httrack scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT out=$("$httrack_bin" -O /dev/null -#test=warc-cdx "$scratch/") echo "$out" diff --git a/tests/01_zlib-warc-wacz.test b/tests/01_zlib-warc-wacz.test index 965f9058..3ec42079 100755 --- a/tests/01_zlib-warc-wacz.test +++ b/tests/01_zlib-warc-wacz.test @@ -16,7 +16,7 @@ if ! "$httrack_bin" -#test 2>&1 | grep -q '^ warc-wacz'; then fi scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT out=$("$httrack_bin" -O /dev/null -#test=warc-wacz "$scratch/") echo "$out" diff --git a/tests/01_zlib-warc.test b/tests/01_zlib-warc.test index b28129f5..0ac88ccd 100755 --- a/tests/01_zlib-warc.test +++ b/tests/01_zlib-warc.test @@ -10,7 +10,7 @@ set -euo pipefail httrack_bin=$(cd "$(dirname "$(command -v httrack)")" && pwd)/httrack scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT for t in warc warc-trunc warc-ftp warc-rotate warc-verbatim; do out=$("$httrack_bin" -O /dev/null "-#test=$t" "$scratch/") diff --git a/tests/02_manpage-regen.test b/tests/02_manpage-regen.test index 35e68816..970d9d37 100755 --- a/tests/02_manpage-regen.test +++ b/tests/02_manpage-regen.test @@ -29,7 +29,7 @@ command -v httrack >/dev/null 2>&1 || { tmp=$(mktemp) || exit 1 committed_clean=$(mktemp) || exit 1 generated_clean=$(mktemp) || exit 1 -trap 'rm -f "$tmp" "$committed_clean" "$generated_clean"' EXIT +trap 'set +e; rm -f "$tmp" "$committed_clean" "$generated_clean"' EXIT README="$top_srcdir/README" bash "$gen" httrack >"$tmp" 2>/dev/null || { echo "makeman.sh failed" >&2 diff --git a/tests/02_update-cache.test b/tests/02_update-cache.test index 4158b9ee..f878e986 100755 --- a/tests/02_update-cache.test +++ b/tests/02_update-cache.test @@ -14,7 +14,7 @@ set -euo pipefail site=$(mktemp -d) out=$(mktemp -d) -trap 'rm -rf "$site" "$out"' EXIT +trap 'set +e; rm -rf "$site" "$out"' EXIT cat >"$site/index.html" <a b diff --git a/tests/13_crawl_proxy_https.test b/tests/13_crawl_proxy_https.test index 54184428..d14814dd 100644 --- a/tests/13_crawl_proxy_https.test +++ b/tests/13_crawl_proxy_https.test @@ -31,7 +31,7 @@ cleanup() { done rm -rf "$tmpdir" } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT # self-signed cert for the local TLS origin (httrack does not verify certs) openssl req -x509 -newkey rsa:2048 -keyout "$tmpdir/key.pem" \ diff --git a/tests/19_local-connect-fallback.test b/tests/19_local-connect-fallback.test index b54b3a68..2fc0dc17 100644 --- a/tests/19_local-connect-fallback.test +++ b/tests/19_local-connect-fallback.test @@ -40,9 +40,8 @@ serverpid= cleanup() { stop_server "$serverpid" rm -rf "$tmpdir" - return 0 } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT # bind the live server to 127.0.0.1 only, so 127.0.0.2 refuses the connect "$python" "$server" --root "$root" --bind 127.0.0.1 >"$tmpdir/srv.out" 2>"$tmpdir/srv.err" & diff --git a/tests/24_local-resume-overlap.test b/tests/24_local-resume-overlap.test index 0394764d..f021806d 100644 --- a/tests/24_local-resume-overlap.test +++ b/tests/24_local-resume-overlap.test @@ -24,7 +24,8 @@ cleanup() { stop_server "$serverpid" rm -rf "$tmpdir" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # OVERLAP_COUNTER gets a byte per flaky.bin request so pass 1 knows when to interrupt. serverlog="${tmpdir}/server.log" diff --git a/tests/40_local-why.test b/tests/40_local-why.test index 6a1e7a44..4a90d9ea 100644 --- a/tests/40_local-why.test +++ b/tests/40_local-why.test @@ -6,7 +6,7 @@ set -euo pipefail # --why: report which +/- filter rule decides for a URL, without crawling. tmpdir="$(mktemp -d)" -trap 'rm -rf "$tmpdir"' EXIT +trap 'set +e; rm -rf "$tmpdir"' EXIT why() { local want="$1" out diff --git a/tests/52_local-socks5.test b/tests/52_local-socks5.test index 5075e0ca..4c55b3e4 100644 --- a/tests/52_local-socks5.test +++ b/tests/52_local-socks5.test @@ -34,7 +34,7 @@ cleanup() { done rm -rf "$tmpdir" } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT openssl req -x509 -newkey rsa:2048 -keyout "$tmpdir/key.pem" \ -out "$tmpdir/cert.pem" -days 2 -nodes -subj "/CN=127.0.0.1" \ diff --git a/tests/53_local-proxytrack-arc-reason.test b/tests/53_local-proxytrack-arc-reason.test index 4d1f5b79..5f13529e 100644 --- a/tests/53_local-proxytrack-arc-reason.test +++ b/tests/53_local-proxytrack-arc-reason.test @@ -5,7 +5,7 @@ set -euo pipefail dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT printf 'HTTP/1.1 404 Not Found Here At All\r\nContent-Type: text/html\r\nLast-Modified: Wed, 01 Jan 2025 00:00:00 GMT\r\nContent-Length: 5\r\n\r\n' >"$dir/hdr" printf 'hello' >"$dir/body" diff --git a/tests/53_local-proxytrack-cache-corrupt.test b/tests/53_local-proxytrack-cache-corrupt.test index 39b5edea..3f44de5b 100644 --- a/tests/53_local-proxytrack-cache-corrupt.test +++ b/tests/53_local-proxytrack-cache-corrupt.test @@ -5,7 +5,7 @@ set -euo pipefail dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # The first length-prefixed field declares far more than firstline[256] holds; # cache_brstr must clamp the copy to the destination, not the declared length. diff --git a/tests/56_local-proxy-noleak.test b/tests/56_local-proxy-noleak.test index 4f32ecaf..d84dde02 100644 --- a/tests/56_local-proxy-noleak.test +++ b/tests/56_local-proxy-noleak.test @@ -29,9 +29,8 @@ serverpid= cleanup() { stop_server "$serverpid" rm -rf "$tmpdir" - return 0 } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT # decoy origin: it must stay silent. LOCAL_SERVER_VERBOSE logs any request it gets. LOCAL_SERVER_VERBOSE=1 "$python" "$server" --root "$root" --bind 127.0.0.1 \ diff --git a/tests/57_local-proxy-connect.test b/tests/57_local-proxy-connect.test index 3564274e..e8b675d9 100644 --- a/tests/57_local-proxy-connect.test +++ b/tests/57_local-proxy-connect.test @@ -29,7 +29,7 @@ cleanup() { done rm -rf "$tmpdir" } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT # start_server : launches a proxy+origin pair, sets $origin_port # and $proxy_port from its announced ephemeral ports. diff --git a/tests/58_watchdog.test b/tests/58_watchdog.test index b9d80f1b..4dafdba7 100644 --- a/tests/58_watchdog.test +++ b/tests/58_watchdog.test @@ -12,7 +12,7 @@ testdir=$(cd "$(dirname "$0")" && pwd) . "${testdir}/testlib.sh" tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_wd.XXXXXX") -trap 'rm -rf "$tmp"' EXIT +trap 'set +e; rm -rf "$tmp"' EXIT fail() { echo "FAIL: $*" >&2 exit 1 diff --git a/tests/59_local-tls-stall.test b/tests/59_local-tls-stall.test index f6eb0914..17d00180 100644 --- a/tests/59_local-tls-stall.test +++ b/tests/59_local-tls-stall.test @@ -27,9 +27,8 @@ serverpid= cleanup() { stop_server "$serverpid" rm -rf "$tmpdir" - return 0 } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT # start_stall_server : sets $port from the announced one. start_stall_server() { diff --git a/tests/60_crawl-log-salvage.test b/tests/60_crawl-log-salvage.test index b42f6005..fceb87da 100644 --- a/tests/60_crawl-log-salvage.test +++ b/tests/60_crawl-log-salvage.test @@ -12,7 +12,7 @@ testdir=$(cd "$(dirname "$0")" && pwd) TMPDIR=$(mktemp -d "${TMPDIR:-/tmp}/httrack_salv.XXXXXX") export TMPDIR -trap 'rm -rf "$TMPDIR"' EXIT +trap 'set +e; rm -rf "$TMPDIR"' EXIT fail() { echo "FAIL: $*" >&2 exit 1 diff --git a/tests/62_lang-integrity.test b/tests/62_lang-integrity.test index 160dec7a..81832d6d 100644 --- a/tests/62_lang-integrity.test +++ b/tests/62_lang-integrity.test @@ -19,7 +19,7 @@ for f in "$eng" "$def"; do done tmp=$(mktemp -d) -trap 'rm -rf "$tmp"' EXIT +trap 'set +e; rm -rf "$tmp"' EXIT keys="$tmp/english.keys" # Byte-wise: each file is in its own declared legacy charset, lang.def is CRLF. diff --git a/tests/63_webhttrack-home.test b/tests/63_webhttrack-home.test index 9b852482..b5073ea1 100644 --- a/tests/63_webhttrack-home.test +++ b/tests/63_webhttrack-home.test @@ -25,10 +25,11 @@ srv= cleanup() { test -z "${srv}" || kill -9 "${srv}" 2>/dev/null || true } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM log=$(mktemp) -trap 'cleanup; rm -f "${log}"' EXIT +trap 'set +e; cleanup; rm -f "${log}"' EXIT # Ask htsserver for its rendered default base path, under the given $HOME # ("-" = leave $HOME unset). diff --git a/tests/65_port-siblings.test b/tests/65_port-siblings.test index 61459a66..722de8f5 100644 --- a/tests/65_port-siblings.test +++ b/tests/65_port-siblings.test @@ -14,7 +14,8 @@ testdir=$(cd "$(dirname "$0")" && pwd) . "${testdir}/testlib.sh" tmp=$(mktemp -d "${TMPDIR:-/tmp}/httrack_portsib.XXXXXX") || exit 1 -trap 'rm -rf "$tmp"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmp"' EXIT +trap 'rm -rf "$tmp"' HUP INT QUIT PIPE TERM # A port the old code accepted only by wrapping: 4295009395 = 2^32 + 42099 and # 4294967376 = 2^32 + 80 both fold to a plausible listen port. They are the diff --git a/tests/67_engine-delayed-truncate.test b/tests/67_engine-delayed-truncate.test index 7d2eff06..cdd428be 100755 --- a/tests/67_engine-delayed-truncate.test +++ b/tests/67_engine-delayed-truncate.test @@ -14,7 +14,7 @@ set -euo pipefail httrack_bin=$(cd "$(dirname "$(command -v httrack)")" && pwd)/httrack scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT cd "$scratch" hexseg=$(printf 'a1b2c3d4e5f60718%.0s' {1..8}) # 128 hex chars diff --git a/tests/68_webhttrack-outdir-charset.test b/tests/68_webhttrack-outdir-charset.test index c8e9c8bd..34272916 100755 --- a/tests/68_webhttrack-outdir-charset.test +++ b/tests/68_webhttrack-outdir-charset.test @@ -36,7 +36,8 @@ cleanup() { wait "${srv}" 2>/dev/null || true # absorb bash's async "Killed" notice rm -rf "${work}" "${srvlog}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # webhttrack server on a pre-picked port; an isolated HOME keeps a stray # ~/.httrack.ini out of it. diff --git a/tests/75_engine-longpath-posix.test b/tests/75_engine-longpath-posix.test index 2ca9701e..704a0697 100755 --- a/tests/75_engine-longpath-posix.test +++ b/tests/75_engine-longpath-posix.test @@ -9,7 +9,7 @@ set -euo pipefail httrack_bin=$(cd "$(dirname "$(command -v httrack)")" && pwd)/httrack scratch=$(mktemp -d) -trap 'rm -rf "$scratch"' EXIT +trap 'set +e; rm -rf "$scratch"' EXIT cd "$scratch" # ~300 chars: over the old 236 ceiling, well under any POSIX PATH_MAX. The diff --git a/tests/76_cli-resize.test b/tests/76_cli-resize.test index 27bb0c11..64e52999 100644 --- a/tests/76_cli-resize.test +++ b/tests/76_cli-resize.test @@ -23,7 +23,8 @@ cleanup() { stop_server "$serverpid" rm -rf "$tmpdir" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM serverlog="${tmpdir}/server.log" : >"$serverlog" diff --git a/tests/77_webhttrack-redirect.test b/tests/77_webhttrack-redirect.test index bd57dac8..2618cbbc 100644 --- a/tests/77_webhttrack-redirect.test +++ b/tests/77_webhttrack-redirect.test @@ -32,7 +32,8 @@ cleanup() { stop rm -f "${log}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM freeport() { python3 -c 'import socket diff --git a/tests/78_webhttrack-sid.test b/tests/78_webhttrack-sid.test index 4cf971bf..f5dd6791 100644 --- a/tests/78_webhttrack-sid.test +++ b/tests/78_webhttrack-sid.test @@ -26,7 +26,8 @@ cleanup() { test -z "${srv}" || kill -9 "${srv}" 2>/dev/null || true rm -f "${log}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM freeport() { python3 -c 'import socket diff --git a/tests/79_local-proxytrack-webdav-mime.test b/tests/79_local-proxytrack-webdav-mime.test index 8af0d9b9..c0b71f16 100755 --- a/tests/79_local-proxytrack-webdav-mime.test +++ b/tests/79_local-proxytrack-webdav-mime.test @@ -30,7 +30,7 @@ cleanup() { stop_server "$ptpid" rm -rf "$dir" } -trap cleanup EXIT +trap 'set +e; cleanup' EXIT # Neither header is present, so file->contenttype and ->lastmodified stay "". printf 'HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n' >"$dir/hdr" diff --git a/tests/80_engine-crash-symbolize.test b/tests/80_engine-crash-symbolize.test index 52c72c63..de958991 100644 --- a/tests/80_engine-crash-symbolize.test +++ b/tests/80_engine-crash-symbolize.test @@ -17,7 +17,8 @@ command -v httrack >/dev/null || { } tmpdir=$(mktemp -d "${TMPDIR:-/tmp}/httrack_symbolize.XXXXXX") || exit 1 -trap 'rm -rf "$tmpdir"' EXIT HUP INT QUIT PIPE TERM +trap 'set +e; rm -rf "$tmpdir"' EXIT +trap 'rm -rf "$tmpdir"' HUP INT QUIT PIPE TERM out="${tmpdir}/trace" raw="${tmpdir}/trace-optout" overflow="this string is far too long for the buffer" diff --git a/tests/81_webhttrack-maxsize.test b/tests/81_webhttrack-maxsize.test index a4e84717..530beebb 100644 --- a/tests/81_webhttrack-maxsize.test +++ b/tests/81_webhttrack-maxsize.test @@ -32,7 +32,8 @@ cleanup() { srv= rm -rf "${work}" "${srvlog}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # webhttrack server on a pre-picked port; an isolated HOME keeps a stray # ~/.httrack.ini out of it. diff --git a/tests/82_webhttrack-browse-links.test b/tests/82_webhttrack-browse-links.test index 367cb209..3ec02d38 100644 --- a/tests/82_webhttrack-browse-links.test +++ b/tests/82_webhttrack-browse-links.test @@ -38,7 +38,8 @@ cleanup() { wait "${srv}" 2>/dev/null || true # absorb bash's async "Killed" notice rm -rf "${work}" "${srvlog}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # Stand in for a finished mirror: the crawl itself is not under test. proj="${work}/websites/proj" diff --git a/tests/83_webhttrack-argescape.test b/tests/83_webhttrack-argescape.test index 9effc55f..9e349fa2 100755 --- a/tests/83_webhttrack-argescape.test +++ b/tests/83_webhttrack-argescape.test @@ -27,7 +27,8 @@ cleanup() { test -z "${srv}" || kill -9 "${srv}" 2>/dev/null || true rm -f "${log}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM freeport() { python3 -c 'import socket diff --git a/tests/84_webhttrack-mirror-verbatim.test b/tests/84_webhttrack-mirror-verbatim.test index 3bc9d990..840d7574 100644 --- a/tests/84_webhttrack-mirror-verbatim.test +++ b/tests/84_webhttrack-mirror-verbatim.test @@ -34,7 +34,8 @@ cleanup() { wait "${csrv}" 2>/dev/null || true # absorb bash's async "Killed" notice rm -rf "${log}" "${work}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM freeport() { python3 -c 'import socket diff --git a/tests/85_webhttrack-projpath.test b/tests/85_webhttrack-projpath.test index 2e4db823..74c28c1d 100644 --- a/tests/85_webhttrack-projpath.test +++ b/tests/85_webhttrack-projpath.test @@ -28,7 +28,8 @@ cleanup() { rm -f "${log}" rm -rf "${base}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM freeport() { python3 -c 'import socket diff --git a/tests/86_local-proxytrack-cache-longfields.test b/tests/86_local-proxytrack-cache-longfields.test index f6c47aea..cf20f422 100755 --- a/tests/86_local-proxytrack-cache-longfields.test +++ b/tests/86_local-proxytrack-cache-longfields.test @@ -9,7 +9,7 @@ testdir=$(cd "$(dirname "$0")" && pwd) . "${testdir}/testlib.sh" dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT pad() { printf "%${1}s" '' | tr ' ' "$2"; } diff --git a/tests/87_local-proxytrack-nodate.test b/tests/87_local-proxytrack-nodate.test index 1638b717..c3d27c2e 100755 --- a/tests/87_local-proxytrack-nodate.test +++ b/tests/87_local-proxytrack-nodate.test @@ -5,7 +5,7 @@ set -euo pipefail dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # $1 Last-Modified value (empty = omit the header), $2 expected archive date, # $3 label. The date is asserted exactly: a guard that fires unconditionally diff --git a/tests/88_local-proxytrack-badmtime.test b/tests/88_local-proxytrack-badmtime.test index fb689996..70ec618e 100755 --- a/tests/88_local-proxytrack-badmtime.test +++ b/tests/88_local-proxytrack-badmtime.test @@ -14,7 +14,7 @@ python=$(find_python) || { } dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT rc=0 "$python" - "$dir/in.zip" <<'EOF' || rc=$? diff --git a/tests/89_webhttrack-error-overflow.test b/tests/89_webhttrack-error-overflow.test index deecf594..4febfade 100644 --- a/tests/89_webhttrack-error-overflow.test +++ b/tests/89_webhttrack-error-overflow.test @@ -33,7 +33,8 @@ cleanup() { rm -f "${log}" rm -rf "${base}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM freeport() { python3 -c 'import socket diff --git a/tests/90_webhttrack-checkbox-clear.test b/tests/90_webhttrack-checkbox-clear.test index 3982b429..110c3222 100755 --- a/tests/90_webhttrack-checkbox-clear.test +++ b/tests/90_webhttrack-checkbox-clear.test @@ -33,7 +33,8 @@ cleanup() { wait "${srv}" 2>/dev/null || true # absorb bash's async "Killed" notice rm -rf "${work}" "${srvlog}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # An isolated HOME keeps a stray ~/.httrack.ini out of the served settings. sport=$("${python}" -c 'import socket diff --git a/tests/91_webhttrack-directory.test b/tests/91_webhttrack-directory.test index 74879742..91b8cb50 100644 --- a/tests/91_webhttrack-directory.test +++ b/tests/91_webhttrack-directory.test @@ -28,7 +28,8 @@ cleanup() { rm -f "${log}" rm -rf "${base}" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # First line only. A "| head -1" would close the pipe early and, under pipefail, # SIGPIPE the producer into a spurious failure. diff --git a/tests/92_local-proxytrack-ndx-fields.test b/tests/92_local-proxytrack-ndx-fields.test index 779ccd61..a534b848 100644 --- a/tests/92_local-proxytrack-ndx-fields.test +++ b/tests/92_local-proxytrack-ndx-fields.test @@ -15,7 +15,7 @@ python=$(find_python) || { } dir=$(mktemp -d) -trap 'rm -rf "$dir"' EXIT +trap 'set +e; rm -rf "$dir"' EXIT # each field fills binput's own bound, so together they run one past line[] "$python" - "$dir/foo.ndx" <<'EOF' diff --git a/tests/93_local-changes.test b/tests/93_local-changes.test index 63a6ed23..a2ff22a5 100644 --- a/tests/93_local-changes.test +++ b/tests/93_local-changes.test @@ -19,7 +19,8 @@ cleanup() { stop_server "$serverpid" rm -rf "$tmpdir" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM serverlog="${tmpdir}/server.log" : >"$serverlog" diff --git a/tests/94_local-single-file.test b/tests/94_local-single-file.test index 7e73f085..d9cd564b 100644 --- a/tests/94_local-single-file.test +++ b/tests/94_local-single-file.test @@ -22,7 +22,8 @@ cleanup() { htssrv= rm -rf "$tmpdir" } -trap cleanup EXIT HUP INT QUIT PIPE TERM +trap 'set +e; cleanup' EXIT +trap cleanup HUP INT QUIT PIPE TERM # --- the site --------------------------------------------------------------- doc="${tmpdir}/doc" diff --git a/tests/99_teardown-status.test b/tests/99_teardown-status.test new file mode 100644 index 00000000..b69d7405 --- /dev/null +++ b/tests/99_teardown-status.test @@ -0,0 +1,81 @@ +#!/bin/bash +# +# Issue #773: a test must fail only when an assertion fails. Under "set -e" a +# failing command in an EXIT trap becomes the script's exit status, so a +# teardown hiccup turned a test whose assertions all passed into a red CI leg. + +set -euo pipefail + +: "${top_srcdir:=..}" + +tmp=$(mktemp -d) +trap 'set +e; rm -rf "$tmp"' EXIT + +fail() { + echo "FAIL: $1" >&2 + exit 1 +} + +# run : exit status and stderr of a subject script. +run() { + { + echo "set -euo pipefail" + # printf, so the scanner below does not read this as a trap of our own + printf 'trap %s EXIT\n' "$1" + echo "$2" + } >"$tmp/subject" + rc=0 + err=$(bash "$tmp/subject" 2>&1 >/dev/null) || rc=$? +} + +# 1. the shape in the tree: teardown fails, every assertion passed -> pass +run "'set +e; false'" "true" +test "$rc" -eq 0 || fail "guarded teardown failure exited $rc, want 0" + +# 2. teeth for case 1: unguarded, the same teardown is what went red +run "'false'" "true" +test "$rc" -eq 1 || fail "unguarded teardown failure exited $rc, want 1" + +# 3. the guard must not swallow a real failure, nor a skip +run "'set +e; false'" "exit 1" +test "$rc" -eq 1 || fail "assertion failure exited $rc, want 1" +run "'set +e; false'" "exit 77" +test "$rc" -eq 77 || fail "skip exited $rc, want 77" + +# 4. not failing must not mean going quiet: teardown still reports why +run "'set +e; rm /nonexistent-teardown-probe'" "true" +test "$rc" -eq 0 || fail "guarded teardown failure exited $rc, want 0" +case "$err" in +*nonexistent-teardown-probe*) ;; +*) fail "teardown error was silenced (stderr: '$err')" ;; +esac +echo "OK: teardown cannot decide the verdict, and still reports" + +# 5. no test may reintroduce the shape case 2 pins. Two spellings neutralise +# errexit for teardown: "set +e" first, or "|| true" over the whole body. +scanned=0 +for f in "$top_srcdir"/tests/*.test "$top_srcdir"/tests/*.sh; do + test -r "$f" || continue + scanned=$((scanned + 1)) +done +# an unexpanded glob would report no offender having read nothing +test "$scanned" -ge 50 || fail "scanned $scanned scripts in $top_srcdir/tests, want the whole suite" + +bad=$(awk ' + FNR == 1 { errexit = 0 } + /^[[:space:]]*set[[:space:]]+(-[a-z]*e|-o[[:space:]]+errexit)/ { errexit = 1 } + !errexit { next } + !/^[[:space:]]*trap[[:space:]]+.*[[:space:]]EXIT([[:space:]]|;|$)/ { next } + { + guarded = /^[[:space:]]*trap[[:space:]]+.set \+e; / || /\|\|[[:space:]]+true.[[:space:]]+EXIT/ + if (!guarded) + print FILENAME ":" FNR " unguarded" + # "set +e" on a trap shared with a signal leaves errexit off for the + # rest of the run, so a torn-down test could still report success + else if (/^[[:space:]]*trap[[:space:]]+.set \+e; / && /[[:space:]]EXIT[[:space:]]+[A-Z]/) + print FILENAME ":" FNR " set +e shared with a signal trap" + } +' "$top_srcdir"/tests/*.test "$top_srcdir"/tests/*.sh) +test -z "$bad" || fail "EXIT trap can decide the verdict: +$bad" +echo "OK: every EXIT trap under set -e runs teardown with errexit off" diff --git a/tests/Makefile.am b/tests/Makefile.am index fe1bca09..7cb4064a 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -200,6 +200,7 @@ TESTS = \ 95_local-sitemap.test \ 96_local-refetch-keep.test \ 97_local-warc-update-keep.test \ - 98_local-warc-segments.test + 98_local-warc-segments.test \ + 99_teardown-status.test CLEANFILES = check-network_sh.cache diff --git a/tests/webhttrack-smoke.sh b/tests/webhttrack-smoke.sh index 821fc369..0c1c7e6f 100644 --- a/tests/webhttrack-smoke.sh +++ b/tests/webhttrack-smoke.sh @@ -13,7 +13,7 @@ test -x "$wht" || { work="$(mktemp -d)" # webhttrack backgrounds htsserver, which outlives it; reap any stray one (scoped # to this prefix) so a lingering server can never hold the CI step open. -trap 'pkill -f "$prefix/bin/htsserver" 2>/dev/null || true; rm -rf "$work"' EXIT +trap 'set +e; pkill -f "$prefix/bin/htsserver" 2>/dev/null || true; rm -rf "$work"' EXIT export HOME="$work/home" mkdir -p "$HOME/websites" marker="$work/marker"