Spaces:
Runtime error
Runtime error
| """ | |
| Archivo: test_ratelimit.py | |
| Fecha de modificación: 04/06/2026 | |
| Autor: Equipo AgroVisión | |
| Descripción: | |
| Pruebas unitarias del limitador de tasa (ventana deslizante en memoria) usado como | |
| mitigación de abuso/DDoS de la API. Se inyecta un reloj falso para determinismo. | |
| Ejecución: | |
| uv run python -m pytest tests/unit/test_ratelimit.py | |
| """ | |
| from __future__ import annotations | |
| from backend.core.ratelimit import SlidingWindowRateLimiter | |
| class _FakeClock: | |
| """Reloj controlable para las pruebas (segundos).""" | |
| def __init__(self) -> None: | |
| self.t = 1000.0 | |
| def __call__(self) -> float: | |
| return self.t | |
| def test_permite_hasta_el_maximo_y_luego_bloquea() -> None: | |
| """Admite `max` peticiones en la ventana y rechaza la siguiente.""" | |
| clock = _FakeClock() | |
| rl = SlidingWindowRateLimiter(max_requests=3, window_seconds=60, clock=clock) | |
| assert rl.allow("ip-1") is True | |
| assert rl.allow("ip-1") is True | |
| assert rl.allow("ip-1") is True | |
| assert rl.allow("ip-1") is False # 4ª en la misma ventana → bloqueada | |
| def test_la_ventana_se_desliza() -> None: | |
| """Al avanzar el tiempo más allá de la ventana, vuelve a permitir.""" | |
| clock = _FakeClock() | |
| rl = SlidingWindowRateLimiter(max_requests=2, window_seconds=60, clock=clock) | |
| assert rl.allow("ip-1") is True | |
| assert rl.allow("ip-1") is True | |
| assert rl.allow("ip-1") is False | |
| clock.t += 61 # pasa la ventana | |
| assert rl.allow("ip-1") is True | |
| def test_claves_independientes() -> None: | |
| """Cada clave (IP) tiene su propio cupo.""" | |
| clock = _FakeClock() | |
| rl = SlidingWindowRateLimiter(max_requests=1, window_seconds=60, clock=clock) | |
| assert rl.allow("ip-1") is True | |
| assert rl.allow("ip-2") is True # otra IP no se ve afectada | |
| assert rl.allow("ip-1") is False | |
| def test_max_cero_desactiva_el_limite() -> None: | |
| """`max_requests<=0` desactiva el limitador (siempre permite).""" | |
| rl = SlidingWindowRateLimiter(max_requests=0, window_seconds=60, clock=_FakeClock()) | |
| for _ in range(1000): | |
| assert rl.allow("ip-1") is True | |