mirror of
https://github.com/MeshCore-Beacon/beacon-server.git
synced 2026-10-20 11:01:56 +00:00
An observer sending NUL-padded status strings had every status update rejected by Postgres, freezing its status and telemetry. Strip them from the text fields and the stored JSON, and warn with the fields affected. Also drop the timestamp-clamp, empty-timestamp and malformed-IATA logs to debug; they're expected and outnumbered inserted packets several times over.
75 lines
2.4 KiB
Go
75 lines
2.4 KiB
Go
// Copyright 2026 Beacon Contributors
|
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
package ingest
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestStatusStatsUsable(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
raw string
|
|
want bool
|
|
}{
|
|
{"full stats", `{"uptime_secs":1093083,"noise_floor":-96,"tx_air_secs":7935,"rx_air_secs":47484,"recv_errors":93689}`, true},
|
|
{"missing stats", `{}`, false},
|
|
{"uptime only", `{"uptime_secs":1096701,"noise_floor":0,"tx_air_secs":0,"rx_air_secs":0,"recv_errors":0}`, false},
|
|
{"uptime and recv errors only", `{"uptime_secs":3834495,"recv_errors":325529}`, false},
|
|
{"fresh boot, no airtime yet", `{"uptime_secs":60,"noise_floor":-110,"tx_air_secs":0,"rx_air_secs":0}`, true},
|
|
{"no noise floor reported", `{"uptime_secs":5000,"tx_air_secs":3,"rx_air_secs":40}`, true},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
var s statusStats
|
|
if err := json.Unmarshal([]byte(c.raw), &s); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := s.usable(); got != c.want {
|
|
t.Errorf("usable() = %v, want %v", got, c.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStripNULs(t *testing.T) {
|
|
fw := "v1.17.1-d929643\x00\x00\x00"
|
|
name := "Canadaverse\x00 RemoteTerm"
|
|
model := "Heltec Wireless Paper"
|
|
got := stripNULs(map[string]*string{"firmware_version": &fw, "origin": &name, "model": &model})
|
|
if fw != "v1.17.1-d929643" || name != "Canadaverse RemoteTerm" || model != "Heltec Wireless Paper" {
|
|
t.Errorf("stripped to %q %q %q", fw, name, model)
|
|
}
|
|
if len(got) != 2 || got[0] != "firmware_version" || got[1] != "origin" {
|
|
t.Errorf("reported fields %v, want [firmware_version origin]", got)
|
|
}
|
|
}
|
|
|
|
func TestStripJSONNULs(t *testing.T) {
|
|
clean := []byte(`{"origin":"a","stats":{"uptime_secs":12}}`)
|
|
if out, changed := stripJSONNULs(clean); changed || string(out) != string(clean) {
|
|
t.Errorf("clean payload rewritten: %s", out)
|
|
}
|
|
|
|
dirty := []byte(`{"firmware_version":"v1.17\u0000\u0000","extra":{"list":["x\u0000y"],"n":1.50}}`)
|
|
out, changed := stripJSONNULs(dirty)
|
|
if !changed {
|
|
t.Fatal("expected payload to be cleaned")
|
|
}
|
|
var v struct {
|
|
FirmwareVersion string `json:"firmware_version"`
|
|
Extra struct {
|
|
List []string `json:"list"`
|
|
N json.Number `json:"n"`
|
|
} `json:"extra"`
|
|
}
|
|
if err := json.Unmarshal(out, &v); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v.FirmwareVersion != "v1.17" || v.Extra.List[0] != "xy" || v.Extra.N != "1.50" {
|
|
t.Errorf("cleaned to %s", out)
|
|
}
|
|
}
|