Files
claude-mem/openclaw/e2e-verify.sh
Alex Newman 33ab7ba747 MAESTRO: Add Docker E2E test against real OpenClaw gateway
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>
2026-02-07 21:28:16 -05:00

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