Speed meter
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBandwidthSamplerFirstObservationIsBaselineOnly(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Minute)
|
||||
now := time.Now()
|
||||
s.Observe("bob", 10_000, 20_000, now)
|
||||
rate, ok := s.Rate("bob")
|
||||
if !ok {
|
||||
t.Fatal("expected the account to be tracked after the first observation")
|
||||
}
|
||||
if !rate.isZero() {
|
||||
t.Fatalf("first observation must not report a speed, got %+v", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerComputesBytesPerSecond(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Minute) // no smoothing: exact delta/dt
|
||||
now := time.Now()
|
||||
s.Observe("bob", 0, 0, now)
|
||||
// 2 MB up and 10 MB down over 2 seconds.
|
||||
s.Observe("bob", 2<<20, 10<<20, now.Add(2*time.Second))
|
||||
rate, _ := s.Rate("bob")
|
||||
if wantUp := float64(1 << 20); rate.UpBytesPerSec != wantUp {
|
||||
t.Fatalf("up = %v, want %v", rate.UpBytesPerSec, wantUp)
|
||||
}
|
||||
if wantDown := float64(5 << 20); rate.DownBytesPerSec != wantDown {
|
||||
t.Fatalf("down = %v, want %v", rate.DownBytesPerSec, wantDown)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerIgnoresSamplesTakenTooCloseTogether(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Minute)
|
||||
now := time.Now()
|
||||
s.Observe("bob", 0, 0, now)
|
||||
s.Observe("bob", 5<<20, 5<<20, now.Add(10*time.Millisecond))
|
||||
rate, _ := s.Rate("bob")
|
||||
if !rate.isZero() {
|
||||
t.Fatalf("a 10ms interval must not produce a speed, got %+v", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerRebaselinesAfterTrafficReset(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Minute)
|
||||
now := time.Now()
|
||||
s.Observe("bob", 0, 0, now)
|
||||
s.Observe("bob", 4<<20, 4<<20, now.Add(2*time.Second))
|
||||
// Panel reset the account's traffic: counters go back to zero.
|
||||
s.Observe("bob", 0, 0, now.Add(4*time.Second))
|
||||
rate, _ := s.Rate("bob")
|
||||
if !rate.isZero() {
|
||||
t.Fatalf("counters moving backwards must reset the speed, got %+v", rate)
|
||||
}
|
||||
s.Observe("bob", 2<<20, 0, now.Add(6*time.Second))
|
||||
rate, _ = s.Rate("bob")
|
||||
if wantUp := float64(1 << 20); rate.UpBytesPerSec != wantUp {
|
||||
t.Fatalf("up after reset = %v, want %v", rate.UpBytesPerSec, wantUp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerReportsZeroWhenIdle(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Minute)
|
||||
now := time.Now()
|
||||
s.Observe("bob", 0, 0, now)
|
||||
s.Observe("bob", 4<<20, 4<<20, now.Add(2*time.Second))
|
||||
s.Observe("bob", 4<<20, 4<<20, now.Add(4*time.Second))
|
||||
rate, _ := s.Rate("bob")
|
||||
if !rate.isZero() {
|
||||
t.Fatalf("unchanged counters must report an idle account, got %+v", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerDropsStaleSpeeds(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Second)
|
||||
now := time.Now().Add(-time.Hour)
|
||||
s.Observe("bob", 0, 0, now)
|
||||
s.Observe("bob", 4<<20, 4<<20, now.Add(2*time.Second))
|
||||
rate, ok := s.Rate("bob")
|
||||
if !ok {
|
||||
t.Fatal("expected the account to still be tracked")
|
||||
}
|
||||
if !rate.isZero() {
|
||||
t.Fatalf("an hour-old sample must not still report a speed, got %+v", rate)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerSmoothsWithTimeConstant(t *testing.T) {
|
||||
s := newBandwidthSampler(5*time.Second, time.Minute)
|
||||
now := time.Now()
|
||||
s.Observe("bob", 0, 0, now)
|
||||
// First real sample has no previous rate to blend with, so it lands exactly.
|
||||
s.Observe("bob", 2<<20, 0, now.Add(2*time.Second))
|
||||
first, _ := s.Rate("bob")
|
||||
if first.UpBytesPerSec != float64(1<<20) {
|
||||
t.Fatalf("first speed = %v, want %v", first.UpBytesPerSec, float64(1<<20))
|
||||
}
|
||||
// Traffic stops: the smoothed value has to fall without jumping to zero.
|
||||
s.Observe("bob", 2<<20, 0, now.Add(4*time.Second))
|
||||
second, _ := s.Rate("bob")
|
||||
if second.UpBytesPerSec <= 0 || second.UpBytesPerSec >= first.UpBytesPerSec {
|
||||
t.Fatalf("smoothed speed = %v, want a value between 0 and %v", second.UpBytesPerSec, first.UpBytesPerSec)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBandwidthSamplerRateForKeysAndRetain(t *testing.T) {
|
||||
s := newBandwidthSampler(0, time.Minute)
|
||||
now := time.Now()
|
||||
s.Observe("uuid-1", 0, 0, now)
|
||||
s.Observe("uuid-1", 1<<20, 0, now.Add(1*time.Second))
|
||||
if _, ok := s.RateForKeys("", "unknown@example", "uuid-1"); !ok {
|
||||
t.Fatal("RateForKeys must find the client under any of its identifiers")
|
||||
}
|
||||
s.Retain(map[string]struct{}{"uuid-2": {}})
|
||||
if _, ok := s.Rate("uuid-1"); ok {
|
||||
t.Fatal("Retain must drop accounts that no longer exist")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user