提交
This commit is contained in:
48
backend/tests/test_auth_rate_limit.py
Normal file
48
backend/tests/test_auth_rate_limit.py
Normal file
@@ -0,0 +1,48 @@
|
||||
"""登录 IP 限速(auth_api._login_rate_limited):窗口内超限拦截、过期滑出、独立 IP 隔离。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
import app.auth_api as auth_api
|
||||
from app.auth_api import _LOGIN_MAX_PER_WINDOW, _LOGIN_WINDOW, _login_attempts, _login_rate_limited
|
||||
|
||||
|
||||
class _FakeClock:
|
||||
"""替换 auth_api 命名空间里的 time(不影响全局 time 模块)。"""
|
||||
|
||||
def __init__(self):
|
||||
self.now = 1000.0
|
||||
|
||||
def monotonic(self) -> float:
|
||||
return self.now
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def clock(monkeypatch):
|
||||
c = _FakeClock()
|
||||
monkeypatch.setattr(auth_api, "time", c)
|
||||
_login_attempts.clear()
|
||||
yield c
|
||||
_login_attempts.clear()
|
||||
|
||||
|
||||
def test_under_limit_passes(clock):
|
||||
for _ in range(_LOGIN_MAX_PER_WINDOW):
|
||||
assert _login_rate_limited("1.2.3.4") is False
|
||||
assert _login_rate_limited("1.2.3.4") is True # 第 16 次被拦
|
||||
|
||||
|
||||
def test_window_slides(clock):
|
||||
for _ in range(_LOGIN_MAX_PER_WINDOW):
|
||||
_login_rate_limited("1.2.3.4")
|
||||
assert _login_rate_limited("1.2.3.4") is True
|
||||
# 窗口滑过:最早的尝试过期出窗,重新放行
|
||||
clock.now += _LOGIN_WINDOW + 0.1
|
||||
assert _login_rate_limited("1.2.3.4") is False
|
||||
|
||||
|
||||
def test_ips_isolated(clock):
|
||||
for _ in range(_LOGIN_MAX_PER_WINDOW):
|
||||
_login_rate_limited("1.1.1.1")
|
||||
assert _login_rate_limited("1.1.1.1") is True
|
||||
assert _login_rate_limited("2.2.2.2") is False # 另一 IP 不受牵连
|
||||
Reference in New Issue
Block a user