Cover the loss window, rate window, error taxonomy and formatters with tests

This commit is contained in:
flamingcow
2026-08-04 15:46:12 -07:00
parent 63196eb691
commit 8db5c29882
5 changed files with 315 additions and 1 deletions
+63 -1
View File
@@ -1,6 +1,68 @@
package main
import "testing"
import (
"testing"
"time"
)
func TestRateWindowLatestNeedsTwoBuckets(t *testing.T) {
w := newRateWindow(4)
if got := w.latest(rxRatePPS); got != 0 {
t.Errorf("empty ring gave %v, want 0", got)
}
w.push(counterSet{t: time.Now(), s: sample{rxFrames: 100}})
if got := w.latest(rxRatePPS); got != 0 {
t.Errorf("one bucket gave %v, want 0", got)
}
}
// The newest pair alone, so a step in the rate shows at once instead of being
// averaged against everything still in the ring.
func TestRateWindowLatestUsesNewestPair(t *testing.T) {
w := newRateWindow(4)
t0 := time.Now()
w.push(counterSet{t: t0, s: sample{rxFrames: 100}})
w.push(counterSet{t: t0.Add(time.Second), s: sample{rxFrames: 300}})
if got := w.latest(rxRatePPS); got != 200 {
t.Errorf("rate = %v, want 200", got)
}
w.push(counterSet{t: t0.Add(2 * time.Second), s: sample{rxFrames: 400}})
if got := w.latest(rxRatePPS); got != 100 {
t.Errorf("rate = %v, want 100 rather than the mean of the ring", got)
}
}
func TestRateWindowLatestIgnoresZeroSpan(t *testing.T) {
w := newRateWindow(4)
t0 := time.Now()
w.push(counterSet{t: t0, s: sample{rxFrames: 100}})
w.push(counterSet{t: t0, s: sample{rxFrames: 300}})
if got := w.latest(rxRatePPS); got != 0 {
t.Errorf("rate = %v, want 0", got)
}
}
// Which counter feeds which bucket is the whole taxonomy the panel reports, so
// it is pinned here rather than left to whoever reads errsBetween next.
func TestErrsBetweenBuckets(t *testing.T) {
n := counterSet{
s: sample{
lost: 1, late: 7,
crcErr: 2, badMagic: 3, badLen: 4,
txErrs: 6, rxErrs: 5,
},
drops: 9,
nic: 8,
}
got := errsBetween(counterSet{}, n)
want := errs{lost: 1, corrupt: 2 + 3 + 4, link: 8 + 5, internal: 9 + 7 + 6}
if got != want {
t.Errorf("errsBetween = %+v, want %+v", got, want)
}
if got.total() != 45 {
t.Errorf("total = %d, want 45", got.total())
}
}
// A reset re-bases from a fresh capture while the ring still holds buckets from
// just before it, so the newest bucket must not be left behind the new origin.