mirror of
https://github.com/thedotmack/claude-mem
synced 2026-04-25 17:15:04 +02:00
Installs plugin on ghcr.io/openclaw/openclaw:main via `plugins install`, starts mock worker + gateway, and verifies 16 checks (discovery, files, SSE connectivity, gateway plugin load). Includes interactive mode for human manual testing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
266 lines
6.9 KiB
Bash
Executable File
266 lines
6.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# e2e-verify.sh — Automated E2E verification for claude-mem plugin on OpenClaw
|
|
#
|
|
# This script verifies the complete plugin installation and operation flow:
|
|
# 1. Plugin is installed and visible in OpenClaw
|
|
# 2. Plugin loads correctly when gateway starts
|
|
# 3. Mock worker SSE stream is consumed by the plugin
|
|
# 4. Observations are received and formatted
|
|
#
|
|
# Exit 0 = all checks passed, Exit 1 = failure
|
|
|
|
set -euo pipefail
|
|
|
|
PASS=0
|
|
FAIL=0
|
|
TOTAL=0
|
|
|
|
pass() {
|
|
PASS=$((PASS + 1))
|
|
TOTAL=$((TOTAL + 1))
|
|
echo " PASS: $1"
|
|
}
|
|
|
|
fail() {
|
|
FAIL=$((FAIL + 1))
|
|
TOTAL=$((TOTAL + 1))
|
|
echo " FAIL: $1"
|
|
}
|
|
|
|
section() {
|
|
echo ""
|
|
echo "=== $1 ==="
|
|
}
|
|
|
|
# ─── Phase 1: Plugin Discovery ───
|
|
|
|
section "Phase 1: Plugin Discovery"
|
|
|
|
# Check plugin is listed
|
|
PLUGIN_LIST=$(node /app/openclaw.mjs plugins list 2>&1)
|
|
if echo "$PLUGIN_LIST" | grep -q "claude-mem"; then
|
|
pass "Plugin appears in 'plugins list'"
|
|
else
|
|
fail "Plugin NOT found in 'plugins list'"
|
|
echo "$PLUGIN_LIST"
|
|
fi
|
|
|
|
# Check plugin info
|
|
PLUGIN_INFO=$(node /app/openclaw.mjs plugins info claude-mem 2>&1 || true)
|
|
if echo "$PLUGIN_INFO" | grep -qi "claude-mem"; then
|
|
pass "Plugin info shows claude-mem details"
|
|
else
|
|
fail "Plugin info failed"
|
|
echo "$PLUGIN_INFO"
|
|
fi
|
|
|
|
# Check plugin is enabled
|
|
if echo "$PLUGIN_LIST" | grep -A1 "claude-mem" | grep -qi "enabled\|loaded"; then
|
|
pass "Plugin is enabled"
|
|
else
|
|
# Try to check via info
|
|
if echo "$PLUGIN_INFO" | grep -qi "enabled\|loaded"; then
|
|
pass "Plugin is enabled (via info)"
|
|
else
|
|
fail "Plugin does not appear enabled"
|
|
echo "$PLUGIN_INFO"
|
|
fi
|
|
fi
|
|
|
|
# Check plugin doctor reports no issues
|
|
DOCTOR_OUT=$(node /app/openclaw.mjs plugins doctor 2>&1 || true)
|
|
if echo "$DOCTOR_OUT" | grep -qi "no.*issue\|0 issue"; then
|
|
pass "Plugin doctor reports no issues"
|
|
else
|
|
fail "Plugin doctor reports issues"
|
|
echo "$DOCTOR_OUT"
|
|
fi
|
|
|
|
# ─── Phase 2: Plugin Files ───
|
|
|
|
section "Phase 2: Plugin Files"
|
|
|
|
# Check extension directory exists
|
|
EXTENSIONS_DIR="/home/node/.openclaw/extensions/openclaw-plugin"
|
|
if [ ! -d "$EXTENSIONS_DIR" ]; then
|
|
# Try alternative naming
|
|
EXTENSIONS_DIR="/home/node/.openclaw/extensions/claude-mem"
|
|
if [ ! -d "$EXTENSIONS_DIR" ]; then
|
|
# Search for it
|
|
FOUND_DIR=$(find /home/node/.openclaw/extensions/ -name "openclaw.plugin.json" -exec dirname {} \; 2>/dev/null | head -1 || true)
|
|
if [ -n "$FOUND_DIR" ]; then
|
|
EXTENSIONS_DIR="$FOUND_DIR"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ -d "$EXTENSIONS_DIR" ]; then
|
|
pass "Plugin directory exists: $EXTENSIONS_DIR"
|
|
else
|
|
fail "Plugin directory not found under /home/node/.openclaw/extensions/"
|
|
ls -la /home/node/.openclaw/extensions/ 2>/dev/null || echo " (extensions dir not found)"
|
|
fi
|
|
|
|
# Check key files exist
|
|
for FILE in "openclaw.plugin.json" "dist/index.js" "package.json"; do
|
|
if [ -f "$EXTENSIONS_DIR/$FILE" ]; then
|
|
pass "File exists: $FILE"
|
|
else
|
|
fail "File missing: $FILE"
|
|
fi
|
|
done
|
|
|
|
# ─── Phase 3: Mock Worker + Plugin Integration ───
|
|
|
|
section "Phase 3: Mock Worker + Plugin Integration"
|
|
|
|
# Start mock worker in background
|
|
echo " Starting mock claude-mem worker..."
|
|
node /app/mock-worker.js &
|
|
MOCK_PID=$!
|
|
|
|
# Wait for mock worker to be ready
|
|
for i in $(seq 1 10); do
|
|
if curl -sf http://localhost:37777/health > /dev/null 2>&1; then
|
|
break
|
|
fi
|
|
sleep 0.5
|
|
done
|
|
|
|
if curl -sf http://localhost:37777/health > /dev/null 2>&1; then
|
|
pass "Mock worker health check passed"
|
|
else
|
|
fail "Mock worker health check failed"
|
|
kill $MOCK_PID 2>/dev/null || true
|
|
fi
|
|
|
|
# Test SSE stream connectivity (curl with max-time to capture initial SSE frame)
|
|
SSE_TEST=$(curl -s --max-time 2 http://localhost:37777/stream 2>/dev/null || true)
|
|
if echo "$SSE_TEST" | grep -q "connected"; then
|
|
pass "SSE stream returns connected event"
|
|
else
|
|
fail "SSE stream did not return connected event"
|
|
echo " Got: $(echo "$SSE_TEST" | head -5)"
|
|
fi
|
|
|
|
# ─── Phase 4: Gateway + Plugin Load ───
|
|
|
|
section "Phase 4: Gateway Startup with Plugin"
|
|
|
|
# Create a minimal config that enables the plugin with the mock worker.
|
|
# The memory slot must be set to "claude-mem" to match what `plugins install` configured.
|
|
# Gateway auth is disabled via token for headless testing.
|
|
mkdir -p /home/node/.openclaw
|
|
cat > /home/node/.openclaw/openclaw.json << 'EOFCONFIG'
|
|
{
|
|
"gateway": {
|
|
"mode": "local",
|
|
"auth": {
|
|
"mode": "token",
|
|
"token": "e2e-test-token"
|
|
}
|
|
},
|
|
"plugins": {
|
|
"slots": {
|
|
"memory": "claude-mem"
|
|
},
|
|
"entries": {
|
|
"claude-mem": {
|
|
"enabled": true,
|
|
"config": {
|
|
"workerPort": 37777,
|
|
"observationFeed": {
|
|
"enabled": true,
|
|
"channel": "telegram",
|
|
"to": "test-chat-id-12345"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
EOFCONFIG
|
|
|
|
pass "OpenClaw config written with plugin enabled"
|
|
|
|
# Start gateway in background and capture output
|
|
GATEWAY_LOG="/tmp/gateway.log"
|
|
echo " Starting OpenClaw gateway (timeout 15s)..."
|
|
OPENCLAW_GATEWAY_TOKEN=e2e-test-token timeout 15 node /app/openclaw.mjs gateway --allow-unconfigured --verbose --token e2e-test-token > "$GATEWAY_LOG" 2>&1 &
|
|
GATEWAY_PID=$!
|
|
|
|
# Give the gateway time to start and load plugins
|
|
sleep 5
|
|
|
|
# Check if gateway started
|
|
if kill -0 $GATEWAY_PID 2>/dev/null; then
|
|
pass "Gateway process is running"
|
|
else
|
|
fail "Gateway process exited early"
|
|
echo " Gateway log:"
|
|
cat "$GATEWAY_LOG" 2>/dev/null | tail -30
|
|
fi
|
|
|
|
# Check gateway log for plugin load messages
|
|
if grep -qi "claude-mem" "$GATEWAY_LOG" 2>/dev/null; then
|
|
pass "Gateway log mentions claude-mem plugin"
|
|
else
|
|
fail "Gateway log does not mention claude-mem"
|
|
echo " Gateway log (last 20 lines):"
|
|
tail -20 "$GATEWAY_LOG" 2>/dev/null
|
|
fi
|
|
|
|
# Check for plugin loaded message
|
|
if grep -q "plugin loaded" "$GATEWAY_LOG" 2>/dev/null || grep -q "v1.0.0" "$GATEWAY_LOG" 2>/dev/null; then
|
|
pass "Plugin load message found in gateway log"
|
|
else
|
|
fail "Plugin load message not found"
|
|
fi
|
|
|
|
# Check for observation feed messages
|
|
if grep -qi "observation feed" "$GATEWAY_LOG" 2>/dev/null; then
|
|
pass "Observation feed activity in gateway log"
|
|
else
|
|
fail "No observation feed activity detected"
|
|
fi
|
|
|
|
# Check for SSE connection to mock worker
|
|
if grep -qi "connected.*SSE\|SSE.*stream\|connecting.*SSE" "$GATEWAY_LOG" 2>/dev/null; then
|
|
pass "SSE connection activity detected"
|
|
else
|
|
fail "No SSE connection activity in log"
|
|
fi
|
|
|
|
# ─── Cleanup ───
|
|
|
|
section "Cleanup"
|
|
kill $GATEWAY_PID 2>/dev/null || true
|
|
kill $MOCK_PID 2>/dev/null || true
|
|
wait $GATEWAY_PID 2>/dev/null || true
|
|
wait $MOCK_PID 2>/dev/null || true
|
|
echo " Processes stopped."
|
|
|
|
# ─── Summary ───
|
|
|
|
echo ""
|
|
echo "==============================="
|
|
echo " E2E Test Results"
|
|
echo "==============================="
|
|
echo " Total: $TOTAL"
|
|
echo " Passed: $PASS"
|
|
echo " Failed: $FAIL"
|
|
echo "==============================="
|
|
|
|
if [ "$FAIL" -gt 0 ]; then
|
|
echo ""
|
|
echo " SOME TESTS FAILED"
|
|
echo ""
|
|
echo " Full gateway log:"
|
|
cat "$GATEWAY_LOG" 2>/dev/null
|
|
exit 1
|
|
fi
|
|
|
|
echo ""
|
|
echo " ALL TESTS PASSED"
|
|
exit 0
|