archy/tests/multinode/repro-federation-sync.sh
archipelago 0c8991b519 test(multinode): assertion-based two-node E2E smoke suite
Adds tests/multinode/smoke.sh on the existing multinode.bash lib: an
assertion suite (pass/fail + non-zero exit) driving two real nodes through
login, onion + FIPS identity, FIPS anchor-connected, federation pairing
both directions, peer content browse over the mesh, and the removed-node
tombstone (with an optional 3rd node C for the transitive-reappear case).
Guards the v1.7.94/v1.7.95 fixes. Content-browse + tombstone checks
skip-with-note against peers older than v1.7.95.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 09:03:58 -04:00

78 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Controlled two-node reproduction of node-to-node federation sync.
#
# Pairs two real nodes via federation.invite/join, triggers federation.sync-state
# in both directions, and reports which transport actually carried the call and
# any per-peer error. This is the controlled repro for the reported
# "Tor connection cloud->node not working" symptom: raw Tor transport is known
# good (see README), so this isolates whether the APP-level sync path works and,
# if it fails, surfaces the exact error string.
#
# Env (override as needed):
# A_URL A_PW node A base url + UI password (default .116 http)
# B_URL B_PW node B base url + UI password (default .228 https)
# FORCE_TOR=1 set both nodes' federation transport preference to Tor first
#
# Usage: tests/multinode/repro-federation-sync.sh
set -uo pipefail
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$HERE/lib/multinode.bash"
A_URL="${A_URL:-http://192.168.1.116}"; A_PW="${A_PW:-ThisIsWeb54321@}"
B_URL="${B_URL:-https://192.168.1.228}"; B_PW="${B_PW:-password123}"
bar() { printf '\n=== %s ===\n' "$*"; }
node_register A "$A_URL" "$A_PW"
node_register B "$B_URL" "$B_PW"
bar "login"
node_login A || { echo "A login failed"; exit 1; }
node_login B || { echo "B login failed"; exit 1; }
echo "A=$A_URL B=$B_URL logged in"
bar "onions"
A_ONION=$(node_onion A); B_ONION=$(node_onion B)
echo "A onion: ${A_ONION:-<none>}"
echo "B onion: ${B_ONION:-<none>}"
if [[ "${FORCE_TOR:-0}" == "1" ]]; then
bar "force federation transport = tor on both"
node_rpc A transport.set-preference '{"service":"federation","pref":"tor"}' | jq -c '.result // .error'
node_rpc B transport.set-preference '{"service":"federation","pref":"tor"}' | jq -c '.result // .error'
fi
bar "federation state BEFORE"
echo "A knows:"; node_result A federation.list-nodes | jq -r '.[]? | " \(.name // "?") did=\(.did[0:24])… last_seen=\(.last_seen // "never")"' 2>/dev/null || echo " (none/err)"
echo "B knows:"; node_result B federation.list-nodes | jq -r '.[]? | " \(.name // "?") did=\(.did[0:24])… last_seen=\(.last_seen // "never")"' 2>/dev/null || echo " (none/err)"
bar "pair: A invites, B joins"
INV_A=$(node_result A federation.invite)
CODE_A=$(echo "$INV_A" | jq -r '.code // empty')
echo "A invite code: ${CODE_A:0:40}"
if [[ -n "$CODE_A" ]]; then
node_result B federation.join "$(jq -nc --arg c "$CODE_A" '{code:$c}')" \
&& echo "B joined A" || echo "B join FAILED"
fi
bar "pair: B invites, A joins"
INV_B=$(node_result B federation.invite)
CODE_B=$(echo "$INV_B" | jq -r '.code // empty')
echo "B invite code: ${CODE_B:0:40}"
if [[ -n "$CODE_B" ]]; then
node_result A federation.join "$(jq -nc --arg c "$CODE_B" '{code:$c}')" \
&& echo "A joined B" || echo "A join FAILED"
fi
bar "trigger sync-state on A (A dials its peers)"
node_result A federation.sync-state | jq '.'
bar "trigger sync-state on B (B dials its peers)"
node_result B federation.sync-state | jq '.'
bar "federation state AFTER (look for fresh last_seen + transport)"
echo "A knows:"; node_result A federation.list-nodes | jq -r '.[]? | " \(.name // "?") last_seen=\(.last_seen // "never") transport=\(.last_transport // .transport // "?")"' 2>/dev/null
echo "B knows:"; node_result B federation.list-nodes | jq -r '.[]? | " \(.name // "?") last_seen=\(.last_seen // "never") transport=\(.last_transport // .transport // "?")"' 2>/dev/null
bar "done"