aboutsummaryrefslogtreecommitdiff
path: root/tests/integration/run_all.sh
diff options
context:
space:
mode:
Diffstat (limited to 'tests/integration/run_all.sh')
-rwxr-xr-xtests/integration/run_all.sh116
1 files changed, 116 insertions, 0 deletions
diff --git a/tests/integration/run_all.sh b/tests/integration/run_all.sh
new file mode 100755
index 00000000..cd373af4
--- /dev/null
+++ b/tests/integration/run_all.sh
@@ -0,0 +1,116 @@
+#!/usr/bin/env bash
+#
+# Run all herdr integration tests in parallel.
+#
+# Each spec gets its own tmux server (isolated socket).
+# Workers are launched with PDEATHSIG so they get SIGTERM if this script dies.
+# A stale sweep cleans up sockets from any previous crashed run.
+#
+set -uo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+SPECS_DIR="$SCRIPT_DIR/specs"
+RESULTS_DIR="$SCRIPT_DIR/results"
+TMUX_ROOT="${TMPDIR:-/tmp}/herdr-test-sockets"
+
+mkdir -p "$RESULTS_DIR" "$TMUX_ROOT"
+
+# Clean previous results
+rm -f "$RESULTS_DIR"/*.json "$RESULTS_DIR"/*.txt 2>/dev/null
+
+# Sweep stale tmux sockets from crashed previous runs
+for dir in "$TMUX_ROOT"/*/; do
+ [ -d "$dir" ] || continue
+ owner_pid=""
+ [ -f "$dir/owner.pid" ] && owner_pid="$(<"$dir/owner.pid")"
+ # If owning worker is still alive, leave it
+ if [ -n "$owner_pid" ] && kill -0 "$owner_pid" 2>/dev/null; then
+ continue
+ fi
+ # Dead owner — kill the tmux server and remove the dir
+ [ -S "$dir/tmux.sock" ] && tmux -S "$dir/tmux.sock" kill-server 2>/dev/null || true
+ rm -rf "$dir"
+done
+
+# Collect specs
+SPECS=("$SPECS_DIR"/*.md)
+if [ ${#SPECS[@]} -eq 0 ]; then
+ echo "No test specs found in $SPECS_DIR"
+ exit 0
+fi
+
+echo "Running ${#SPECS[@]} integration tests..."
+
+# Detect PDEATHSIG support
+PDEATHSIG_CMD=()
+if command -v setpriv >/dev/null 2>&1 && setpriv --help 2>&1 | grep -q -- '--pdeathsig'; then
+ PDEATHSIG_CMD=(setpriv --pdeathsig TERM --)
+elif [ -f "$SCRIPT_DIR/pdeathsig.py" ]; then
+ PDEATHSIG_CMD=(python3 "$SCRIPT_DIR/pdeathsig.py" TERM)
+fi
+
+# Launch all specs in parallel — directly from this shell (no subshell wrapper)
+PIDS=()
+NAMES=()
+
+for spec in "${SPECS[@]}"; do
+ name="$(basename "$spec" .md)"
+ NAMES+=("$name")
+
+ "${PDEATHSIG_CMD[@]}" "$SCRIPT_DIR/run_spec.sh" "$spec" "$RESULTS_DIR" "$TMUX_ROOT" &
+ PIDS+=($!)
+done
+
+# Wait for all, ignoring individual exit codes (we read results from files)
+for pid in "${PIDS[@]}"; do
+ wait "$pid" 2>/dev/null || true
+done
+
+echo ""
+
+# Print summary from result files
+PASSED=0
+FAILED=0
+SKIPPED=0
+
+for name in "${NAMES[@]}"; do
+ result_file="$RESULTS_DIR/$name.json"
+
+ if [[ ! -f "$result_file" ]]; then
+ echo " ? $name (no result file)"
+ FAILED=$((FAILED + 1))
+ continue
+ fi
+
+ result=$(python3 -c "import sys,json; print(json.load(sys.stdin).get('result','unknown'))" < "$result_file" 2>/dev/null || echo "unknown")
+
+ case "$result" in
+ pass)
+ echo " ✓ $name"
+ PASSED=$((PASSED + 1))
+ ;;
+ skip)
+ echo " - $name (skipped)"
+ SKIPPED=$((SKIPPED + 1))
+ ;;
+ *)
+ echo " ✗ $name"
+ python3 -c "
+import sys, json
+data = json.load(sys.stdin)
+for c in data.get('checks', []):
+ if not c.get('pass', True):
+ print(f' ✗ {c[\"name\"]}: {c.get(\"detail\", \"\")}')
+notes = data.get('notes', '')
+if notes and data.get('result') == 'error':
+ print(f' {notes}')
+" < "$result_file" 2>/dev/null
+ FAILED=$((FAILED + 1))
+ ;;
+ esac
+done
+
+echo ""
+echo "$PASSED passed, $FAILED failed, $SKIPPED skipped"
+
+[ $FAILED -eq 0 ]