The car sends live data to ABRP itself, and the car and the server go over the same mobile connection: when the car cannot reach ABRP, it cannot reach the server either, so the server's fallback bought nothing. The forwarder, its ABRP_* settings and abrpSentUtc are gone; the server only stores. The app stops sending abrpSentUtc (the server ignores unknown fields, so 2.11.0 keeps working) and its texts no longer promise a server fallback. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLJfZQZeAKAwSqViTmLzki
68 lines
2.1 KiB
Go
68 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func chunk(date string, atMs int64, km, kwh float64, soh *float64) ConsumptionChunk {
|
|
return ConsumptionChunk{
|
|
InstallationID: testInstallation, Date: date, RecordedAt: time.UnixMilli(atMs),
|
|
Day: Totals{Km: km, Kwh: kwh, Hours: km / 50, SocDrop: kwh / 0.6}, SohPercent: soh,
|
|
}
|
|
}
|
|
|
|
func ptr(f float64) *float64 { return &f }
|
|
|
|
func TestAggregateDaysSumsPerDayNewestFirstWithRunningLifetime(t *testing.T) {
|
|
days := aggregateDays([]ConsumptionChunk{
|
|
chunk("2026-10-16", 1000, 10, 2, nil),
|
|
chunk("2026-10-17", 3000, 5, 1, nil),
|
|
chunk("2026-10-16", 2000, 20, 3, nil),
|
|
})
|
|
if len(days) != 2 || days[0].Date != "2026-10-17" || days[1].Date != "2026-10-16" {
|
|
t.Fatalf("order: %+v", days)
|
|
}
|
|
if days[1].Day.Km != 30 || days[1].Day.Kwh != 5 || days[1].RecordedAt.UnixMilli() != 2000 {
|
|
t.Fatalf("day sums: %+v", days[1])
|
|
}
|
|
if days[1].Lifetime.Km != 30 || days[0].Lifetime.Km != 35 || days[0].Lifetime.Kwh != 6 {
|
|
t.Fatalf("lifetime: %+v / %+v", days[0].Lifetime, days[1].Lifetime)
|
|
}
|
|
}
|
|
|
|
func TestAggregateDaysNewestSohWins(t *testing.T) {
|
|
days := aggregateDays([]ConsumptionChunk{
|
|
chunk("2026-10-16", 2000, 1, 1, ptr(96)),
|
|
chunk("2026-10-16", 1000, 1, 1, ptr(98)),
|
|
chunk("2026-10-17", 3000, 1, 1, nil),
|
|
})
|
|
if *days[1].SohPercent != 96 {
|
|
t.Fatalf("want 96, got %v", *days[1].SohPercent)
|
|
}
|
|
if days[0].SohPercent != nil {
|
|
t.Fatal("a day without SoH got one")
|
|
}
|
|
}
|
|
|
|
func TestLoadConfigFailsClosed(t *testing.T) {
|
|
env := map[string]string{
|
|
"INFLUX_URL": "http://influxdb:8086", "INFLUX_TOKEN": "t", "INFLUX_ORG": "mg4",
|
|
"INGEST_TOKEN": "0123456789abcdef01234567",
|
|
}
|
|
get := func(k string) string { return env[k] }
|
|
c, err := loadConfig(get)
|
|
if err != nil || c.listenAddr != ":8080" || c.influxBucket != "mg4" {
|
|
t.Fatalf("defaults: %+v %v", c, err)
|
|
}
|
|
env["INGEST_TOKEN"] = "short"
|
|
if _, err := loadConfig(get); err == nil {
|
|
t.Fatal("short ingest token accepted")
|
|
}
|
|
env["INGEST_TOKEN"] = "0123456789abcdef01234567"
|
|
delete(env, "INFLUX_TOKEN")
|
|
if _, err := loadConfig(get); err == nil {
|
|
t.Fatal("missing InfluxDB token accepted")
|
|
}
|
|
}
|