import pytest from app.core.exceptions import AppException from app.integrations.models import PlatformSetting from app.intelligence import settings class _Redis: def __init__(self): self.count = 0 async def eval(self, script, key_count, key, window): assert "redis.call('INCR'" in script assert "ttl < 0" in script assert key_count == 1 assert key == "intelligence_read_limit:person_01" assert window == 60 self.count += 1 return self.count async def ttl(self, _key): return 37 @pytest.mark.asyncio async def test_intelligence_reads_have_a_dedicated_configurable_budget( db_session, monkeypatch, ): db_session.add(PlatformSetting( key=settings.SETTING_READS_PER_MINUTE, value=30, )) await db_session.commit() redis = _Redis() monkeypatch.setattr(settings, "get_redis", lambda: redis) for _ in range(30): await settings.apply_intelligence_read_limit( db_session, user_id="person_01", ) with pytest.raises(AppException) as exc_info: await settings.apply_intelligence_read_limit( db_session, user_id="person_01", ) assert exc_info.value.code == "INTELLIGENCE_READ_RATE_LIMITED" assert exc_info.value.status_code == 429 assert exc_info.value.headers == {"Retry-After": "37"} @pytest.mark.asyncio async def test_legacy_over_limit_key_without_ttl_is_bounded_and_self_healed( db_session, monkeypatch, ): db_session.add(PlatformSetting( key=settings.SETTING_READS_PER_MINUTE, value=30, )) await db_session.commit() class _LegacyRedis(_Redis): async def eval(self, script, key_count, key, window): await super().eval(script, key_count, key, window) return 31 async def ttl(self, _key): # Defensive fallback for a Redis replica/race still reporting the # legacy state immediately after the Lua script repaired it. return -1 redis = _LegacyRedis() monkeypatch.setattr(settings, "get_redis", lambda: redis) with pytest.raises(AppException) as exc_info: await settings.apply_intelligence_read_limit( db_session, user_id="person_01", ) assert exc_info.value.headers == {"Retry-After": "60"}