- Simplify DHT encoding: use JSON instead of DNS packets (drop simple-dns) - Fix mainline crate API: SigningKey takes 32 bytes, get_mutable returns Result - Add missing dht_did field to IdentityRecord constructor - Store DID Document as JSON in DHT (DNS encoding deferred) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
196 lines
8.7 KiB
Bash
Executable File
196 lines
8.7 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# test-all-features.sh — Comprehensive single-node feature validation
|
|
#
|
|
# Usage: ./scripts/test-all-features.sh [TARGET_IP] [--iterations N]
|
|
#
|
|
# Runs all feature checks on a single node:
|
|
# - System health (CPU, RAM, disk, services)
|
|
# - Container lifecycle (running, count, health monitor)
|
|
# - Federation (peers, trust, sync)
|
|
# - Tor (hidden service reachable)
|
|
# - DWN (status, write, query)
|
|
# - NIP-07 (provider injection)
|
|
# - Backup (create, list, verify, delete)
|
|
# - Identity (DID, credentials)
|
|
# - Monitoring (metrics endpoint)
|
|
#
|
|
# Exit 0 = all checks passed = production ready
|
|
# Output: TAP format
|
|
|
|
set -uo pipefail
|
|
|
|
TARGET="${1:-192.168.1.228}"
|
|
ITERATIONS=10
|
|
SSH_KEY="${HOME}/.ssh/archipelago-deploy"
|
|
SSH_OPTS="-i ${SSH_KEY} -o StrictHostKeyChecking=no -o ConnectTimeout=10"
|
|
SUDO_PASS="EwPDR8q45l0Upx@"
|
|
PASS=0
|
|
FAIL=0
|
|
TEST_NUM=0
|
|
|
|
# Parse args
|
|
shift || true
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--iterations) ITERATIONS="$2"; shift 2 ;;
|
|
*) echo "Unknown arg: $1"; exit 1 ;;
|
|
esac
|
|
done
|
|
|
|
tap_ok() { TEST_NUM=$((TEST_NUM+1)); PASS=$((PASS+1)); echo "ok ${TEST_NUM} - $1"; }
|
|
tap_fail() { TEST_NUM=$((TEST_NUM+1)); FAIL=$((FAIL+1)); echo "not ok ${TEST_NUM} - $1"; echo "# $2"; }
|
|
|
|
ssh_cmd() { ssh ${SSH_OPTS} "archipelago@${TARGET}" "$@" 2>/dev/null; }
|
|
ssh_sudo() { ssh ${SSH_OPTS} "archipelago@${TARGET}" "echo '${SUDO_PASS}' | sudo -S $*" 2>/dev/null; }
|
|
|
|
get_session() {
|
|
curl -s -D- -o/dev/null -X POST \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"method":"auth.login","params":{"password":"password123"}}' \
|
|
"http://${TARGET}:5678/rpc/v1" 2>/dev/null | grep -i "set-cookie" | tr '\r' '\n'
|
|
}
|
|
|
|
rpc() {
|
|
local method="$1"
|
|
local params="${2:-\{\}}"
|
|
local session="$3"
|
|
local csrf="$4"
|
|
local timeout="${5:-30}"
|
|
local body
|
|
if [[ "$params" == "{}" || "$params" == "\{\}" ]]; then
|
|
body="{\"method\":\"${method}\"}"
|
|
else
|
|
body="{\"method\":\"${method}\",\"params\":${params}}"
|
|
fi
|
|
curl -s --max-time "$timeout" -X POST \
|
|
-H "Content-Type: application/json" \
|
|
-H "Cookie: session=${session}; csrf_token=${csrf}" \
|
|
-H "X-CSRF-Token: ${csrf}" \
|
|
-d "$body" \
|
|
"http://${TARGET}:5678/rpc/v1" 2>/dev/null
|
|
}
|
|
|
|
echo "TAP version 13"
|
|
echo "# Archipelago Full Feature Validation"
|
|
echo "# Target: ${TARGET}"
|
|
echo "# Iterations: ${ITERATIONS}"
|
|
echo "# Started: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
|
|
# ── Auth ──────────────────────────────────────────────────────────────────
|
|
session_header=$(get_session)
|
|
SESSION=$(echo "$session_header" | sed -n 's/.*session=\([^;]*\).*/\1/p' | head -1 | tr -d '[:space:]')
|
|
CSRF=$(echo "$session_header" | sed -n 's/.*csrf_token=\([^;]*\).*/\1/p' | head -1 | tr -d '[:space:]')
|
|
|
|
if [[ -z "$SESSION" ]]; then
|
|
echo "BAIL OUT! Cannot authenticate to ${TARGET}"
|
|
exit 1
|
|
fi
|
|
|
|
for i in $(seq 1 "$ITERATIONS"); do
|
|
echo ""
|
|
echo "# ── Iteration ${i}/${ITERATIONS} [$(date +%H:%M:%S)] ──"
|
|
|
|
# ── System Health ─────────────────────────────────────────────────────
|
|
health=$(curl -s --max-time 5 "http://${TARGET}/health" 2>/dev/null || echo "fail")
|
|
if [[ "$health" == "OK" ]]; then tap_ok "health-${i}"; else tap_fail "health-${i}" "$health"; fi
|
|
|
|
mem_avail=$(ssh_cmd "awk '/MemAvailable/ {print \$2}' /proc/meminfo" 2>/dev/null | tr -d '[:space:]')
|
|
if [[ -n "$mem_avail" ]] && [[ "$mem_avail" -gt 524288 ]]; then
|
|
tap_ok "memory-${i} # ${mem_avail}kB"
|
|
else
|
|
tap_fail "memory-${i}" "Available: ${mem_avail:-unknown}kB"
|
|
fi
|
|
|
|
disk=$(ssh_cmd "df / --output=pcent | tail -1" 2>/dev/null | tr -d '[:space:]%')
|
|
if [[ -n "$disk" ]] && [[ "$disk" -lt 85 ]]; then
|
|
tap_ok "disk-${i} # ${disk}%"
|
|
else
|
|
tap_fail "disk-${i}" "${disk:-unknown}%"
|
|
fi
|
|
|
|
# ── Containers ────────────────────────────────────────────────────────
|
|
count=$(ssh_sudo "podman ps --format '{{.Names}}' | wc -l" 2>/dev/null | tail -1 | tr -d '[:space:]')
|
|
if [[ -n "$count" ]] && [[ "$count" -ge 20 ]]; then
|
|
tap_ok "containers-${i} # ${count}"
|
|
else
|
|
tap_fail "containers-${i}" "Only ${count:-0}"
|
|
fi
|
|
|
|
exited=$(ssh_sudo "podman ps -a --format '{{.State}}' | grep -c -i exited" 2>/dev/null || echo "0")
|
|
exited=$(echo "$exited" | tail -1 | tr -d '[:space:]')
|
|
if [[ "$exited" == "0" ]]; then
|
|
tap_ok "no-exited-${i}"
|
|
else
|
|
tap_fail "no-exited-${i}" "${exited} exited"
|
|
fi
|
|
|
|
# ── Federation ────────────────────────────────────────────────────────
|
|
fed_result=$(rpc "federation.list-nodes" "{}" "$SESSION" "$CSRF")
|
|
peer_count=$(echo "$fed_result" | python3 -c "import sys,json; d=json.load(sys.stdin); print(len(d.get('result',{}).get('nodes',[])))" 2>/dev/null || echo "0")
|
|
if [[ "$peer_count" -ge 1 ]]; then
|
|
tap_ok "federation-peers-${i} # ${peer_count}"
|
|
else
|
|
tap_fail "federation-peers-${i}" "No peers"
|
|
fi
|
|
|
|
# ── DWN ───────────────────────────────────────────────────────────────
|
|
dwn_result=$(rpc "dwn.status" "{}" "$SESSION" "$CSRF")
|
|
dwn_running=$(echo "$dwn_result" | python3 -c "import sys,json; d=json.load(sys.stdin); print('yes' if d.get('result',{}).get('running') else 'no')" 2>/dev/null || echo "error")
|
|
if [[ "$dwn_running" == "yes" ]]; then
|
|
tap_ok "dwn-running-${i}"
|
|
else
|
|
tap_fail "dwn-running-${i}" "DWN not running"
|
|
fi
|
|
|
|
# ── Identity ──────────────────────────────────────────────────────────
|
|
did_result=$(rpc "node.did" "{}" "$SESSION" "$CSRF")
|
|
did=$(echo "$did_result" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('result',{}).get('did',''))" 2>/dev/null || echo "")
|
|
if [[ "$did" == did:* ]]; then
|
|
tap_ok "identity-did-${i} # ${did:0:20}..."
|
|
else
|
|
tap_fail "identity-did-${i}" "No DID: ${did}"
|
|
fi
|
|
|
|
# ── NIP-07 ────────────────────────────────────────────────────────────
|
|
provider=$(curl -s --connect-timeout 5 "http://${TARGET}/app/mempool/" 2>/dev/null | grep -c "nostr-provider" || echo "0")
|
|
if [[ "$provider" -gt 0 ]]; then
|
|
tap_ok "nip07-provider-${i}"
|
|
else
|
|
tap_fail "nip07-provider-${i}" "nostr-provider.js not found"
|
|
fi
|
|
|
|
# ── Backup (only first iteration to avoid rate limits) ────────────────
|
|
if [[ "$i" -eq 1 ]]; then
|
|
bk_pass="test-allfeatures-$(date +%s)"
|
|
bk_result=$(rpc "backup.create" "{\"passphrase\":\"${bk_pass}\",\"description\":\"allfeatures-test\"}" "$SESSION" "$CSRF" 60)
|
|
bk_id=$(echo "$bk_result" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('result',{}).get('id',''))" 2>/dev/null || echo "")
|
|
if [[ -n "$bk_id" && "$bk_id" != "None" ]]; then
|
|
tap_ok "backup-create # ${bk_id:0:8}"
|
|
# Verify
|
|
vr=$(rpc "backup.verify" "{\"id\":\"${bk_id}\",\"passphrase\":\"${bk_pass}\"}" "$SESSION" "$CSRF" 60)
|
|
valid=$(echo "$vr" | python3 -c "import sys,json; d=json.load(sys.stdin); print('yes' if d.get('result',{}).get('valid') else 'no')" 2>/dev/null || echo "no")
|
|
if [[ "$valid" == "yes" ]]; then tap_ok "backup-verify"; else tap_fail "backup-verify" "$vr"; fi
|
|
# Delete
|
|
rpc "backup.delete" "{\"id\":\"${bk_id}\"}" "$SESSION" "$CSRF" 10 >/dev/null 2>&1
|
|
tap_ok "backup-delete"
|
|
else
|
|
tap_fail "backup-create" "${bk_result:0:100}"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
TOTAL=$((PASS + FAIL))
|
|
echo "1..${TOTAL}"
|
|
echo ""
|
|
echo "# ═══════════════════════════════════════════════════════════════"
|
|
echo "# Results: ${PASS} passed, ${FAIL} failed, ${TOTAL} total"
|
|
echo "# Finished: $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "# ═══════════════════════════════════════════════════════════════"
|
|
|
|
if [[ "$FAIL" -gt 0 ]]; then
|
|
exit 1
|
|
fi
|
|
exit 0
|