Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
- Snapshot mismatches show a readable line diff even when `git` is unavailable (expected lines prefixed `-`, actual `+`) (#679)
- Failure output now includes the originating test `file:line` (`at <file>:<line>`) (#680)
- Project config file `.bashunitrc` (`KEY=value` lines); precedence is CLI flag > env var / `.env` > `.bashunitrc` > default; honors `--skip-env-file` (#681)
- Killed tests now report a specific cause instead of a bare "Killed": timeout (124), SIGINT (130), SIGKILL/OOM (137), SIGTERM (143), or "Killed by signal N" (#683)

### Fixed
- `bashunit watch` now forwards `--filter` (and other flags) to each run regardless of position, and no longer mangles forwarded arguments (#682)
Expand Down
39 changes: 39 additions & 0 deletions src/runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,32 @@ function bashunit::runner::detect_runtime_error() {
printf ''
}

##
# Maps a process exit code to a human-readable description when it indicates the
# test was killed by a signal (128 + signal) or timed out. Returns an empty
# string for ordinary exit codes. Bash 3.0+ compatible.
# Arguments: $1 exit code
##
function bashunit::runner::classify_kill_signal() {
local code=$1

case "$code" in
124) printf 'Timed out (killed by `timeout`)' ;;
130) printf 'Interrupted (SIGINT)' ;;
137) printf 'Killed (SIGKILL — out of memory or forced termination)' ;;
143) printf 'Terminated (SIGTERM — e.g. a timeout)' ;;
*)
# Generic "killed by signal N" for other 128+N codes (signals 1..64)
case "$code" in
'' | *[!0-9]*) return 0 ;;
esac
if [ "$code" -gt 128 ] && [ "$code" -le 192 ]; then
printf 'Killed by signal %s' "$((code - 128))"
fi
;;
esac
}

function bashunit::runner::print_verbose_test_summary() {
local test_file=$1
local fn_name=$2
Expand Down Expand Up @@ -945,6 +971,19 @@ function bashunit::runner::run_test() {
elif [ -z "$error_message" ] && [ -n "$hook_message" ]; then
error_message="$hook_message"
fi

# When the test was killed by a signal (or timed out), replace an empty or
# generic "Killed" message with a specific cause.
if [ -z "$hook_failure" ]; then
local kill_message
kill_message=$(bashunit::runner::classify_kill_signal "$test_exit_code")
if [ -n "$kill_message" ]; then
case "$error_message" in
'' | *[Kk]illed* | *[Tt]erminated*) error_message="$kill_message" ;;
esac
fi
fi

bashunit::console_results::print_error_test "$failure_function" "$error_message" "$runtime_output"
bashunit::reports::add_test_failed "$test_file" "$failure_label" "$duration" "$total_assertions" "$error_message"
bashunit::runner::write_failure_result_output "$test_file" "$failure_function" "$error_message" "$runtime_output"
Expand Down
28 changes: 28 additions & 0 deletions tests/unit/runner_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -204,3 +204,31 @@ function test_compute_total_assertions_does_not_touch_caller_locals() {
assert_same "5" "$_BASHUNIT_RUNNER_TOTAL_OUT"
assert_same "##ASSERTIONS_PASSED=4##ASSERTIONS_FAILED=1" "$test_execution_result"
}

function test_classify_kill_signal_sigkill_mentions_oom() {
local output
output="$(bashunit::runner::classify_kill_signal 137)"

assert_contains "SIGKILL" "$output"
assert_contains "memory" "$output"
}

function test_classify_kill_signal_sigterm() {
assert_contains "SIGTERM" "$(bashunit::runner::classify_kill_signal 143)"
}

function test_classify_kill_signal_timeout() {
assert_contains "Timed out" "$(bashunit::runner::classify_kill_signal 124)"
}

function test_classify_kill_signal_sigint() {
assert_contains "SIGINT" "$(bashunit::runner::classify_kill_signal 130)"
}

function test_classify_kill_signal_generic_signal() {
assert_contains "signal 6" "$(bashunit::runner::classify_kill_signal 134)"
}

function test_classify_kill_signal_empty_for_normal_exit() {
assert_empty "$(bashunit::runner::classify_kill_signal 1)"
}
Loading