#!/bin/sh # test — run the net-tools test suite (no root required). set -eu self=$0 while [ -L "$self" ]; do link=$(readlink "$self") case $link in /*) self=$link ;; *) self=$(dirname "$self")/$link ;; esac done root=$(cd "$(dirname "$self")" && pwd) while [ "$root" != "/" ] && [ ! -f "$root/data/mesh-hosts.json" ]; do root=$(dirname "$root"); done echo "==> python unit tests" python3 "$root/smart-lan-router/test_smart_lan_router.py" echo "==> shell syntax" sh -n "$root/bin/mesh-hosts-render" sh -n "$root/bin/host-apply" sh -n "$root/bin/fleet-status" sh -n "$root/bin/wg-dns-sync" sh -n "$root/bin/wg-render" echo "==> wg-render multi-segment" hub_who=$(WG_RENDER_SELF=citron "$root/bin/wg-render" --whoami 2>/dev/null) case "$hub_who" in *"role=hub"*) : ;; *) echo "FAIL: citron not resolved as hub ($hub_who)" >&2; exit 1 ;; esac # Hub config must include a [Peer] block for its spoke(s). WG_RENDER_SELF=citron "$root/bin/wg-render" --dry-run 2>/dev/null | grep -q '^\[Peer\]' \ || { echo "FAIL: citron hub render has no [Peer]" >&2; exit 1; } # Spoke config must point at the segment hub endpoint with a keepalive. spoke=$(WG_RENDER_SELF=lime "$root/bin/wg-render" --dry-run 2>/dev/null) case "$spoke" in *"Endpoint = 143.244.223.5:51820"*"PersistentKeepalive"*) : ;; *) echo "FAIL: lime spoke render missing hub endpoint/keepalive" >&2; exit 1 ;; esac echo "ok: citron=hub peers spokes, lime=spoke -> citron" echo "==> wg-dns-sync segment listen" cit_listen=$(WG_DNS_SELF=citron "$root/bin/wg-dns-sync" --dry-run 2>/dev/null | sed -n 's/^listen-address=//p') apr_listen=$(WG_DNS_SELF=apricot "$root/bin/wg-dns-sync" --dry-run 2>/dev/null | sed -n 's/^listen-address=//p') case "$cit_listen" in *10.9.0.7*) : ;; *) echo "FAIL: citron dns listen not nyc3 ($cit_listen)" >&2; exit 1 ;; esac case "$apr_listen" in *10.9.0.2*) : ;; *) echo "FAIL: apricot dns listen changed ($apr_listen)" >&2; exit 1 ;; esac echo "ok: citron serves nyc3 ($cit_listen), apricot unchanged ($apr_listen)" echo "==> wg-dns-sync overlay" lan_ip=$("$root/bin/wg-dns-sync" --dry-run | sed -n 's|address=/apricot\.lan/\([^[:space:]#]*\).*|\1|p' | head -1) state_ip=$(jq -r '.apricot // empty' "$root/data/lan-state.json" 2>/dev/null || true) seed_ip=$(jq -r '.hosts[] | select(.name=="apricot") | .lan' "$root/data/mesh-hosts.json") if [ -n "$state_ip" ] && [ "$lan_ip" != "$state_ip" ]; then echo "FAIL: apricot.lan is $lan_ip, expected overlay $state_ip" >&2 exit 1 fi if [ -z "$state_ip" ] && [ "$lan_ip" != "$seed_ip" ]; then echo "FAIL: apricot.lan is $lan_ip, expected seed $seed_ip" >&2 exit 1 fi echo "ok: apricot.lan -> ${lan_ip:-?}" echo "==> all passed"