package middleware import ( "testing" "time" ) func TestFailureLimiterLocksOutAfterLimit(t *testing.T) { l := NewFailureLimiter(3, time.Minute, time.Minute) for i := 0; i < 2; i++ { l.Fail("10.0.0.1") if allowed, _ := l.Allowed("10.0.0.1"); !allowed { t.Fatalf("locked out after %d of 3 failures", i+1) } } l.Fail("10.0.0.1") allowed, retryAfter := l.Allowed("10.0.0.1") if allowed { t.Fatal("still allowed after reaching the failure limit") } if retryAfter <= 0 { t.Fatalf("retryAfter = %v, want positive so Retry-After is usable", retryAfter) } } // Ein Sync-Client darf nicht unter fremden Fehlversuchen leiden: Erfolg räumt // den Zähler weg. func TestFailureLimiterResetOnSuccess(t *testing.T) { l := NewFailureLimiter(2, time.Minute, time.Minute) l.Fail("10.0.0.2") l.Reset("10.0.0.2") l.Fail("10.0.0.2") if allowed, _ := l.Allowed("10.0.0.2"); !allowed { t.Fatal("locked out although a success cleared the earlier failure") } } func TestFailureLimiterIsolatesKeys(t *testing.T) { l := NewFailureLimiter(1, time.Minute, time.Minute) l.Fail("10.0.0.3") if allowed, _ := l.Allowed("10.0.0.4"); !allowed { t.Fatal("a different address was locked out") } } // Nach Ablauf des Fensters zählt der Versuch nicht mehr mit – sonst summierten // sich Vertipper über Wochen zu einer Sperre. func TestFailureLimiterWindowExpires(t *testing.T) { l := NewFailureLimiter(2, 10*time.Millisecond, time.Minute) l.Fail("10.0.0.5") time.Sleep(20 * time.Millisecond) l.Fail("10.0.0.5") if allowed, _ := l.Allowed("10.0.0.5"); !allowed { t.Fatal("locked out although the first failure was outside the window") } }