Initial commit: Go SRE interview exercises
Includes solved 02-worker-pool and 09-safe-counter (mutex, atomic, sharded). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GbnJj9ZqEx9nUvzkjdwfMq
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestBurstAllowedThenDenied(t *testing.T) {
|
||||
l := NewLimiter(1, 3) // slow refill so it doesn't interfere
|
||||
for i := 0; i < 3; i++ {
|
||||
if !l.Allow() {
|
||||
t.Fatalf("request %d within burst should be allowed", i)
|
||||
}
|
||||
}
|
||||
if l.Allow() {
|
||||
t.Fatal("4th immediate request should be denied (bucket empty)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefillOverTime(t *testing.T) {
|
||||
l := NewLimiter(20, 1) // 20 tokens/sec => 1 token per 50ms
|
||||
if !l.Allow() {
|
||||
t.Fatal("initial token missing")
|
||||
}
|
||||
if l.Allow() {
|
||||
t.Fatal("bucket should be empty immediately after")
|
||||
}
|
||||
time.Sleep(120 * time.Millisecond) // ~2.4 tokens accrued, capped at 1
|
||||
if !l.Allow() {
|
||||
t.Fatal("token should have refilled after wait")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBurstIsCapped(t *testing.T) {
|
||||
l := NewLimiter(1000, 2)
|
||||
time.Sleep(50 * time.Millisecond) // would accrue ~50 tokens uncapped
|
||||
allowed := 0
|
||||
for i := 0; i < 10; i++ {
|
||||
if l.Allow() {
|
||||
allowed++
|
||||
}
|
||||
}
|
||||
if allowed > 2 {
|
||||
t.Fatalf("bucket exceeded burst: %d immediate allows (cap 2) — idle time built infinite credit", allowed)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrentNoOverAdmission(t *testing.T) {
|
||||
l := NewLimiter(0.0001, 100) // effectively no refill during the test
|
||||
var allowed atomic.Int64
|
||||
var wg sync.WaitGroup
|
||||
for i := 0; i < 50; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for j := 0; j < 10; j++ {
|
||||
if l.Allow() {
|
||||
allowed.Add(1)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
if got := allowed.Load(); got > 100 {
|
||||
t.Fatalf("over-admission under concurrency: %d > 100 tokens spent", got)
|
||||
} else if got < 100 {
|
||||
t.Fatalf("under-admission: only %d of 100 available tokens spent", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user