151 lines
6.6 KiB
Bash
151 lines
6.6 KiB
Bash
#!/usr/bin/env bash
|
|||
|
|
set -euo pipefail
|
||
|
|
|
||
|
|
# ═══════════════════════════════════════════════════════════════
|
||
|
|
# E2E Test — IMPHNEN Moderation Stack
|
||
|
|
# Tests frontend, backend API, DB connectivity, and moderation
|
||
|
|
# pipeline against the real production environment.
|
||
|
|
# ═══════════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
BASE_URL="${1:-https://imphnen.asepharyana.my.id}"
|
||
|
|
API="${BASE_URL}/api"
|
||
|
|
|
||
|
|
PASS=0
|
||
|
|
FAIL=0
|
||
|
|
TIMEOUT=10
|
||
|
|
|
||
|
|
red() { printf "\033[31m%s\033[0m\n" "$*"; }
|
||
|
|
green() { printf "\033[32m%s\033[0m\n" "$*"; }
|
||
|
|
blue() { printf "\033[36m%s\033[0m\n" "$*"; }
|
||
|
|
|
||
|
|
assert() {
|
||
|
|
local desc="$1" method="$2" url="$3" expect="$4" extra="$5"
|
||
|
|
local code body
|
||
|
|
if [ "$method" = "GET" ]; then
|
||
|
|
body=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$TIMEOUT" "$url" 2>&1)
|
||
|
|
code="$body"
|
||
|
|
elif [ "$method" = "POST" ]; then
|
||
|
|
body=$(curl -s -o /dev/null -w "%{http_code}" --max-time "$TIMEOUT" -X POST -H "Content-Type: application/json" -d "$extra" "$url" 2>&1)
|
||
|
|
code="$body"
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [ "$code" = "$expect" ]; then
|
||
|
|
green " ✓ $desc"
|
||
|
|
PASS=$((PASS + 1))
|
||
|
|
else
|
||
|
|
red " ✗ $desc — expected $expect, got $code"
|
||
|
|
FAIL=$((FAIL + 1))
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
assert_json_field() {
|
||
|
|
local desc="$1" url="$2" field="$3" extra="${4:-}"
|
||
|
|
local val
|
||
|
|
if [ -n "$extra" ]; then
|
||
|
|
val=$(curl -s --max-time "$TIMEOUT" -X POST -H "Content-Type: application/json" -d "$extra" "$url" 2>&1 | python3 -c "
|
||
|
|
import sys, json
|
||
|
|
try:
|
||
|
|
d = json.load(sys.stdin)
|
||
|
|
keys = '${field}'.split('.')
|
||
|
|
for k in keys:
|
||
|
|
d = d[k]
|
||
|
|
print(d)
|
||
|
|
except: print('__MISSING__')
|
||
|
|
")
|
||
|
|
else
|
||
|
|
val=$(curl -s --max-time "$TIMEOUT" "$url" 2>&1 | python3 -c "
|
||
|
|
import sys, json
|
||
|
|
try:
|
||
|
|
d = json.load(sys.stdin)
|
||
|
|
keys = '${field}'.split('.')
|
||
|
|
for k in keys:
|
||
|
|
d = d[k]
|
||
|
|
print(d)
|
||
|
|
except: print('__MISSING__')
|
||
|
|
")
|
||
|
|
fi
|
||
|
|
|
||
|
|
if [ "$val" != "__MISSING__" ] && [ -n "$val" ]; then
|
||
|
|
green " ✓ $desc (${field}=${val:0:80})"
|
||
|
|
PASS=$((PASS + 1))
|
||
|
|
else
|
||
|
|
red " ✗ $desc — field '${field}' not found"
|
||
|
|
FAIL=$((FAIL + 1))
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
assert_contains() {
|
||
|
|
local desc="$1" url="$2" needle="$3"
|
||
|
|
local body
|
||
|
|
body=$(curl -s --max-time "$TIMEOUT" "$url" 2>&1)
|
||
|
|
if echo "$body" | grep -q "$needle"; then
|
||
|
|
green " ✓ $desc"
|
||
|
|
PASS=$((PASS + 1))
|
||
|
|
else
|
||
|
|
red " ✗ $desc — expected response to contain '${needle}'"
|
||
|
|
FAIL=$((FAIL + 1))
|
||
|
|
fi
|
||
|
|
}
|
||
|
|
|
||
|
|
# ───────────────────────────────────────────────────────────────
|
||
|
|
blue ""
|
||
|
|
blue "════════════════════════════════════════════════════════"
|
||
|
|
blue " E2E Test: IMPHNEN Moderation Stack"
|
||
|
|
blue " Target: ${BASE_URL}"
|
||
|
|
blue "════════════════════════════════════════════════════════"
|
||
|
|
blue ""
|
||
|
|
|
||
|
|
# ── 1. Health Check ────────────────────────────────────────────
|
||
|
|
blue "── API: Health Check ──"
|
||
|
|
assert "GET /api/health → 200" GET "${API}/health" 200 ""
|
||
|
|
assert_json_field "health.status == healthy" "${API}/health" "status"
|
||
|
|
|
||
|
|
# ── 2. Dashboard ───────────────────────────────────────────────
|
||
|
|
blue "── API: Dashboard ──"
|
||
|
|
assert "GET /api/dashboard/stats → 200" GET "${API}/dashboard/stats" 200 ""
|
||
|
|
assert_json_field "dashboard.total_messages" "${API}/dashboard/stats" "total_messages"
|
||
|
|
assert_json_field "dashboard.total_flagged" "${API}/dashboard/stats" "total_flagged"
|
||
|
|
assert_json_field "dashboard.active_users_24h" "${API}/dashboard/stats" "active_users_24h"
|
||
|
|
|
||
|
|
# ── 3. Recordings ──────────────────────────────────────────────
|
||
|
|
blue "── API: Recordings ──"
|
||
|
|
assert "GET /api/recordings → 200" GET "${API}/recordings?limit=5" 200 ""
|
||
|
|
assert_json_field "recordings.items array" "${API}/recordings?limit=5" "items"
|
||
|
|
|
||
|
|
# ── 4. Messages ────────────────────────────────────────────────
|
||
|
|
blue "── API: Messages ──"
|
||
|
|
assert "GET /api/messages (no channelId) → 400" GET "${API}/messages?limit=3" 400 ""
|
||
|
|
|
||
|
|
# ── 5. Config ──────────────────────────────────────────────────
|
||
|
|
blue "── API: Config ──"
|
||
|
|
assert "GET /api/config → 200" GET "${API}/config" 200 ""
|
||
|
|
|
||
|
|
# ── 6. Auth ────────────────────────────────────────────────────
|
||
|
|
blue "── API: Auth (POST) → 401" POST "${API}/auth" 401 '{"password": "wrong"}'
|
||
|
|
|
||
|
|
# ── 7. Voice Guilds ────────────────────────────────────────────
|
||
|
|
blue "── API: Voice ──"
|
||
|
|
assert "GET /api/guilds → 200" GET "${API}/guilds" 200 ""
|
||
|
|
|
||
|
|
# ── 8. Frontend ────────────────────────────────────────────────
|
||
|
|
blue "── Frontend ──"
|
||
|
|
assert "GET / → 200" GET "${BASE_URL}/" 200 ""
|
||
|
|
assert_contains "Frontend renders title" "${BASE_URL}/" "IMPHNEN"
|
||
|
|
|
||
|
|
# ── 9. Endpoints that should 404 ──────────────────────────────
|
||
|
|
blue "── Negative Tests ──"
|
||
|
|
assert "GET /api/nonexistent → 404" GET "${API}/nonexistent" 404 ""
|
||
|
|
|
||
|
|
# ── Summary ────────────────────────────────────────────────────
|
||
|
|
blue ""
|
||
|
|
blue "════════════════════════════════════════════════════════"
|
||
|
|
if [ "$FAIL" -eq 0 ]; then
|
||
|
|
green " ALL ${PASS} TESTS PASSED"
|
||
|
|
else
|
||
|
|
red " ${PASS} passed, ${FAIL} failed"
|
||
|
|
fi
|
||
|
|
blue "════════════════════════════════════════════════════════"
|
||
|
|
blue ""
|
||
|
|
|
||
|
|
exit "$FAIL"
|