#!/usr/bin/env bash
# Layer 2: Two Peers — DHT Discovery + Connect
# Tests: DHT bootstrap, topic announce/lookup, peer discovery, encrypted connect, packet exchange.
set -euo pipefail
cd "$(dirname "$0")"
echo "=== Layer 2: Two Peers — DHT Discovery + Connect ==="
# Cleanup from previous runs
rm -f /tmp/layer_bootstrap.txt /tmp/layer2_peer_*.txt
PIDS=()
cleanup() {
for pid in "${PIDS[@]}"; do
kill "$pid" 2>/dev/null || true
pkill -P "$pid" 2>/dev/null || true
done
sleep 0.5
for pid in "${PIDS[@]}"; do
kill -9 "$pid" 2>/dev/null || true
pkill -9 -P "$pid" 2>/dev/null || true
done
wait 2>/dev/null || true
rm -f /tmp/layer_bootstrap.txt /tmp/layer2_peer_*.txt
}
trap cleanup EXIT
# Start DHT testnet
echo "[orchestrator] starting DHT testnet..."
node layer2_testnet.js > /tmp/layer2_testnet_out.txt 2>&1 &
PIDS+=($!)
# Wait for bootstrap file
for i in $(seq 1 30); do
[ -f /tmp/layer_bootstrap.txt ] && break
sleep 0.2
done
if [ ! -f /tmp/layer_bootstrap.txt ]; then
echo "FAIL: testnet did not write bootstrap file"
exit 1
fi
echo "[orchestrator] testnet ready: $(cat /tmp/layer_bootstrap.txt)"
# Start Peer A (server/announcer) — uses project/
echo "[orchestrator] starting peer A..."
timeout -k 10 60 godot4 --headless --path project --script res://layer2_peer_a.gd > /tmp/layer2_peer_a_out.txt 2>&1 &
PIDS+=($!)
# Give Peer A time to join DHT and announce
echo "[orchestrator] waiting for Peer A to announce..."
for i in $(seq 1 60); do
STATUS=$(cat /tmp/layer2_peer_a_status.txt 2>/dev/null || echo "")
[ "$STATUS" = "LISTENING" ] && break
sleep 0.2
done
STATUS=$(cat /tmp/layer2_peer_a_status.txt 2>/dev/null || echo "")
if [ "$STATUS" != "LISTENING" ]; then
echo "FAIL: Peer A did not reach LISTENING state (got: $STATUS)"
echo "--- Peer A output ---"
cat /tmp/layer2_peer_a_out.txt 2>/dev/null || true
exit 1
fi
echo "[orchestrator] Peer A is LISTENING"
# Start Peer B (discoverer/connector) — uses project_b/ to avoid Godot project lock
echo "[orchestrator] starting peer B..."
timeout -k 10 60 godot4 --headless --path project_b --script res://layer2_peer_b.gd > /tmp/layer2_peer_b_out.txt 2>&1 &
PIDS+=($!)
# Wait for both peers with timeout
ELAPSED=0
MAX_WAIT=45
echo "[orchestrator] waiting for connection (max ${MAX_WAIT}s)..."
while [ $ELAPSED -lt $MAX_WAIT ]; do
A_STATUS=$(cat /tmp/layer2_peer_a_status.txt 2>/dev/null || echo "")
B_STATUS=$(cat /tmp/layer2_peer_b_status.txt 2>/dev/null || echo "")
if [ "$A_STATUS" = "PASS" ] && [ "$B_STATUS" = "PASS" ]; then
echo ""
echo "=== Layer 2: PASS ==="
exit 0
fi
if echo "$A_STATUS" | grep -q "^FAIL" || echo "$B_STATUS" | grep -q "^FAIL"; then
echo ""
echo "Peer A status: $A_STATUS"
echo "Peer B status: $B_STATUS"
echo "--- Peer A output ---"
cat /tmp/layer2_peer_a_out.txt 2>/dev/null || true
echo "--- Peer B output ---"
cat /tmp/layer2_peer_b_out.txt 2>/dev/null || true
echo "=== Layer 2: FAILED ==="
exit 1
fi
sleep 1
ELAPSED=$((ELAPSED + 1))
done
echo ""
echo "Peer A status: $(cat /tmp/layer2_peer_a_status.txt 2>/dev/null || echo 'no status')"
echo "Peer B status: $(cat /tmp/layer2_peer_b_status.txt 2>/dev/null || echo 'no status')"
echo "--- Peer A output ---"
cat /tmp/layer2_peer_a_out.txt 2>/dev/null || true
echo "--- Peer B output ---"
cat /tmp/layer2_peer_b_out.txt 2>/dev/null || true
echo "=== Layer 2: TIMEOUT after ${MAX_WAIT}s ==="
exit 1