Skip to content

Commit 44a3b60

Browse files
rustyconoverclaude
andcommitted
ci(integration): fail on a fatal-signal report the exit code can't express
Catch2 arms signal handlers for the duration of each test case, and forked children of the extension inherit them until they exec. A signal landing in that window makes the child print a "due to a fatal error condition" block plus a run summary -- the parent's counters, since it's an address-space copy -- and die. The parent records nothing and exits 0. Run 29051359074's shm lane was green with exactly that block in its log. Scan the captured output and fail the lane when it appears. The underlying fork window is fixed in Query-farm/vgi (SubProcess et al. now reset signal dispositions in the child), but this class of failure can never reach the exit code, so the guard is worth keeping regardless of source. Use `set +e` around the pipeline rather than `|| true`: the latter runs before PIPESTATUS is read and overwrites it with true's 0, which would have silently swallowed every real test failure in the suite. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 418700f commit 44a3b60

1 file changed

Lines changed: 34 additions & 3 deletions

File tree

‎ci/run-integration.sh‎

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,12 +257,43 @@ rm -f "$STAGE/test/_warm.test"
257257
# simple_writable); the http lane's writes self-skip.
258258
echo "Running suite ($SUITE_GLOB, transport=$TRANSPORT) ..."
259259
suite_rc=0
260+
261+
# run_unittest — invoke haybarn-unittest, streaming its output, and additionally
262+
# fail on a fatal-signal report that the process's own exit code cannot express.
263+
#
264+
# Catch2 arms handlers for SIGTERM/SIGINT/SIGSEGV/... for the duration of a test
265+
# case. Those handlers are inherited by any process the extension fork()s, and
266+
# run in the child if a signal lands before it execs. The child then prints a
267+
# full "FAILED: ... due to a fatal error condition: SIGTERM" block plus a run
268+
# summary — the *parent's* accumulated counters, since it's an address-space
269+
# copy — and dies. The parent never sees it, records no failure, and exits 0.
270+
# The only trace is on stdout, so that is what we scan. Seen on the shm lane in
271+
# https://github.com/Query-farm/vgi-python/actions/runs/29051359074.
272+
run_unittest() {
273+
local log rc=0
274+
log="$(mktemp)"
275+
# `set +e` rather than `|| true`: the latter runs before PIPESTATUS is read and
276+
# overwrites it with true's 0, silently swallowing every real test failure.
277+
set +e
278+
"$HAYBARN_UNITTEST" "$@" 2>&1 | tee "$log"
279+
rc="${PIPESTATUS[0]}"
280+
set -e
281+
if grep -q 'due to a fatal error condition' "$log"; then
282+
echo "::error::a forked child ran the test harness's signal handler (see the" \
283+
"'fatal error condition' block above). The parent exited $rc and would" \
284+
"otherwise have passed. This is invisible to the exit code by construction."
285+
rc=1
286+
fi
287+
rm -f "$log"
288+
return "$rc"
289+
}
290+
260291
if [ "$TRANSPORT" = "launch" ]; then
261-
"$HAYBARN_UNITTEST" "$SUITE_GLOB" || suite_rc=$?
292+
run_unittest "$SUITE_GLOB" || suite_rc=$?
262293
else
263-
"$HAYBARN_UNITTEST" "$SUITE_GLOB" "~test/sql/integration/simple_writable/*" || suite_rc=$?
294+
run_unittest "$SUITE_GLOB" "~test/sql/integration/simple_writable/*" || suite_rc=$?
264295
echo "Running simple_writable (isolated process) ..."
265-
"$HAYBARN_UNITTEST" "test/sql/integration/simple_writable/*" || suite_rc=$?
296+
run_unittest "test/sql/integration/simple_writable/*" || suite_rc=$?
266297
fi
267298

268299
exit "$suite_rc"

0 commit comments

Comments
 (0)