afv-library/plugins/builder/salesforce-development/scripts/test/python3-guard.test.sh

102 lines
4.5 KiB
Bash
Executable File

#!/bin/bash
# Regression test for the python3 preflight guards added to scripts/sf-context,
# scripts/sf-deploy-gate, and bin/lsp-precheck. All three shell out to python3
# for their real logic (org detection/classification, JSON parsing); without a
# guard, a missing python3 surfaces as a raw "command not found" instead of a
# diagnosable message, and (for sf-deploy-gate/lsp-precheck, which back
# PreToolUse/PostToolUse hooks) can break the hook's expected JSON-on-stdout
# contract entirely.
#
# Simulates "python3 missing" by running each script with PATH restricted to a
# stub directory containing only the couple of external commands each script
# needs BEFORE it reaches the python3 check (dirname, cat) — deliberately
# omitting python3 so `command -v python3` fails for real, not just at runtime.
#
# Run: bash plugins/builder/salesforce-development/scripts/test/python3-guard.test.sh
set -uo pipefail
PLUGIN_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
SF_CONTEXT="$PLUGIN_ROOT/scripts/sf-context"
SF_DEPLOY_GATE="$PLUGIN_ROOT/scripts/sf-deploy-gate"
LSP_PRECHECK="$PLUGIN_ROOT/bin/lsp-precheck"
PASS=0
FAIL=0
ok() { PASS=$((PASS + 1)); printf ' ok %s\n' "$1"; }
bad() { FAIL=$((FAIL + 1)); printf ' FAIL %s\n' "$1"; }
# PATH with no python3 on it at all — only the bare commands each wrapper
# needs before its guard runs (dirname, cat). Real symlinks, not stubs, so the
# scripts behave exactly as they normally would up to the python3 check.
STUB_DIR=$(mktemp -d)
trap 'rm -rf "$STUB_DIR"' EXIT
ln -s "$(command -v dirname)" "$STUB_DIR/dirname"
ln -s "$(command -v cat)" "$STUB_DIR/cat"
echo "python3 preflight guards — sf-context, sf-deploy-gate, lsp-precheck"
# --- 1. sf-context: fails closed with a clear message ------------------------
OUT=$(PATH="$STUB_DIR" "$SF_CONTEXT" detect 2>&1)
RC=$?
if [ "$RC" -ne 0 ] && printf '%s' "$OUT" | grep -qi "python3 not found"; then
ok "sf-context: missing python3 -> non-zero exit with clear stderr message"
else
bad "sf-context: missing python3 -> expected non-zero exit + message (rc=$RC out=$OUT)"
fi
# --- 2. sf-deploy-gate classify: fails OPEN as 'unknown' ----------------------
OUT=$(printf '' | PATH="$STUB_DIR" "$SF_DEPLOY_GATE" classify 2>&1)
RC=$?
if [ "$RC" -eq 0 ] && printf '%s' "$OUT" | grep -q "unknown" && printf '%s' "$OUT" | grep -qi "python3 not found"; then
ok "sf-deploy-gate classify: missing python3 -> 'unknown', exit 0, stderr note"
else
bad "sf-deploy-gate classify: missing python3 -> expected 'unknown'/exit 0/stderr note (rc=$RC out=$OUT)"
fi
# --- 3. sf-deploy-gate prod-check: fails OPEN with a valid allow decision -----
OUT=$(PATH="$STUB_DIR" "$SF_DEPLOY_GATE" prod-check < /dev/null 2>&1)
RC=$?
if [ "$RC" -eq 0 ] && printf '%s' "$OUT" | grep -q '"continue": true'; then
ok "sf-deploy-gate prod-check: missing python3 -> allows (continue:true)"
else
bad "sf-deploy-gate prod-check: missing python3 -> expected continue:true (rc=$RC out=$OUT)"
fi
# --- 4. lsp-precheck: fails OPEN, never attempts the node cold-start ---------
OUT=$(printf '%s' '{"tool_input":{"command":"sf project deploy start"}}' | PATH="$STUB_DIR" "$LSP_PRECHECK" 2>&1)
RC=$?
if [ "$RC" -eq 0 ] && printf '%s' "$OUT" | grep -q '"continue": true'; then
ok "lsp-precheck: missing python3 -> allows (continue:true), no node cold-start"
else
bad "lsp-precheck: missing python3 -> expected continue:true (rc=$RC out=$OUT)"
fi
# --- 5. Normal behavior is unaffected when python3 IS present ----------------
OUT=$("$SF_CONTEXT" __python3_guard_test_unknown_cmd__ 2>&1)
RC=$?
if [ "$RC" -ne 0 ] && printf '%s' "$OUT" | grep -qi "Unknown command" && ! printf '%s' "$OUT" | grep -qi "python3 not found"; then
ok "sf-context: python3 present -> guard does not fire, real dispatch runs"
else
bad "sf-context: python3 present -> guard should not fire (rc=$RC out=$OUT)"
fi
OUT=$(printf '{}' | "$SF_DEPLOY_GATE" classify 2>&1)
RC=$?
if [ "$RC" -eq 0 ] && printf '%s' "$OUT" | grep -q "unknown" && ! printf '%s' "$OUT" | grep -qi "python3 not found"; then
ok "sf-deploy-gate classify: python3 present -> guard does not fire"
else
bad "sf-deploy-gate classify: python3 present -> guard should not fire (rc=$RC out=$OUT)"
fi
OUT=$(printf '%s' '{"tool_input":{"command":"ls"}}' | "$LSP_PRECHECK" 2>&1)
RC=$?
if [ "$RC" -eq 0 ] && printf '%s' "$OUT" | grep -q '"continue": true' && ! printf '%s' "$OUT" | grep -qi "python3 not found"; then
ok "lsp-precheck: python3 present -> guard does not fire"
else
bad "lsp-precheck: python3 present -> guard should not fire (rc=$RC out=$OUT)"
fi
echo ""
echo " $PASS passed, $FAIL failed"
[ "$FAIL" -eq 0 ]