mirror of
https://github.com/jmcorgan/fips.git
synced 2026-08-09 00:04:54 +00:00
Add FMP node profile negotiation with mixed-profile integration tests
NodeProfile enum (Full/NonRouting/Leaf) with FMP feature bitfield: bits 0-2 profile, bits 3-6 MMP wants/provides, bit 7 bloom filter size negotiable. Bloom size TLV always sent with min=max=1KB. Config mapping: leaf_only -> Leaf, disable_routing -> NonRouting. Profile and agreed bloom size stored on PeerConnection and ActivePeer. Handshake msg2/msg3 carry FMP negotiation payload with profile validation and bloom size agreement. MMP report sending gated by profile wants/provides. Parent selection and routing constraints skip non-full peers. One-way bloom filters for non-routing peers (F inserts N as dependent). Leaf mode: single-peer enforcement, suppress tree announces and discovery forwarding. Mixed-profile integration test: A(Full) + B(Full) + C(NonRouting) + D(Leaf) with 9 connectivity assertions.
This commit is contained in:
Executable
+169
@@ -0,0 +1,169 @@
|
||||
#!/bin/bash
|
||||
# Mixed-profile integration test: Full, NonRouting, and Leaf nodes.
|
||||
#
|
||||
# Topology:
|
||||
# A (Full) ─── B (Full)
|
||||
# │ \ │
|
||||
# │ \ │
|
||||
# D (Leaf) C (NonRouting)
|
||||
#
|
||||
# Usage:
|
||||
# ./mixed-profile-test.sh inject-config Inject profile config overrides
|
||||
# ./mixed-profile-test.sh Run the full test
|
||||
#
|
||||
# inject-config is run separately by CI after generate-configs.sh and
|
||||
# before building Docker images.
|
||||
|
||||
set -e
|
||||
trap 'echo ""; echo "Test interrupted"; exit 130' INT
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
TOPOLOGY="mixed-profile"
|
||||
NODES="a b c d"
|
||||
|
||||
# ── inject-config subcommand ──────────────────────────────────────────
|
||||
# Inject profile overrides into generated node configs.
|
||||
if [ "${1:-}" = "inject-config" ]; then
|
||||
echo "Injecting mixed-profile config overrides..."
|
||||
|
||||
# Node C: non-routing
|
||||
cfg="$SCRIPT_DIR/../generated-configs/$TOPOLOGY/node-c.yaml"
|
||||
if [ ! -f "$cfg" ]; then
|
||||
echo " Error: $cfg not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
python3 -c "
|
||||
import yaml
|
||||
with open('$cfg') as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
cfg.setdefault('node', {})['disable_routing'] = True
|
||||
with open('$cfg', 'w') as f:
|
||||
yaml.dump(cfg, f, default_flow_style=False, sort_keys=False)
|
||||
"
|
||||
echo " ✓ node-c (disable_routing: true)"
|
||||
|
||||
# Node D: leaf
|
||||
cfg="$SCRIPT_DIR/../generated-configs/$TOPOLOGY/node-d.yaml"
|
||||
if [ ! -f "$cfg" ]; then
|
||||
echo " Error: $cfg not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
python3 -c "
|
||||
import yaml
|
||||
with open('$cfg') as f:
|
||||
cfg = yaml.safe_load(f)
|
||||
cfg.setdefault('node', {})['leaf_only'] = True
|
||||
with open('$cfg', 'w') as f:
|
||||
yaml.dump(cfg, f, default_flow_style=False, sort_keys=False)
|
||||
"
|
||||
echo " ✓ node-d (leaf_only: true)"
|
||||
|
||||
echo "✓ Config injection complete"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── Full test ─────────────────────────────────────────────────────────
|
||||
source "$SCRIPT_DIR/../../lib/wait-converge.sh"
|
||||
ENV_FILE="$SCRIPT_DIR/../generated-configs/npubs.env"
|
||||
if [ ! -f "$ENV_FILE" ]; then
|
||||
echo "Error: $ENV_FILE not found. Run generate-configs.sh first." >&2
|
||||
exit 1
|
||||
fi
|
||||
source "$ENV_FILE"
|
||||
|
||||
PASSED=0
|
||||
FAILED=0
|
||||
|
||||
check() {
|
||||
local desc="$1"
|
||||
shift
|
||||
echo -n " $desc ... "
|
||||
if "$@" >/dev/null 2>&1; then
|
||||
echo "PASS"
|
||||
PASSED=$((PASSED + 1))
|
||||
else
|
||||
echo "FAIL"
|
||||
FAILED=$((FAILED + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
ping_fips() {
|
||||
local from="$1"
|
||||
local to_npub="$2"
|
||||
docker exec "fips-$from" ping6 -c 1 -W 5 "${to_npub}.fips"
|
||||
}
|
||||
|
||||
echo "=== Mixed-Profile Integration Test ==="
|
||||
echo ""
|
||||
|
||||
# Phase 1: Wait for link convergence
|
||||
echo "Phase 1: Link convergence"
|
||||
# A: peers with B, C, D → 3 links
|
||||
# B: peers with A, C → 2 links
|
||||
# C (NonRouting): peers with A, B → 2 links
|
||||
# D (Leaf): peers with A → 1 link
|
||||
wait_for_peers fips-node-a 3 30 || true
|
||||
wait_for_peers fips-node-b 2 30 || true
|
||||
wait_for_peers fips-node-c 2 30 || true
|
||||
wait_for_peers fips-node-d 1 30 || true
|
||||
|
||||
# Phase 2: Verify link counts (already validated by wait_for_peers above)
|
||||
echo ""
|
||||
echo "Phase 2: Link counts verified via convergence wait"
|
||||
|
||||
# Phase 3: Wait for discovery/session convergence
|
||||
echo ""
|
||||
echo "Phase 3: Waiting for session convergence (up to 45s)..."
|
||||
# Try all pairs repeatedly until they all work
|
||||
CONV_START=$SECONDS
|
||||
CONV_TIMEOUT=45
|
||||
ALL_OK=false
|
||||
while (( SECONDS - CONV_START < CONV_TIMEOUT )); do
|
||||
ALL_GOOD=true
|
||||
for pair in "node-a:$NPUB_B" "node-a:$NPUB_C" "node-a:$NPUB_D" \
|
||||
"node-b:$NPUB_A" "node-b:$NPUB_C" \
|
||||
"node-c:$NPUB_A" "node-c:$NPUB_B" \
|
||||
"node-d:$NPUB_A" "node-d:$NPUB_B"; do
|
||||
from="${pair%%:*}"
|
||||
to="${pair##*:}"
|
||||
if ! docker exec "fips-$from" ping6 -c 1 -W 1 "${to}.fips" >/dev/null 2>&1; then
|
||||
ALL_GOOD=false
|
||||
break
|
||||
fi
|
||||
done
|
||||
if $ALL_GOOD; then
|
||||
echo " All pairs reachable after $((SECONDS - CONV_START))s"
|
||||
ALL_OK=true
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if ! $ALL_OK; then
|
||||
echo " WARNING: Not all pairs converged within ${CONV_TIMEOUT}s (continuing with tests)"
|
||||
fi
|
||||
|
||||
# Phase 4: Connectivity tests
|
||||
echo ""
|
||||
echo "Phase 4: F↔F connectivity"
|
||||
check "A → B (Full → Full, direct)" ping_fips node-a "$NPUB_B"
|
||||
check "B → A (Full → Full, direct)" ping_fips node-b "$NPUB_A"
|
||||
|
||||
echo ""
|
||||
echo "Phase 5: F↔N connectivity"
|
||||
check "A → C (Full → NonRouting, direct)" ping_fips node-a "$NPUB_C"
|
||||
check "C → A (NonRouting → Full, direct)" ping_fips node-c "$NPUB_A"
|
||||
check "B → C (Full → NonRouting, direct)" ping_fips node-b "$NPUB_C"
|
||||
check "C → B (NonRouting → Full, direct)" ping_fips node-c "$NPUB_B"
|
||||
|
||||
echo ""
|
||||
echo "Phase 6: F↔L connectivity"
|
||||
check "A → D (Full → Leaf, direct)" ping_fips node-a "$NPUB_D"
|
||||
check "D → A (Leaf → Full, direct)" ping_fips node-d "$NPUB_A"
|
||||
|
||||
echo ""
|
||||
echo "Phase 7: Multi-hop through Full nodes"
|
||||
check "D → B (Leaf → Full, via A)" ping_fips node-d "$NPUB_B"
|
||||
|
||||
echo ""
|
||||
echo "=== Results: $PASSED passed, $FAILED failed ==="
|
||||
[ "$FAILED" -eq 0 ] && exit 0 || exit 1
|
||||
Reference in New Issue
Block a user