Added test_hits_expire_after_window_elapses() which uses unittest.mock.patch to deterministically advance time and verify that expired hits are evicted from the rolling window. This exercises the while loop in RateLimiter.allow() that was previously untested. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013PphXq1s43DNRj1uWKGXof
32 lines
1.1 KiB
Python
32 lines
1.1 KiB
Python
from unittest.mock import patch
|
|
|
|
from app.rate_limit import RateLimiter
|
|
|
|
|
|
def test_allows_up_to_limit_then_blocks():
|
|
limiter = RateLimiter(max_requests=3, window_seconds=60)
|
|
assert limiter.allow("user-1") is True
|
|
assert limiter.allow("user-1") is True
|
|
assert limiter.allow("user-1") is True
|
|
assert limiter.allow("user-1") is False
|
|
|
|
|
|
def test_different_keys_tracked_independently():
|
|
limiter = RateLimiter(max_requests=1, window_seconds=60)
|
|
assert limiter.allow("user-1") is True
|
|
assert limiter.allow("user-2") is True
|
|
assert limiter.allow("user-1") is False
|
|
|
|
|
|
def test_hits_expire_after_window_elapses():
|
|
limiter = RateLimiter(max_requests=2, window_seconds=10)
|
|
|
|
with patch("app.rate_limit.time.monotonic", return_value=100.0):
|
|
assert limiter.allow("user-1") is True
|
|
assert limiter.allow("user-1") is True
|
|
assert limiter.allow("user-1") is False # at limit
|
|
|
|
with patch("app.rate_limit.time.monotonic", return_value=111.0):
|
|
# 11 seconds later, both prior hits (at t=100) are older than window_start (111 - 10 = 101)
|
|
assert limiter.allow("user-1") is True
|