fix: revert TUNNEL_LOCAL_SSH_PORT to 2223, fix registry, add incident docs
- wizard.sh + connect.conf: TUNNEL_LOCAL_SSH_PORT back to 2223 (Synology SSH port) - port-registry: renamed x6340 → x4662 (matches QuickConnect ID) - port-registry: added MR2200ac mesh satellite note for x4662 - deployment checklist: added kit-connect section, post-deployment rules, incident log, and complete fleet port registry table - memory: added fleet-router-inventory.md with full fleet state - hub README: updated with current status and locations Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,225 @@
|
||||
# telemetry-synology.bats — Tests for Synology telemetry agent
|
||||
|
||||
LIBDIR="$(cd "$BATS_TEST_DIRNAME/../.."/package/kit-busrouter/files/usr/lib/busrouter && pwd)"
|
||||
|
||||
setup() {
|
||||
export LIB_DIR="$LIBDIR"
|
||||
export AIWANBAL_STATE_DIR="$BATS_TMPDIR/aiwanbal"
|
||||
export TELEMETRY_BUFFER_DIR="$BATS_TMPDIR/telemetry-buf"
|
||||
export TELEMETRY_HUB="http://10.88.0.1:8080/api/telemetry"
|
||||
rm -rf "$AIWANBAL_STATE_DIR" "$TELEMETRY_BUFFER_DIR"
|
||||
mkdir -p "$AIWANBAL_STATE_DIR"
|
||||
|
||||
# Seed minimal aiwanbal state for collection tests
|
||||
printf '85\n' > "$AIWANBAL_STATE_DIR/wan1_score_avg"
|
||||
printf '15\n' > "$AIWANBAL_STATE_DIR/wan1_latency"
|
||||
printf '50000000\n' > "$AIWANBAL_STATE_DIR/wan1_throughput" # 50 Mbps
|
||||
printf '10000000\n' > "$AIWANBAL_STATE_DIR/wan1_upload"
|
||||
printf '2\n' > "$AIWANBAL_STATE_DIR/wan1_jitter"
|
||||
printf '0\n' > "$AIWANBAL_STATE_DIR/wan1_packet_loss"
|
||||
printf -- '-80\n' > "$AIWANBAL_STATE_DIR/wan1_rsrp"
|
||||
printf -- '-12\n' > "$AIWANBAL_STATE_DIR/wan1_rsrq"
|
||||
printf '8\n' > "$AIWANBAL_STATE_DIR/wan1_sinr"
|
||||
printf '5G-NR\n' > "$AIWANBAL_STATE_DIR/wan1_technology"
|
||||
printf 'eyeride\n' > "$AIWANBAL_STATE_DIR/wan1_modem_type"
|
||||
|
||||
printf '70\n' > "$AIWANBAL_STATE_DIR/wan2_score_avg"
|
||||
printf '25\n' > "$AIWANBAL_STATE_DIR/wan2_latency"
|
||||
printf '30000000\n' > "$AIWANBAL_STATE_DIR/wan2_throughput"
|
||||
printf '5000000\n' > "$AIWANBAL_STATE_DIR/wan2_upload"
|
||||
printf '5\n' > "$AIWANBAL_STATE_DIR/wan2_jitter"
|
||||
printf '1\n' > "$AIWANBAL_STATE_DIR/wan2_packet_loss"
|
||||
printf -- '-90\n' > "$AIWANBAL_STATE_DIR/wan2_rsrp"
|
||||
printf 'generic\n' > "$AIWANBAL_STATE_DIR/wan2_modem_type"
|
||||
|
||||
printf 'active\n' > "$AIWANBAL_STATE_DIR/wan0_mode"
|
||||
|
||||
# Fake device identity
|
||||
mkdir -p /etc/busrouter
|
||||
printf 'B0042\n' > /etc/busrouter/device-id
|
||||
printf '1.0\n' > /etc/busrouter/version
|
||||
|
||||
# Load the library under test
|
||||
load '../../package/kit-busrouter/files/usr/lib/busrouter/telemetry-synology.sh'
|
||||
}
|
||||
|
||||
teardown() {
|
||||
rm -rf "$AIWANBAL_STATE_DIR" "$TELEMETRY_BUFFER_DIR"
|
||||
rm -f /etc/busrouter/device-id /etc/busrouter/version
|
||||
}
|
||||
|
||||
# ── Data collection ──────────────────────────────────────────────────────────────
|
||||
|
||||
@test "telemetry_synology_collect: output contains required JSON keys" {
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"device_id"'
|
||||
echo "$output" | grep -q '"timestamp"'
|
||||
echo "$output" | grep -q '"uptime"'
|
||||
echo "$output" | grep -q '"version"'
|
||||
echo "$output" | grep -q '"platform":"synology"'
|
||||
echo "$output" | grep -q '"gps"'
|
||||
echo "$output" | grep -q '"wan"'
|
||||
echo "$output" | grep -q '"wan1"'
|
||||
echo "$output" | grep -q '"wan2"'
|
||||
echo "$output" | grep -q '"starlink"'
|
||||
echo "$output" | grep -q '"sel_primary"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: device_id from identity file" {
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"device_id":"B0042"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: falls back to hostname when identity file missing" {
|
||||
rm -f /etc/busrouter/device-id
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
# Should contain a device_id (whatever hostname returns)
|
||||
echo "$output" | grep -q '"device_id"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: handles missing state files gracefully" {
|
||||
rm -rf "$AIWANBAL_STATE_DIR"
|
||||
mkdir -p "$AIWANBAL_STATE_DIR"
|
||||
# No state files at all — should still produce valid JSON
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"wan1"'
|
||||
echo "$output" | grep -q '"wan2"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: sel_primary is wan1 in active mode" {
|
||||
printf 'active\n' > "$AIWANBAL_STATE_DIR/wan0_mode"
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"sel_primary":"wan1"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: sel_primary is wan2 in failover when wan2 up" {
|
||||
printf 'failover\n' > "$AIWANBAL_STATE_DIR/wan0_mode"
|
||||
printf 'up\n' > "$AIWANBAL_STATE_DIR/wan2_state"
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"sel_primary":"wan2"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: wan JSON includes cellular metadata" {
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"rsrp_dbm"'
|
||||
echo "$output" | grep -q '"technology"'
|
||||
echo "$output" | grep -q '"carrier"'
|
||||
echo "$output" | grep -q '"5G-NR"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: throughput converted from B/s to Mbps" {
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
# 50000000 B/s = ~400 Mbps → should appear as "dl_mbps":400.0 or similar
|
||||
echo "$output" | grep -q '"dl_mbps"'
|
||||
}
|
||||
|
||||
@test "telemetry_synology_collect: gps is null when Eyeride unavailable" {
|
||||
# Without EYERIDE_PASSWORD, eyeride_gps returns 1 → gps fields are null
|
||||
unset EYERIDE_PASSWORD
|
||||
run telemetry_synology_collect
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"lat":null'
|
||||
echo "$output" | grep -q '"lon":null'
|
||||
echo "$output" | grep -q '"fix":null'
|
||||
}
|
||||
|
||||
# ── Buffering + POST ─────────────────────────────────────────────────────────────
|
||||
|
||||
@test "telemetry_synology_send: buffers payload when curl fails" {
|
||||
mkdir -p "$BATS_TMPDIR/tel_stub"
|
||||
printf '#!/bin/sh\nexit 7\n' > "$BATS_TMPDIR/tel_stub/curl"
|
||||
chmod +x "$BATS_TMPDIR/tel_stub/curl"
|
||||
export PATH="$BATS_TMPDIR/tel_stub:$PATH"
|
||||
export TELEMETRY_BUFFER_DIR="$BATS_TMPDIR/buf_test"
|
||||
rm -rf "$TELEMETRY_BUFFER_DIR"
|
||||
|
||||
run telemetry_synology_send
|
||||
[ -d "$TELEMETRY_BUFFER_DIR" ]
|
||||
buf_count=$(ls "$TELEMETRY_BUFFER_DIR"/*.json 2>/dev/null | wc -l)
|
||||
[ "$buf_count" -ge 1 ]
|
||||
}
|
||||
|
||||
@test "telemetry_synology_flush: posts and removes buffered file on success" {
|
||||
mkdir -p "$BATS_TMPDIR/tel_stub2"
|
||||
printf '#!/bin/sh\necho 200\n' > "$BATS_TMPDIR/tel_stub2/curl"
|
||||
chmod +x "$BATS_TMPDIR/tel_stub2/curl"
|
||||
export PATH="$BATS_TMPDIR/tel_stub2:$PATH"
|
||||
export TELEMETRY_BUFFER_DIR="$BATS_TMPDIR/flush_test"
|
||||
mkdir -p "$TELEMETRY_BUFFER_DIR"
|
||||
echo '{"test":1}' > "$TELEMETRY_BUFFER_DIR/1234567890_test.json"
|
||||
|
||||
run telemetry_synology_flush
|
||||
[ "$status" -eq 0 ]
|
||||
[ ! -f "$TELEMETRY_BUFFER_DIR/1234567890_test.json" ]
|
||||
}
|
||||
|
||||
@test "telemetry_synology_flush: stops on first failure" {
|
||||
mkdir -p "$BATS_TMPDIR/tel_stub3"
|
||||
# curl that fails on second call
|
||||
printf '#!/bin/sh\nif [ -f /tmp/first_done ]; then exit 7; fi\ntouch /tmp/first_done; echo 200\n' > "$BATS_TMPDIR/tel_stub3/curl"
|
||||
chmod +x "$BATS_TMPDIR/tel_stub3/curl"
|
||||
export PATH="$BATS_TMPDIR/tel_stub3:$PATH"
|
||||
export TELEMETRY_BUFFER_DIR="$BATS_TMPDIR/flush_fail"
|
||||
rm -f /tmp/first_done
|
||||
mkdir -p "$TELEMETRY_BUFFER_DIR"
|
||||
echo '{"test":1}' > "$TELEMETRY_BUFFER_DIR/1111111111_a.json"
|
||||
echo '{"test":2}' > "$TELEMETRY_BUFFER_DIR/2222222222_b.json"
|
||||
|
||||
run telemetry_synology_flush
|
||||
[ "$status" -ne 0 ]
|
||||
# First file should be deleted, second should remain
|
||||
[ ! -f "$TELEMETRY_BUFFER_DIR/1111111111_a.json" ]
|
||||
[ -f "$TELEMETRY_BUFFER_DIR/2222222222_b.json" ]
|
||||
rm -f /tmp/first_done
|
||||
}
|
||||
|
||||
# ── WAN JSON fragment ────────────────────────────────────────────────────────────
|
||||
|
||||
@test "_synology_wan_json: produces valid JSON fragment" {
|
||||
run _synology_wan_json 1
|
||||
[ "$status" -eq 0 ]
|
||||
# Should be a valid JSON object (starts with {, ends with })
|
||||
echo "$output" | grep -q '^{'
|
||||
echo "$output" | grep -q '}$'
|
||||
echo "$output" | grep -q '"score"'
|
||||
echo "$output" | grep -q '"latency_ms"'
|
||||
echo "$output" | grep -q '"carrier"'
|
||||
}
|
||||
|
||||
@test "_synology_wan_json: defaults score to 0 when file missing" {
|
||||
rm -f "$AIWANBAL_STATE_DIR/wan1_score_avg"
|
||||
run _synology_wan_json 1
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"score":0'
|
||||
}
|
||||
|
||||
@test "_synology_wan_json: modem type maps to carrier name" {
|
||||
printf 'peplink\n' > "$AIWANBAL_STATE_DIR/wan1_modem_type"
|
||||
run _synology_wan_json 1
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | grep -q '"carrier":"Peplink"'
|
||||
}
|
||||
|
||||
# ── eyeride_gps ──────────────────────────────────────────────────────────────────
|
||||
|
||||
@test "eyeride_gps: returns 1 when no password set" {
|
||||
unset EYERIDE_PASSWORD
|
||||
run eyeride_gps
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "eyeride_gps: returns 1 when eyeride unreachable" {
|
||||
export EYERIDE_PASSWORD="test"
|
||||
export EYERIDE_IP="192.0.2.1" # TEST-NET-1 — guaranteed unreachable
|
||||
export EYERIDE_PORT="9999"
|
||||
run eyeride_gps
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
Reference in New Issue
Block a user