from __future__ import annotations import time from yuxi.channels.adapters.nextcloudtalk.webhook_server import _AuthRateLimiter class TestAuthRateLimiter: def test_initial_state_allows_access(self): limiter = _AuthRateLimiter(max_requests=3, window_s=60, lockout_s=300) assert limiter.check("192.168.1.1") is True def test_after_max_failures_blocks(self): limiter = _AuthRateLimiter(max_requests=3, window_s=60, lockout_s=5) for _ in range(3): limiter.record_failure("192.168.1.1") assert limiter.check("192.168.1.1") is False def test_lockout_reattempt(self): limiter = _AuthRateLimiter(max_requests=2, window_s=60, lockout_s=1) for _ in range(2): limiter.record_failure("10.0.0.1") assert limiter.check("10.0.0.1") is False time.sleep(1.1) assert limiter.check("10.0.0.1") is False def test_different_ips_independent(self): limiter = _AuthRateLimiter(max_requests=2, window_s=60, lockout_s=5) for _ in range(2): limiter.record_failure("10.0.0.1") assert limiter.check("10.0.0.1") is False assert limiter.check("10.0.0.2") is True def test_stats(self): limiter = _AuthRateLimiter(max_requests=3, window_s=60, lockout_s=5) limiter.record_failure("10.0.0.1") stats = limiter.stats() assert stats["tracked_ips"] == 1 assert stats["locked_ips"] == 0 def test_stats_after_lockout(self): limiter = _AuthRateLimiter(max_requests=2, window_s=60, lockout_s=5) for _ in range(2): limiter.record_failure("10.0.0.1") limiter.check("10.0.0.1") stats = limiter.stats() assert stats["locked_ips"] == 1 def test_gc_cleans_expired_lockouts(self): limiter = _AuthRateLimiter(max_requests=2, window_s=60, lockout_s=1) for _ in range(2): limiter.record_failure("10.0.0.1") limiter.check("10.0.0.1") time.sleep(1.1) stats = limiter.stats() assert stats["locked_ips"] == 0 def test_gc_cleans_expired_failures(self): limiter = _AuthRateLimiter(max_requests=3, window_s=1, lockout_s=5) limiter.record_failure("10.0.0.1") time.sleep(1.1) limiter.check("10.0.0.1") stats = limiter.stats() assert stats["tracked_ips"] == 0 def test_multiple_failures_in_window(self): limiter = _AuthRateLimiter(max_requests=5, window_s=60, lockout_s=5) for _ in range(4): limiter.record_failure("10.0.0.1") assert limiter.check("10.0.0.1") is True def test_record_failure_timestamps(self): limiter = _AuthRateLimiter(max_requests=3, window_s=60, lockout_s=5) limiter.record_failure("10.0.0.1") time.sleep(0.01) limiter.record_failure("10.0.0.1") limiter.record_failure("10.0.0.1") assert limiter.check("10.0.0.1") is False