dify/api/tests/unit_tests/libs/test_rate_limiter.py
QuantumGhost 03e3acfc71
feat(api): Human Input Node (backend part) (#31646)
The backend part of the human in the loop (HITL) feature and relevant architecture / workflow engine changes.

Signed-off-by: yihong0618 <zouzou0208@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: -LAN- <laipz8200@outlook.com>
Co-authored-by: 盐粒 Yanli <yanli@dify.ai>
Co-authored-by: CrabSAMA <40541269+CrabSAMA@users.noreply.github.com>
Co-authored-by: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: yihong <zouzou0208@gmail.com>
Co-authored-by: Joel <iamjoel007@gmail.com>
2026-01-30 10:18:49 +08:00

69 lines
2.2 KiB
Python

from unittest.mock import MagicMock
from libs import helper as helper_module
class _FakeRedis:
def __init__(self) -> None:
self._zsets: dict[str, dict[str, float]] = {}
self._expiry: dict[str, int] = {}
def zadd(self, key: str, mapping: dict[str, float]) -> int:
zset = self._zsets.setdefault(key, {})
for member, score in mapping.items():
zset[str(member)] = float(score)
return len(mapping)
def zremrangebyscore(self, key: str, min_score: str | float, max_score: str | float) -> int:
zset = self._zsets.get(key, {})
min_value = float("-inf") if min_score == "-inf" else float(min_score)
max_value = float("inf") if max_score == "+inf" else float(max_score)
to_delete = [member for member, score in zset.items() if min_value <= score <= max_value]
for member in to_delete:
del zset[member]
return len(to_delete)
def zcard(self, key: str) -> int:
return len(self._zsets.get(key, {}))
def expire(self, key: str, ttl: int) -> bool:
self._expiry[key] = ttl
return True
def test_rate_limiter_counts_attempts_within_same_second(monkeypatch):
fake_redis = _FakeRedis()
monkeypatch.setattr(helper_module.time, "time", lambda: 1000)
limiter = helper_module.RateLimiter(
prefix="test_rate_limit",
max_attempts=2,
time_window=60,
redis_client=fake_redis,
)
limiter.increment_rate_limit("203.0.113.10")
limiter.increment_rate_limit("203.0.113.10")
assert limiter.is_rate_limited("203.0.113.10") is True
def test_rate_limiter_uses_injected_redis(monkeypatch):
redis_client = MagicMock()
redis_client.zcard.return_value = 1
monkeypatch.setattr(helper_module.time, "time", lambda: 1000)
limiter = helper_module.RateLimiter(
prefix="test_rate_limit",
max_attempts=1,
time_window=60,
redis_client=redis_client,
)
limiter.increment_rate_limit("203.0.113.10")
limiter.is_rate_limited("203.0.113.10")
assert redis_client.zadd.called is True
assert redis_client.zremrangebyscore.called is True
assert redis_client.zcard.called is True