You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A test killed by --test-timeout never runs its tear_down. The watchdog signals the test's process group, the subshell dies without running its EXIT trap, and bashunit::runner::cleanup_on_exit never calls the hook.
Same class as #1318, at test scope. The file-scoped pair survives a timeout, because the loop keeps going and runs tear_down_after_script. The per-test pair does not.
This is the opposite asymmetry from #1323, where tear_down runs and tear_down_after_script does not. Both are the same missing guarantee seen from two sides.
Current behavior
The test is reported as Test timed out after 1s, the run continues, and whatever set_up acquired for that test is left behind.
$ CLEANUP_MARKER=/tmp/bu-to.marker ./bashunit --no-parallel --test-timeout 1 timeout_test.sh
✗ Error: Hangs
Test timed out after 1s
$ ls /tmp/bu-to.marker.*
/tmp/bu-to.marker.RAN_FILE_TEARDOWN
/tmp/bu-to.marker.setupfile
/tmp/bu-to.marker.setuptest
RAN_TEST_TEARDOWN is absent. The per-test set_up ran, its tear_down did not.
Verified on bash 3.2.57. Bash's default SIGTERM handling inside a forked subshell has changed across versions, so confirm on bash 5 before choosing a fix. A closely related path behaves differently on the same machine: pkill -P $$ on Ctrl-C does let the EXIT trap run.
Expected behavior
A timed-out test runs tear_down, so a per-test resource can be released. The timeout still bounds the run.
Where it happens
src/runner/exec.sh:363: the test body is spawned as (bashunit::runner::execute_test_body ...) & under set -m
src/runner/exec.sh:399-402: the watchdog writes the marker, sends kill -TERM -"$test_pid" to the group, sleeps 0.3s, then kill -KILL -"$test_pid"
src/runner/hooks.sh:37: bashunit::runner::run_tear_down lives in cleanup_on_exit, the subshell's EXIT trap, which never fires
src/runner/hooks.sh:38-40: clear_mocks and cleanup_testcase_temp_files are skipped on the same path
Acceptance criteria
An acceptance test: --test-timeout 1 against a hanging test whose tear_down releases a resource, asserted gone.
The Test timed out after Ns message and the failure classification are unchanged. tests/acceptance timeout coverage still passes.
A tear_down that hangs cannot extend the run past the watchdog's KILL. The 0.3s grace, or whatever replaces it, still bounds the process.
Verified on bash 3.2 and bash 5. The make test-bash-3 path exists for the first.
--parallel runs behave the same way.
CHANGELOG.md gets a Fixed entry.
Notes for the implementer
Trapping TERM inside the test-body subshell so the EXIT trap gets a chance is the direct fix. The 0.3s between TERM and KILL is the whole budget the hook gets, so measure whether that is enough or has to grow.
Weigh the tradeoff and write the decision down: a teardown that never returns is worse than a teardown that never runs. A bounded best-effort hook is the useful behaviour, not an unbounded one.
Summary
A test killed by
--test-timeoutnever runs itstear_down. The watchdog signals the test's process group, the subshell dies without running itsEXITtrap, andbashunit::runner::cleanup_on_exitnever calls the hook.Same class as #1318, at test scope. The file-scoped pair survives a timeout, because the loop keeps going and runs
tear_down_after_script. The per-test pair does not.This is the opposite asymmetry from #1323, where
tear_downruns andtear_down_after_scriptdoes not. Both are the same missing guarantee seen from two sides.Current behavior
The test is reported as
Test timed out after 1s, the run continues, and whateverset_upacquired for that test is left behind.How to reproduce
timeout_test.sh:RAN_TEST_TEARDOWNis absent. The per-testset_upran, itstear_downdid not.Verified on bash 3.2.57. Bash's default
SIGTERMhandling inside a forked subshell has changed across versions, so confirm on bash 5 before choosing a fix. A closely related path behaves differently on the same machine:pkill -P $$on Ctrl-C does let theEXITtrap run.Expected behavior
A timed-out test runs
tear_down, so a per-test resource can be released. The timeout still bounds the run.Where it happens
src/runner/exec.sh:363: the test body is spawned as(bashunit::runner::execute_test_body ...) &underset -msrc/runner/exec.sh:399-402: the watchdog writes the marker, sendskill -TERM -"$test_pid"to the group, sleeps 0.3s, thenkill -KILL -"$test_pid"src/runner/hooks.sh:37:bashunit::runner::run_tear_downlives incleanup_on_exit, the subshell'sEXITtrap, which never firessrc/runner/hooks.sh:38-40:clear_mocksandcleanup_testcase_temp_filesare skipped on the same pathAcceptance criteria
--test-timeout 1against a hanging test whosetear_downreleases a resource, asserted gone.Test timed out after Nsmessage and the failure classification are unchanged.tests/acceptancetimeout coverage still passes.tear_downthat hangs cannot extend the run past the watchdog'sKILL. The 0.3s grace, or whatever replaces it, still bounds the process.make test-bash-3path exists for the first.--parallelruns behave the same way.CHANGELOG.mdgets aFixedentry.Notes for the implementer
TERMinside the test-body subshell so theEXITtrap gets a chance is the direct fix. The0.3sbetweenTERMandKILLis the whole budget the hook gets, so measure whether that is enough or has to grow.src/runner/exec.sh:366-390explain why it is detached and why it re-checkskill -0. Do not break that. The suites acceptance test is flaky on Bash 3.0 under load #1137 is the receipt..claude/rules/bash-style.md.make sa,make lint,./bashunit tests/,./bashunit --parallel tests/.