257 lines
4.4 KiB
Go
257 lines
4.4 KiB
Go
package ratecounter
|
|
|
|
import (
|
|
"fmt"
|
|
"io/ioutil"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestRateCounter(t *testing.T) {
|
|
interval := 500 * time.Millisecond
|
|
r := NewRateCounter(interval)
|
|
|
|
check := func(expected int64) {
|
|
val := r.Rate()
|
|
if val != expected {
|
|
t.Error("Expected ", val, " to equal ", expected)
|
|
}
|
|
}
|
|
|
|
check(0)
|
|
r.Incr(1)
|
|
check(1)
|
|
r.Incr(2)
|
|
check(3)
|
|
time.Sleep(2 * interval)
|
|
check(0)
|
|
}
|
|
|
|
func TestRateCounterResetAndRestart(t *testing.T) {
|
|
interval := 100 * time.Millisecond
|
|
|
|
r := NewRateCounter(interval)
|
|
|
|
check := func(expected int64) {
|
|
val := r.Rate()
|
|
if val != expected {
|
|
t.Error("Expected ", val, " to equal ", expected)
|
|
}
|
|
}
|
|
|
|
check(0)
|
|
r.Incr(1)
|
|
check(1)
|
|
time.Sleep(2 * interval)
|
|
check(0)
|
|
time.Sleep(2 * interval)
|
|
r.Incr(2)
|
|
check(2)
|
|
time.Sleep(2 * interval)
|
|
check(0)
|
|
r.Incr(2)
|
|
check(2)
|
|
}
|
|
|
|
func TestRateCounterPartial(t *testing.T) {
|
|
interval := 500 * time.Millisecond
|
|
almostinterval := 400 * time.Millisecond
|
|
|
|
r := NewRateCounter(interval)
|
|
|
|
check := func(expected int64) {
|
|
val := r.Rate()
|
|
if val != expected {
|
|
t.Error("Expected ", val, " to equal ", expected)
|
|
}
|
|
}
|
|
|
|
check(0)
|
|
r.Incr(1)
|
|
check(1)
|
|
time.Sleep(almostinterval)
|
|
r.Incr(2)
|
|
check(3)
|
|
time.Sleep(almostinterval)
|
|
check(2)
|
|
time.Sleep(2 * interval)
|
|
check(0)
|
|
}
|
|
|
|
func TestRateCounterHighResolution(t *testing.T) {
|
|
interval := 500 * time.Millisecond
|
|
tenth := 50 * time.Millisecond
|
|
|
|
r := NewRateCounter(interval).WithResolution(100)
|
|
|
|
check := func(expected int64) {
|
|
val := r.Rate()
|
|
if val != expected {
|
|
t.Error("Expected ", val, " to equal ", expected)
|
|
}
|
|
}
|
|
|
|
check(0)
|
|
r.Incr(1)
|
|
check(1)
|
|
time.Sleep(2 * tenth)
|
|
r.Incr(1)
|
|
check(2)
|
|
time.Sleep(2 * tenth)
|
|
r.Incr(1)
|
|
check(3)
|
|
time.Sleep(interval - 5*tenth)
|
|
check(3)
|
|
time.Sleep(2 * tenth)
|
|
check(2)
|
|
time.Sleep(2 * tenth)
|
|
check(1)
|
|
time.Sleep(2 * tenth)
|
|
check(0)
|
|
}
|
|
|
|
func TestRateCounterLowResolution(t *testing.T) {
|
|
interval := 500 * time.Millisecond
|
|
tenth := 50 * time.Millisecond
|
|
|
|
r := NewRateCounter(interval).WithResolution(4)
|
|
|
|
check := func(expected int64) {
|
|
val := r.Rate()
|
|
if val != expected {
|
|
t.Error("Expected ", val, " to equal ", expected)
|
|
}
|
|
}
|
|
|
|
check(0)
|
|
r.Incr(1)
|
|
check(1)
|
|
time.Sleep(2 * tenth)
|
|
r.Incr(1)
|
|
check(2)
|
|
time.Sleep(2 * tenth)
|
|
r.Incr(1)
|
|
check(3)
|
|
time.Sleep(interval - 5*tenth)
|
|
check(3)
|
|
time.Sleep(2 * tenth)
|
|
check(1)
|
|
time.Sleep(2 * tenth)
|
|
check(0)
|
|
time.Sleep(2 * tenth)
|
|
check(0)
|
|
}
|
|
|
|
func TestRateCounterMinResolution(t *testing.T) {
|
|
defer func() {
|
|
if r := recover(); r == nil {
|
|
t.Errorf("Resolution < 1 did not panic")
|
|
}
|
|
}()
|
|
|
|
NewRateCounter(500 * time.Millisecond).WithResolution(0)
|
|
}
|
|
|
|
func TestRateCounterNoResolution(t *testing.T) {
|
|
interval := 500 * time.Millisecond
|
|
tenth := 50 * time.Millisecond
|
|
|
|
r := NewRateCounter(interval).WithResolution(1)
|
|
|
|
check := func(expected int64) {
|
|
val := r.Rate()
|
|
if val != expected {
|
|
t.Error("Expected ", val, " to equal ", expected)
|
|
}
|
|
}
|
|
|
|
check(0)
|
|
r.Incr(1)
|
|
check(1)
|
|
time.Sleep(2 * tenth)
|
|
r.Incr(1)
|
|
check(2)
|
|
time.Sleep(2 * tenth)
|
|
r.Incr(1)
|
|
check(3)
|
|
time.Sleep(interval - 5*tenth)
|
|
check(3)
|
|
time.Sleep(2 * tenth)
|
|
check(0)
|
|
time.Sleep(2 * tenth)
|
|
check(0)
|
|
time.Sleep(2 * tenth)
|
|
check(0)
|
|
}
|
|
|
|
func TestRateCounter_String(t *testing.T) {
|
|
r := NewRateCounter(1 * time.Second)
|
|
if r.String() != "0" {
|
|
t.Error("Expected ", r.String(), " to equal ", "0")
|
|
}
|
|
|
|
r.Incr(1)
|
|
if r.String() != "1" {
|
|
t.Error("Expected ", r.String(), " to equal ", "1")
|
|
}
|
|
}
|
|
|
|
func TestRateCounter_Incr_ReturnsImmediately(t *testing.T) {
|
|
interval := 1 * time.Second
|
|
r := NewRateCounter(interval)
|
|
|
|
start := time.Now()
|
|
r.Incr(-1)
|
|
duration := time.Since(start)
|
|
|
|
if duration >= 1*time.Second {
|
|
t.Error("incr took", duration, "to return")
|
|
}
|
|
}
|
|
|
|
func BenchmarkRateCounter(b *testing.B) {
|
|
interval := 0 * time.Millisecond
|
|
r := NewRateCounter(interval)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
r.Incr(1)
|
|
r.Rate()
|
|
}
|
|
}
|
|
|
|
func BenchmarkRateCounter_Parallel(b *testing.B) {
|
|
interval := 0 * time.Millisecond
|
|
r := NewRateCounter(interval)
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
r.Incr(1)
|
|
r.Rate()
|
|
}
|
|
})
|
|
}
|
|
|
|
func BenchmarkRateCounter_With5MillionExisting(b *testing.B) {
|
|
interval := 1 * time.Hour
|
|
r := NewRateCounter(interval)
|
|
|
|
for i := 0; i < 5000000; i++ {
|
|
r.Incr(1)
|
|
}
|
|
|
|
b.ResetTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
r.Incr(1)
|
|
r.Rate()
|
|
}
|
|
}
|
|
|
|
func Benchmark_TimeNowAndAdd(b *testing.B) {
|
|
var a time.Time
|
|
for i := 0; i < b.N; i++ {
|
|
a = time.Now().Add(1 * time.Second)
|
|
}
|
|
fmt.Fprintln(ioutil.Discard, a)
|
|
}
|