package admin import ( "testing" "time" ) func TestRestoreAttemptLimiterBlocksAfterMaxFailures(t *testing.T) { limiter := newRestoreAttemptLimiter(2, time.Minute) now := time.Unix(1700000000, 0) if limited, _ := limiter.allow(1, now); !limited { t.Fatalf("first attempt should be allowed") } limiter.recordFailure(1, now) if limited, _ := limiter.allow(1, now.Add(time.Second)); !limited { t.Fatalf("second attempt should still be allowed") } limiter.recordFailure(1, now.Add(2*time.Second)) allowed, retryAfter := limiter.allow(1, now.Add(3*time.Second)) if allowed { t.Fatal("limiter should block after hitting max failures") } if retryAfter <= 0 { t.Fatalf("retryAfter should be positive, got %v", retryAfter) } } func TestRestoreAttemptLimiterResetsAfterSuccess(t *testing.T) { limiter := newRestoreAttemptLimiter(2, time.Minute) now := time.Unix(1700000000, 0) limiter.recordFailure(1, now) limiter.recordSuccess(1) allowed, retryAfter := limiter.allow(1, now.Add(time.Second)) if !allowed { t.Fatalf("limiter should reset after success, retryAfter=%v", retryAfter) } } func TestRestoreAttemptLimiterExpiresBlockWindow(t *testing.T) { limiter := newRestoreAttemptLimiter(1, time.Minute) now := time.Unix(1700000000, 0) limiter.recordFailure(1, now) allowed, _ := limiter.allow(1, now.Add(61*time.Second)) if !allowed { t.Fatal("limiter should allow attempts after block window expires") } }