Files
kit-busrouter/tests/bats/telemetry-synology.bats
kitadmin 24d8fbd366 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>
2026-07-22 21:20:08 +00:00

226 lines
8.3 KiB
Bash

# 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 ]
}