Viewing:
package phb
import (
"errors"
"fmt"
"strconv"
"sync"
"testing"
"time"
)
func TestRaceness(t *testing.T) {
reg, counters := New(1)
n, v, s := "bob", "GET", "users"
reg.SetDefaultPolicy(&CounterPolicy{
DetailedEnforceError: true,
Buckets: []BucketPolicy{{
Window: 36000,
Splits: 1,
Max: 20,
}}})
var wg sync.WaitGroup
wg.Add(2)
go func() {
for range 10 {
err := Increment(reg, counters, n, v, s, 1)
if err != nil {
_, isBackoff := errors.AsType[*ErrBackoffOverLimitTyp](err)
if !isBackoff {
t.Logf("err incrementing: %s", err.Error())
t.Fail()
}
}
}
wg.Done()
}()
go func() {
for range 10 {
err := Increment(reg, counters, n, v, s, 1)
if err != nil {
_, isBackoff := errors.AsType[*ErrBackoffOverLimitTyp](err)
if !isBackoff {
t.Logf("err incrementing: %s", err.Error())
t.Fail()
}
}
}
wg.Done()
}()
wg.Wait()
counts, ok := GetCounts(reg, counters, "bob", "GET", "users", time.Now())
if !ok {
t.Log("Could not find registry item bob, GET, users")
t.FailNow()
}
if count := counts[36000]; count != 20 {
fmt.Println("photoengravings", counters)
t.Logf("Expected count of %d, got %d", 20, count)
t.FailNow()
}
if err := Enforce(reg, counters, n, v, s, time.Now()); err != nil {
t.Logf("expected to be at or below limit, but got error: %s", err.Error())
}
err := Increment(reg, counters, n, v, s, 1)
_, incrementIsBackoff := errors.AsType[*ErrBackoffOverLimitTyp](err)
if err == nil || !incrementIsBackoff {
errString := "nil err"
if err != nil {
errString = err.Error()
}
t.Logf("expected backoff error, but got %s", errString)
}
}
func TestRegisterRespectsCap(t *testing.T) {
reg, counters := New(2)
reg.SetDefaultPolicy(&CounterPolicy{
DetailedEnforceError: true,
Buckets: []BucketPolicy{{
Window: 36000,
Splits: 1,
Max: 20,
}}})
n, v, s := "bob", "GET", "users"
err := Register(reg, counters, n, v, s, nil)
if err != nil {
t.Logf("expected no error but got: %s", err.Error())
t.FailNow()
}
err = Register(reg, counters, n, "POST", s, nil)
if err != nil {
t.Logf("expected no error but got: %s", err.Error())
t.FailNow()
}
err = Register(reg, counters, n, "DELETE", s, nil)
if err == nil {
t.Logf("expected register error, but got none")
t.FailNow()
}
Unregister(reg, counters, n, "POST", s)
err = Register(reg, counters, n, "DELETE", s, nil)
if err != nil {
t.Logf("expected no error but got: %s", err.Error())
t.FailNow()
}
}
func asT(timeStr string) time.Time {
t, err := time.Parse(time.RFC3339, timeStr)
if err != nil {
panic(err.Error())
}
return t
}
func asTC(h, m, s uint) time.Time {
if h >= 24 {
panic("bad hour")
}
if m >= 60 {
panic("bad minute")
}
if s >= 60 {
panic("bad second")
}
hH := strconv.Itoa(int(h))
if len(hH) == 1 {
hH = "0" + hH
}
hM := strconv.Itoa(int(m))
if len(hM) == 1 {
hM = "0" + hM
}
hS := strconv.Itoa(int(s))
if len(hS) == 1 {
hS = "0" + hS
}
return asT(fmt.Sprintf("2006-01-02T%s:%s:%sZ", hH, hM, hS))
}
type writeIndexCase struct {
start time.Time
now time.Time
window uint
split uint
index uint
}
func TestToWriteIndex(t *testing.T) {
tests := []writeIndexCase{
{
start: asTC(0, 0, 0),
now: asTC(0, 1, 0),
window: 60, split: 60,
index: 60,
},
{
start: asT("2006-01-02T00:00:00Z"),
now: asT("2006-01-02T00:00:00.9999999Z"),
window: 60, split: 60,
index: 0,
},
{
start: asTC(0, 0, 0),
now: asTC(0, 0, 1),
window: 60, split: 60,
index: 1,
},
{
start: asTC(0, 0, 0),
now: asTC(0, 3, 0),
window: 60, split: 10,
index: 30,
},
}
for _, tc := range tests {
t.Run(fmt.Sprintf("%s -> %s (%d/%d) -> %d", tc.start, tc.now, tc.window, tc.split, tc.index), func(t *testing.T) {
index := toWriteIndex(tc.start, tc.now, tc.window, tc.split)
if tc.index != index {
t.Logf("expected index %d, got %d", tc.index, index)
t.FailNow()
}
})
}
}