test: add review-gate unit tests (43 tests)
Tests cover: - All CLI commands (check, enable, approve, reject, status, list, clean) - Exit codes (0 for allow, 1 for block) - State file creation and JSON structure - Session ID auto-detection from env vars - Multiple issues in reject - Workflow reset (re-enable after approve) - Error handling Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
061556e003
commit
4130dd4614
321
skills/review-gate/tests/test-review-gate.sh
Executable file
321
skills/review-gate/tests/test-review-gate.sh
Executable file
|
|
@ -0,0 +1,321 @@
|
|||
#!/usr/bin/env bash
|
||||
# Tests for review-gate CLI
|
||||
# Run: bash skills/review-gate/tests/test-review-gate.sh
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REVIEW_GATE="$SCRIPT_DIR/../scripts/review-gate"
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Test state directory (isolated per test run)
|
||||
TEST_STATE_DIR=$(mktemp -d)
|
||||
export REVIEW_STATE_DIR="$TEST_STATE_DIR"
|
||||
|
||||
cleanup() {
|
||||
rm -rf "$TEST_STATE_DIR"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Test helpers
|
||||
assert_exit_code() {
|
||||
local description="$1"
|
||||
local expected="$2"
|
||||
local actual="$3"
|
||||
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
echo -e "${GREEN}PASS${NC}: $description"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: $description"
|
||||
echo " Expected exit code: $expected, Actual: $actual"
|
||||
((FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_output_contains() {
|
||||
local description="$1"
|
||||
local pattern="$2"
|
||||
local output="$3"
|
||||
|
||||
if echo "$output" | grep -q "$pattern"; then
|
||||
echo -e "${GREEN}PASS${NC}: $description"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: $description"
|
||||
echo " Pattern not found: '$pattern'"
|
||||
echo " Output was:"
|
||||
echo "$output" | sed 's/^/ /'
|
||||
((FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_output_not_contains() {
|
||||
local description="$1"
|
||||
local pattern="$2"
|
||||
local output="$3"
|
||||
|
||||
if ! echo "$output" | grep -q "$pattern"; then
|
||||
echo -e "${GREEN}PASS${NC}: $description"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: $description"
|
||||
echo " Pattern found but should not be: '$pattern'"
|
||||
((FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_exists() {
|
||||
local description="$1"
|
||||
local file="$2"
|
||||
|
||||
if [[ -f "$file" ]]; then
|
||||
echo -e "${GREEN}PASS${NC}: $description"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: $description"
|
||||
echo " File does not exist: $file"
|
||||
((FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_file_not_exists() {
|
||||
local description="$1"
|
||||
local file="$2"
|
||||
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo -e "${GREEN}PASS${NC}: $description"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: $description"
|
||||
echo " File exists but should not: $file"
|
||||
((FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
assert_json_field() {
|
||||
local description="$1"
|
||||
local expected="$2"
|
||||
local field="$3"
|
||||
local file="$4"
|
||||
|
||||
local actual
|
||||
actual=$(jq -r "$field" "$file" 2>/dev/null)
|
||||
|
||||
if [[ "$actual" == "$expected" ]]; then
|
||||
echo -e "${GREEN}PASS${NC}: $description"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: $description"
|
||||
echo " Expected $field: '$expected', Actual: '$actual'"
|
||||
((FAILED++))
|
||||
fi
|
||||
}
|
||||
|
||||
run_gate() {
|
||||
"$REVIEW_GATE" "$@" 2>&1
|
||||
}
|
||||
|
||||
run_gate_status() {
|
||||
"$REVIEW_GATE" "$@" 2>&1
|
||||
echo $?
|
||||
}
|
||||
|
||||
echo "=== Review Gate CLI Tests ==="
|
||||
echo "State dir: $TEST_STATE_DIR"
|
||||
echo ""
|
||||
|
||||
# --- Help Command ---
|
||||
echo "## Help Command"
|
||||
|
||||
output=$(run_gate help)
|
||||
assert_output_contains "Help shows check command" "check \[session\]" "$output"
|
||||
assert_output_contains "Help shows enable command" "enable \[session\]" "$output"
|
||||
assert_output_contains "Help shows approve command" "approve \[session\]" "$output"
|
||||
assert_output_contains "Help shows reject command" "reject \[session\]" "$output"
|
||||
|
||||
# --- Check Without State ---
|
||||
echo ""
|
||||
echo "## Check Without State (No Review Required)"
|
||||
|
||||
output=$(run_gate check no-state-session)
|
||||
exit_code=$?
|
||||
assert_exit_code "Check returns 0 when no state exists" "0" "$exit_code"
|
||||
assert_output_contains "Check indicates no review required" "No review required" "$output"
|
||||
|
||||
# --- Enable Command ---
|
||||
echo ""
|
||||
echo "## Enable Command"
|
||||
|
||||
output=$(run_gate enable test-enable)
|
||||
assert_output_contains "Enable confirms session" "Review enabled" "$output"
|
||||
assert_file_exists "State file created" "$TEST_STATE_DIR/test-enable.json"
|
||||
assert_json_field "Status is pending" "pending" ".status" "$TEST_STATE_DIR/test-enable.json"
|
||||
assert_json_field "Session ID stored" "test-enable" ".session_id" "$TEST_STATE_DIR/test-enable.json"
|
||||
|
||||
# --- Check When Pending ---
|
||||
echo ""
|
||||
echo "## Check When Pending (Should Block)"
|
||||
|
||||
run_gate enable test-pending > /dev/null
|
||||
output=$(run_gate check test-pending)
|
||||
exit_code=$?
|
||||
assert_exit_code "Check returns 1 when pending" "1" "$exit_code"
|
||||
assert_output_contains "Check shows BLOCKED" "BLOCKED" "$output"
|
||||
assert_output_contains "Check shows pending status" "pending" "$output"
|
||||
|
||||
# --- Approve Command ---
|
||||
echo ""
|
||||
echo "## Approve Command"
|
||||
|
||||
run_gate enable test-approve > /dev/null
|
||||
output=$(run_gate approve test-approve)
|
||||
assert_output_contains "Approve confirms" "Review approved" "$output"
|
||||
assert_json_field "Status changed to approved" "approved" ".status" "$TEST_STATE_DIR/test-approve.json"
|
||||
|
||||
# --- Check When Approved ---
|
||||
echo ""
|
||||
echo "## Check When Approved (Should Allow)"
|
||||
|
||||
output=$(run_gate check test-approve)
|
||||
exit_code=$?
|
||||
assert_exit_code "Check returns 0 when approved" "0" "$exit_code"
|
||||
assert_output_contains "Check shows approved" "approved" "$output"
|
||||
|
||||
# --- Reject Command ---
|
||||
echo ""
|
||||
echo "## Reject Command"
|
||||
|
||||
run_gate enable test-reject > /dev/null
|
||||
output=$(run_gate reject test-reject "Missing tests")
|
||||
assert_output_contains "Reject confirms" "Review rejected" "$output"
|
||||
assert_output_contains "Reject shows reason" "Missing tests" "$output"
|
||||
assert_json_field "Status changed to rejected" "rejected" ".status" "$TEST_STATE_DIR/test-reject.json"
|
||||
assert_json_field "Reason stored" "Missing tests" ".reason" "$TEST_STATE_DIR/test-reject.json"
|
||||
|
||||
# --- Check When Rejected ---
|
||||
echo ""
|
||||
echo "## Check When Rejected (Should Block)"
|
||||
|
||||
output=$(run_gate check test-reject)
|
||||
exit_code=$?
|
||||
assert_exit_code "Check returns 1 when rejected" "1" "$exit_code"
|
||||
assert_output_contains "Check shows BLOCKED" "BLOCKED" "$output"
|
||||
assert_output_contains "Check shows reason" "Missing tests" "$output"
|
||||
|
||||
# --- Reject With Issues ---
|
||||
echo ""
|
||||
echo "## Reject With Multiple Issues"
|
||||
|
||||
run_gate enable test-issues > /dev/null
|
||||
output=$(run_gate reject test-issues "Quality issues" "No unit tests" "Missing docs" "Bad naming")
|
||||
|
||||
issues=$(jq -r '.issues | length' "$TEST_STATE_DIR/test-issues.json")
|
||||
if [[ "$issues" == "3" ]]; then
|
||||
echo -e "${GREEN}PASS${NC}: Three issues stored"
|
||||
((PASSED++))
|
||||
else
|
||||
echo -e "${RED}FAIL${NC}: Three issues stored (got $issues)"
|
||||
((FAILED++))
|
||||
fi
|
||||
|
||||
assert_json_field "First issue stored" "No unit tests" ".issues[0]" "$TEST_STATE_DIR/test-issues.json"
|
||||
|
||||
# Check displays issues
|
||||
output=$(run_gate check test-issues)
|
||||
assert_output_contains "Check displays issues" "No unit tests" "$output"
|
||||
|
||||
# --- Status Command ---
|
||||
echo ""
|
||||
echo "## Status Command"
|
||||
|
||||
output=$(run_gate status test-issues)
|
||||
assert_output_contains "Status shows session" "test-issues" "$output"
|
||||
assert_output_contains "Status shows rejected" "rejected" "$output"
|
||||
|
||||
# Status for non-existent session
|
||||
output=$(run_gate status nonexistent)
|
||||
assert_output_contains "Status handles missing session" "No review state" "$output"
|
||||
|
||||
# --- List Command ---
|
||||
echo ""
|
||||
echo "## List Command"
|
||||
|
||||
output=$(run_gate list)
|
||||
assert_output_contains "List shows test-enable" "test-enable" "$output"
|
||||
assert_output_contains "List shows test-approve" "test-approve" "$output"
|
||||
assert_output_contains "List shows statuses" "approved" "$output"
|
||||
assert_output_contains "List shows rejected" "rejected" "$output"
|
||||
|
||||
# --- Session ID Auto-Detection ---
|
||||
echo ""
|
||||
echo "## Session ID Auto-Detection"
|
||||
|
||||
# From REVIEW_SESSION_ID
|
||||
export REVIEW_SESSION_ID="env-review-id"
|
||||
output=$(run_gate enable)
|
||||
assert_file_exists "Uses REVIEW_SESSION_ID" "$TEST_STATE_DIR/env-review-id.json"
|
||||
unset REVIEW_SESSION_ID
|
||||
|
||||
# From CLAUDE_SESSION_ID
|
||||
export CLAUDE_SESSION_ID="env-claude-id"
|
||||
output=$(run_gate enable)
|
||||
assert_file_exists "Uses CLAUDE_SESSION_ID" "$TEST_STATE_DIR/env-claude-id.json"
|
||||
unset CLAUDE_SESSION_ID
|
||||
|
||||
# --- Approve Without Prior Enable ---
|
||||
echo ""
|
||||
echo "## Approve Without Prior Enable"
|
||||
|
||||
output=$(run_gate approve new-approve)
|
||||
assert_output_contains "Approve works without enable" "approved" "$output"
|
||||
assert_file_exists "State file created on approve" "$TEST_STATE_DIR/new-approve.json"
|
||||
|
||||
# --- Re-enable After Approve ---
|
||||
echo ""
|
||||
echo "## Re-enable After Approve (Workflow Reset)"
|
||||
|
||||
run_gate approve reset-session > /dev/null
|
||||
run_gate enable reset-session > /dev/null
|
||||
assert_json_field "Status reset to pending" "pending" ".status" "$TEST_STATE_DIR/reset-session.json"
|
||||
|
||||
output=$(run_gate check reset-session)
|
||||
exit_code=$?
|
||||
assert_exit_code "Check blocks after re-enable" "1" "$exit_code"
|
||||
|
||||
# --- Clean Command ---
|
||||
echo ""
|
||||
echo "## Clean Command"
|
||||
|
||||
# Create an old file (touch with old timestamp not reliable in all envs, so just test the command runs)
|
||||
output=$(run_gate clean 0d)
|
||||
assert_output_contains "Clean runs" "Cleaning" "$output"
|
||||
|
||||
# --- Unknown Command ---
|
||||
echo ""
|
||||
echo "## Error Handling"
|
||||
|
||||
output=$(run_gate unknown-cmd 2>&1)
|
||||
exit_code=$?
|
||||
assert_exit_code "Unknown command returns 1" "1" "$exit_code"
|
||||
assert_output_contains "Unknown command shows error" "Unknown command" "$output"
|
||||
|
||||
# --- Summary ---
|
||||
echo ""
|
||||
echo "=== Summary ==="
|
||||
echo -e "Passed: ${GREEN}$PASSED${NC}"
|
||||
echo -e "Failed: ${RED}$FAILED${NC}"
|
||||
|
||||
if [[ $FAILED -gt 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo -e "${GREEN}All tests passed!${NC}"
|
||||
Loading…
Reference in a new issue