package ratelimit import ( "testing" "time" ) func TestLimiter(t *testing.T) { now := time.Date(2026, 10, 2, 12, 0, 0, 0, time.UTC) l := &Limiter{Limit: 3, Window: time.Minute, now: func() time.Time { return now }} for i := range 3 { if ok, _ := l.Allow("1.2.3.4"); !ok { t.Fatalf("Versuch %d abgelehnt", i+1) } } ok, retry := l.Allow("1.2.3.4") if ok || retry != time.Minute { t.Errorf("4. Versuch: ok=%v retry=%v, erwartet abgelehnt mit 1 min", ok, retry) } if ok, _ := l.Allow("5.6.7.8"); !ok { t.Error("andere IP mitbetroffen") } now = now.Add(40 * time.Second) if _, retry := l.Allow("1.2.3.4"); retry != 20*time.Second { t.Errorf("Retry-After nach 40 s: %v, erwartet 20 s", retry) } now = now.Add(20 * time.Second) if ok, _ := l.Allow("1.2.3.4"); !ok { t.Error("nach Ablauf des Fensters weiter gesperrt") } } // Die Zählerliste darf bei vielen IPs nicht unbegrenzt wachsen. func TestLimiter_ForgetsOldEntries(t *testing.T) { now := time.Date(2026, 10, 2, 12, 0, 0, 0, time.UTC) l := &Limiter{Limit: 1, Window: time.Minute, now: func() time.Time { return now }} for i := range 1000 { l.Allow(string(rune('a'+i%26)) + time.Duration(i).String()) } now = now.Add(2 * time.Minute) l.Allow("neu") if n := l.size(); n != 1 { t.Errorf("%d Einträge nach Ablauf, erwartet 1", n) } } func TestLimiter_Disabled(t *testing.T) { l := &Limiter{Limit: -1, Window: time.Minute} for range 100 { if ok, _ := l.Allow("x"); !ok { t.Fatal("Limit -1 muss unbegrenzt sein") } } }