package main 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. func TestResetDoesNotUnderflowTotals(t *testing.T) { d := &direction{ win: newRateWindow(8), cable: newCableStats(), rxStats: []*rxStats{{}}, } d.rxStats[0].frames.Store(100) d.rxStats[0].bytes.Store(6400) d.sample() d.rxStats[0].frames.Store(150) d.rxStats[0].bytes.Store(9600) d.reset() v := d.displayView() if v.rxFrames != 0 { t.Errorf("rxFrames = %d, want 0", v.rxFrames) } if v.rxBytes != 0 { t.Errorf("rxBytes = %d, want 0", v.rxBytes) } // The rolling window and the rates are about now rather than since the // reset, so the buckets from before it have to survive. if got := d.win.count(); got < 2 { t.Errorf("ring holds %d buckets after reset, want the pre-reset history kept", got) } }