import asyncio import pytest from app.services import strategy_config_service as scs class _Boom: def __init__(self, counter): self.counter = counter async def __aenter__(self): self.counter.append(1) await asyncio.sleep(0.01) raise RuntimeError("db down") async def __aexit__(self, *a): return False @pytest.mark.asyncio async def test_inflight_guard_and_backoff(monkeypatch): calls = [] monkeypatch.setattr(scs, "AsyncSessionLocal", lambda: _Boom(calls)) svc = scs.StrategyConfigService() for _ in range(50): svc.get("X") await asyncio.sleep(0.1) assert len(calls) == 1 for _ in range(50): svc.get("X") await asyncio.sleep(0.05) assert len(calls) == 1 # 실패 후 TTL 내 재시도 없음 assert svc._consecutive_failures == 1 assert svc.get_cache_health_v2()["stale_alarm"] is True @pytest.mark.asyncio async def test_stale_error_log(monkeypatch, caplog): monkeypatch.setattr(scs, "AsyncSessionLocal", lambda: _Boom([])) svc = scs.StrategyConfigService() svc._last_success_ts = scs.time.monotonic() - svc.STALE_ERROR_SEC - 1 with caplog.at_level("ERROR"): await svc._refresh() assert any("낡음" in r.message for r in caplog.records)