Files
beacon-server/internal/cache/scope_stats_test.go
T
MrAlders0n 98006a9364 feat(stats): serve historical stats from hourly rollups
Stats endpoints read hourly rollup tables filled once per closed hour by one
advisory-locked task, instead of materialized views that re-scanned every
observation on each refresh. IATA-set tables give exact distinct counts for any
IATA set or region. Cleanup holds raw rows for unrolled hours (up to 24h).

Adds /stats/series; ingest keeps packet observation counts, observer last IATA,
channel message counts and trace tag summaries. 001_baseline.sql is rewritten,
so pre-release 2.0 databases must be recreated. See docs/historical-stats.md.
2026-10-02 07:43:56 -04:00

62 lines
1.5 KiB
Go

// Copyright 2026 Beacon Contributors
// SPDX-License-Identifier: AGPL-3.0-or-later
package cache
import (
"context"
"slices"
"testing"
"time"
"github.com/MeshCore-Beacon/beacon-server/internal/api"
)
type scopeStatsReader struct {
api.Reader
calls int64
}
func (r *scopeStatsReader) GetScopeStats(context.Context, []string, time.Time) ([]api.ScopeStats, error) {
r.calls++
return []api.ScopeStats{{Name: "#test", PacketCount: r.calls}}, nil
}
func (r *scopeStatsReader) AnalyticsRevision(context.Context) (int64, error) { return 0, nil }
func TestScopeStatsCacheSeparatesIATAs(t *testing.T) {
c, _ := newTestClient(t)
inner := &scopeStatsReader{}
reader := NewCachedReader(inner, c, CacheTTLs{Reference: time.Minute})
for _, tc := range []struct {
iatas []string
want int64
}{
{nil, 1},
{[]string{"YVR"}, 2},
{[]string{"YYJ"}, 3},
{[]string{"YYJ", "YVR"}, 4},
{[]string{"YVR", "YYJ", "YVR"}, 4},
{[]string{"YVR"}, 2},
{[]string{}, 1},
{[]string{"ZZZ"}, 5},
{[]string{""}, 6},
{nil, 1},
} {
before := slices.Clone(tc.iatas)
rows, err := reader.GetScopeStats(context.Background(), tc.iatas, time.Time{})
if err != nil {
t.Fatal(err)
}
if len(rows) != 1 || rows[0].PacketCount != tc.want {
t.Fatalf("IATAs %v: got %+v, want cached count %d", tc.iatas, rows, tc.want)
}
if !slices.Equal(before, tc.iatas) {
t.Fatalf("caller IATAs mutated: %v -> %v", before, tc.iatas)
}
}
if inner.calls != 6 {
t.Fatalf("underlying calls = %d, want 6", inner.calls)
}
}