#!/bin/bash ## Tests for `pave run`: phase and host file selection, failure semantics, chains, reports. # shellcheck source=tests/testlib.bash source "${BASH_SOURCE[0]%/*}/testlib.bash" # ---- file selection: common file, then this host's file, and no other host's ---- G="$scratch/select" goals "$G/manual.bash" <<<'echo common-ran' goals "$G/boot.bash" <<<'echo boot-ran' goals "$G/hosts/testhost/manual.bash" <<<'echo host-ran' goals "$G/hosts/otherhost/manual.bash" <<<'echo otherhost-ran' pv run "$G" manual assert_eq "selection: exit 0" 0 "$rc" assert_eq "selection: common then host, nothing else" $'common-ran\nhost-ran' "$out" # ---- top-level failures are recorded and the file carries on ---- G="$scratch/toplevel" goals "$G/manual.bash" <<'EOF' false echo after-first x=$(exit 3) echo after-cmdsubst false EOF pv run "$G" manual assert_eq "toplevel: exit 7" 7 "$rc" assert_has "toplevel: failure located" "pave: FAIL: exit 1 at ./manual.bash:1" assert_has "toplevel: carried on after failure" "after-first" assert_has "toplevel: cmdsubst failure located" "pave: FAIL: exit 3 at ./manual.bash:3" assert_has "toplevel: carried on after cmdsubst" "after-cmdsubst" assert_has "toplevel: last-line failure located" "pave: FAIL: exit 1 at ./manual.bash:5" assert_count "toplevel: each failure recorded once" "pave: FAIL" 3 assert_has "toplevel: summary counts" "pave: manual: 0 changed, 3 failed" # ---- chains stop at their first failure; the file carries on after them ---- G="$scratch/chains" goals "$G/manual.bash" <<'EOF' ( chain first echo first-a false echo first-b-SHOULD-NOT-RUN ) echo between helper() { echo helper-a false echo helper-b-SHOULD-NOT-RUN } ( chain viafunc helper echo viafunc-SHOULD-NOT-RUN ) inner() { ( chain inner false ) } ( chain outer inner echo outer-SHOULD-NOT-RUN ) ( chain ok echo ok-a true echo ok-b ) EOF pv run "$G" manual assert_eq "chains: exit 7" 7 "$rc" assert_lacks "chains: nothing after a failure ran" "SHOULD-NOT-RUN" assert_has "chains: failure named and located" "pave: FAIL: chain first: exit 1 at ./manual.bash:3" assert_has "chains: file carried on" "between" assert_has "chains: failure inside a called function stops the chain" "helper-a" assert_has "chains: nested failure recorded at the innermost chain" "pave: FAIL: chain inner: exit 1" assert_count "chains: each failed chain recorded once" "pave: FAIL" 3 assert_has "chains: a chain that doesn't fail runs to the end" "ok-b" # ---- chain outside a subshell is refused, and doesn't switch on errexit ---- G="$scratch/badchain" goals "$G/manual.bash" <<'EOF' chain oops false echo still-running ( chain ) EOF pv run "$G" manual assert_eq "bad chain: exit 7" 7 "$rc" assert_has "bad chain: refusal explained" "chain oops: not inside ( ... )" assert_has "bad chain: refusal recorded" "pave: FAIL: exit 1 at ./manual.bash:1" assert_has "bad chain: errexit stayed off" "still-running" assert_has "bad chain: nameless chain refused" "usage: ( chain NAME ... )" # ---- whole-file aborts: unset variables, syntax errors ---- G="$scratch/aborts" goals "$G/manual.bash" <<'EOF' echo before-unset echo "$NO_SUCH_VARIABLE" echo after-unset-SHOULD-NOT-RUN EOF goals "$G/hosts/testhost/manual.bash" <<'EOF' echo syntax-SHOULD-NOT-RUN if then fi EOF pv run "$G" manual assert_eq "aborts: exit 7" 7 "$rc" assert_has "aborts: ran up to the unset variable" "before-unset" assert_lacks "aborts: nothing ran after an abort, or in a file with a syntax error" "SHOULD-NOT-RUN" assert_has "aborts: unset variable aborts the file" "pave: FAIL: ./manual.bash: aborted" assert_has "aborts: syntax error skips the file" "pave: FAIL: ./hosts/testhost/manual.bash: syntax error" # ---- usage errors, and misnamed phase files ---- pv run "$scratch/select" sesion assert_eq "unknown phase argument: exit 4" 4 "$rc" assert_has "unknown phase argument: lists phases" "boot session login manual" pv run "$scratch/no-such-dir" manual assert_eq "missing goals dir: exit 5" 5 "$rc" G="$scratch/misnamed" goals "$G/manual.bash" <<<'echo manual-ran' goals "$G/hosts/testhost/sesion.bash" <<<'true' pv run "$G" manual assert_eq "misnamed phase file: exit 6" 6 "$rc" assert_has "misnamed phase file: named" "pave: FAIL: ./hosts/testhost/sesion.bash: not named for a phase" assert_has "misnamed phase file: goals still ran" "manual-ran" # ---- the environment goal files run in ---- G="$scratch/env" goals "$G/manual.bash" <<'EOF' echo "cwd=$PWD" if read -r line; then echo stdin-had-data; else echo stdin-empty; fi EOF out=$(echo surprise | "$PAVE" run "$G" manual 2>&1) assert_has "env: cwd is the goals dir" "cwd=$G" assert_has "env: stdin is empty" "stdin-empty" # ---- reports, and quiet convergence ---- G="$scratch/quiet" T="$scratch/quiet-target" goals "$G/manual.bash" <