DC-040: repurpose post-deploy-patches.sh as a verifier (fail-loud, not patch-and-continue)
Empirically measured against all 4 release versions + origin/main: every patch in the old script is a no-op against every current release. v1.14.4 (the version that originally needed patches) doesn't even ship src/ in the tarball — the old script silently no-op'd on it because it couldn't find files to patch, then the build crashed with MODULE_NOT_FOUND in production. Repurposed as a verifier: 5 hard checks (server.js requires, license-manager path, src/ tree presence, license-keygen.js at root, generic src/ require path scan) + informational warnings. Exits 1 on ANY failure with a clear 'Build should be ABORTED' message naming the v1.14.4-class bug if relevant. Old behaviour was 'patch and continue' (silently hid regressions); new behaviour is 'fail loud' (every regression now produces a build abort). Files changed: - scripts/dashcaddy-post-deploy-patches.sh — rewritten as verifier (222→274 lines, header explains the empirical evidence + behaviour change) - dashcaddy-api/scripts/test-dashcaddy-post-deploy-verifier.sh — new regression test, 17 assertions across 10 scenarios (clean tree, missing files, broken requires, empty src/, missing app.js, absolute path, etc.) Empirical measurements documented: - origin/main: 5/5 checks pass - v1.14.9 (latest): 5/5 checks pass (0 patches applied under old script) - v1.14.8: 5/5 checks pass (0 patches applied under old script) - v1.14.4: 2/5 checks FAIL under new verifier (src/ missing, license-manager in wrong location) — old script silently no-op'd on the same input Tests: 1214/1214 Jest + 31 shell assertions. Lint: 150 warnings, all pre-existing in untouched files (zero new warnings introduced).
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
#!/usr/bin/env bash
|
||||
# Regression test for dashcaddy-post-deploy-patches.sh (the verifier).
|
||||
# Run from the dashcaddy-api/scripts/ directory:
|
||||
# bash test-dashcaddy-post-deploy-verifier.sh
|
||||
# Exit 0 = all assertions pass, non-zero = failure.
|
||||
#
|
||||
# The verifier has FIVE checks:
|
||||
# 1. server.js exists + uses './src/...' requires (not '../src/...')
|
||||
# 2. license-manager.js exists in src/managers/ + uses '../../license-keygen'
|
||||
# 3. src/ directory exists, non-empty, contains src/app.js
|
||||
# 4. license-keygen.js exists at API root
|
||||
# 5. src/ require paths — informational warnings only, does not fail build
|
||||
#
|
||||
# Test strategy: build synthetic API_DIR trees (clean, broken) and assert the
|
||||
# right checks pass/fail. No network calls, no real tarballs required.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Resolve verifier script — prefer local copy, fall back to canonical /root/dashcaddy/scripts/
|
||||
VERIFY_SCRIPT="${SCRIPT_DIR}/dashcaddy-post-deploy-patches.sh"
|
||||
if [[ ! -f "$VERIFY_SCRIPT" ]]; then
|
||||
ALT="$(cd "${SCRIPT_DIR}/../../scripts" 2>/dev/null && pwd)/dashcaddy-post-deploy-patches.sh"
|
||||
[[ -f "$ALT" ]] && VERIFY_SCRIPT="$ALT"
|
||||
fi
|
||||
|
||||
if [[ ! -f "$VERIFY_SCRIPT" ]]; then
|
||||
echo "FAIL: dashcaddy-post-deploy-patches.sh not found (looked in ${SCRIPT_DIR} and ${SCRIPT_DIR}/../../scripts)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
assert_exit_0() {
|
||||
local desc="$1"; shift
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
echo " PASS: $desc"
|
||||
pass=$(( pass + 1 ))
|
||||
else
|
||||
echo " FAIL: $desc — expected exit 0, got $?"
|
||||
fail=$(( fail + 1 ))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_exit_nonzero() {
|
||||
local desc="$1"; shift
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
echo " FAIL: $desc — expected non-zero exit, got 0"
|
||||
fail=$(( fail + 1 ))
|
||||
else
|
||||
echo " PASS: $desc"
|
||||
pass=$(( pass + 1 ))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_output_contains() {
|
||||
local desc="$1" needle="$2"; shift 2
|
||||
local output
|
||||
output=$("$@" 2>&1 || true)
|
||||
if echo "$output" | grep -q "$needle"; then
|
||||
echo " PASS: $desc"
|
||||
pass=$(( pass + 1 ))
|
||||
else
|
||||
echo " FAIL: $desc — '$needle' not in output:"
|
||||
echo "$output" | head -10 | sed 's/^/ /'
|
||||
fail=$(( fail + 1 ))
|
||||
fi
|
||||
}
|
||||
|
||||
# Build a clean API_DIR tree — all 5 checks should pass.
|
||||
build_clean_api_dir() {
|
||||
local d="$1"
|
||||
mkdir -p "$d/src/managers"
|
||||
cat > "$d/server.js" << 'EOF'
|
||||
const { createApp } = require('./src/app');
|
||||
const platformPaths = require('./platform-paths');
|
||||
EOF
|
||||
cat > "$d/license-keygen.js" << 'EOF'
|
||||
module.exports = { verifyCode: () => true };
|
||||
EOF
|
||||
cat > "$d/src/app.js" << 'EOF'
|
||||
module.exports = { createApp: () => ({}) };
|
||||
EOF
|
||||
cat > "$d/src/managers/license-manager.js" << 'EOF'
|
||||
const keygen = require('../../license-keygen');
|
||||
module.exports = { load: () => keygen };
|
||||
EOF
|
||||
}
|
||||
|
||||
# ── Test 1: clean tree — verifier passes 5/5 ─────────────────────────────────
|
||||
echo "=== Test 1: clean tree (all checks should pass) ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
assert_exit_0 "clean tree passes verifier" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports 5/5" "5/5 checks passed" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 2: missing server.js — fails check 1 ────────────────────────────────
|
||||
echo "=== Test 2: server.js missing → fails ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
rm "$TMP/api/server.js"
|
||||
assert_exit_nonzero "missing server.js fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports server.js failure" "server.js: file missing" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 3: server.js with broken '../src/' requires — fails check 1 ────────
|
||||
echo "=== Test 3: server.js with '../src/' requires → fails ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
cat > "$TMP/api/server.js" << 'EOF'
|
||||
const { createApp } = require('../src/app');
|
||||
EOF
|
||||
assert_exit_nonzero "broken server.js fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports '../src/' breakage" "../src/" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 4: src/ directory missing — fails check 3 (v1.14.4-class bug) ──────
|
||||
echo "=== Test 4: src/ missing (v1.14.4-class bug) → fails loudly ==="
|
||||
TMP=$(mktemp -d)
|
||||
mkdir -p "$TMP/api"
|
||||
cat > "$TMP/api/server.js" << 'EOF'
|
||||
const { createApp } = require('./src/app');
|
||||
EOF
|
||||
cat > "$TMP/api/license-keygen.js" << 'EOF'
|
||||
module.exports = {};
|
||||
EOF
|
||||
# No src/ at all
|
||||
assert_exit_nonzero "missing src/ fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "names v1.14.4-class bug" "v1.14.4-class bug" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 5: license-keygen.js missing at root — fails check 4 ───────────────
|
||||
echo "=== Test 5: license-keygen.js missing at root → fails ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
rm "$TMP/api/license-keygen.js"
|
||||
assert_exit_nonzero "missing license-keygen.js fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports license-keygen.js missing" "license-keygen.js: missing" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 6: license-manager.js with broken './license-keygen' — fails check 2
|
||||
echo "=== Test 6: license-manager.js uses broken './license-keygen' → fails ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
cat > "$TMP/api/src/managers/license-manager.js" << 'EOF'
|
||||
const keygen = require('./license-keygen');
|
||||
module.exports = {};
|
||||
EOF
|
||||
assert_exit_nonzero "broken license-manager.js fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports broken license-manager path" "broken './license-keygen'" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 7: empty src/ directory — fails check 3 ────────────────────────────
|
||||
echo "=== Test 7: src/ exists but is empty → fails ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
rm -rf "$TMP/api/src"
|
||||
mkdir -p "$TMP/api/src"
|
||||
assert_exit_nonzero "empty src/ fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports empty src/" "directory is empty" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 8: src/ exists but missing app.js — fails check 3 ──────────────────
|
||||
echo "=== Test 8: src/ present but missing app.js → fails ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
rm "$TMP/api/src/app.js"
|
||||
assert_exit_nonzero "missing src/app.js fails build" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
assert_output_contains "reports missing src/app.js" "src/app.js: missing" bash "$VERIFY_SCRIPT" "$TMP/api"
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 9: absolute path handling (verify cd doesn't break path resolution) ─
|
||||
echo "=== Test 9: relative vs absolute API_DIR both work ==="
|
||||
TMP=$(mktemp -d)
|
||||
build_clean_api_dir "$TMP/api"
|
||||
# Run from a DIFFERENT cwd to prove absolute path resolution
|
||||
(cd /tmp && assert_exit_0 "absolute path works from different cwd" bash "$VERIFY_SCRIPT" "$TMP/api")
|
||||
rm -rf "$TMP"
|
||||
|
||||
# ── Test 10: API_DIR doesn't exist → exits non-zero with clear error ────────
|
||||
echo "=== Test 10: non-existent API_DIR → fails clearly ==="
|
||||
assert_exit_nonzero "non-existent API_DIR fails" bash "$VERIFY_SCRIPT" "/tmp/does-not-exist-xyz-12345"
|
||||
|
||||
# ── Summary ──────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo " dashcaddy-post-deploy-patches.sh (verifier) test"
|
||||
echo " PASS: $pass FAIL: $fail"
|
||||
echo "═══════════════════════════════════════════"
|
||||
|
||||
if (( fail > 0 )); then
|
||||
exit 1
|
||||
fi
|
||||
echo "All tests passed."
|
||||
Reference in New Issue
Block a user