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