112 lines
2.9 KiB
Python
112 lines
2.9 KiB
Python
from datetime import UTC, datetime
|
|
|
|
import pytest
|
|
|
|
from src.services.operator_summary_cache import (
|
|
clear_operator_summary_cache,
|
|
get_cached_operator_summary_async,
|
|
get_cached_operator_summary,
|
|
store_operator_summary_async,
|
|
store_operator_summary,
|
|
)
|
|
|
|
|
|
class _FakeRedis:
|
|
def __init__(self) -> None:
|
|
self.values: dict[str, str] = {}
|
|
self.expirations: dict[str, int] = {}
|
|
|
|
async def get(self, key: str) -> str | None:
|
|
return self.values.get(key)
|
|
|
|
async def set(self, key: str, value: str, ex: int) -> bool:
|
|
self.values[key] = value
|
|
self.expirations[key] = ex
|
|
return True
|
|
|
|
async def delete(self, key: str) -> int:
|
|
return 1 if self.values.pop(key, None) is not None else 0
|
|
|
|
|
|
def test_operator_summary_cache_returns_copy_with_hit_metadata() -> None:
|
|
clear_operator_summary_cache()
|
|
key = {"project_id": "awoooi", "limit": 30}
|
|
stored = store_operator_summary(
|
|
"truth_chain_quality_summary",
|
|
key,
|
|
{"evaluated_total": 30, "nested": {"ok": True}},
|
|
ttl_seconds=30,
|
|
now_monotonic=100.0,
|
|
now_utc=datetime(2026, 6, 1, tzinfo=UTC),
|
|
)
|
|
|
|
assert stored["cache"]["status"] == "miss"
|
|
stored["nested"]["ok"] = False
|
|
|
|
cached = get_cached_operator_summary(
|
|
"truth_chain_quality_summary",
|
|
key,
|
|
ttl_seconds=30,
|
|
now_monotonic=105.5,
|
|
)
|
|
|
|
assert cached is not None
|
|
assert cached["cache"]["status"] == "hit"
|
|
assert cached["cache"]["age_seconds"] == 5.5
|
|
assert cached["nested"]["ok"] is True
|
|
|
|
|
|
def test_operator_summary_cache_expires_by_ttl() -> None:
|
|
clear_operator_summary_cache()
|
|
key = {"project_id": "awoooi", "page": 1}
|
|
store_operator_summary(
|
|
"callback_replies",
|
|
key,
|
|
{"total": 4},
|
|
ttl_seconds=20,
|
|
now_monotonic=200.0,
|
|
now_utc=datetime(2026, 6, 1, tzinfo=UTC),
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_operator_summary_cache_uses_shared_redis(monkeypatch) -> None:
|
|
clear_operator_summary_cache()
|
|
fake_redis = _FakeRedis()
|
|
monkeypatch.setattr("src.core.redis_client.get_redis", lambda: fake_redis)
|
|
key = {"project_id": "awoooi", "per_page": 1}
|
|
|
|
stored = await store_operator_summary_async(
|
|
"callback_replies",
|
|
key,
|
|
{"total": 4, "items": []},
|
|
ttl_seconds=20,
|
|
now_monotonic=300.0,
|
|
now_utc=datetime(2026, 6, 1, tzinfo=UTC),
|
|
)
|
|
|
|
assert stored["cache"]["status"] == "miss"
|
|
assert fake_redis.values
|
|
|
|
clear_operator_summary_cache()
|
|
cached = await get_cached_operator_summary_async(
|
|
"callback_replies",
|
|
key,
|
|
ttl_seconds=20,
|
|
now_monotonic=302.0,
|
|
)
|
|
|
|
assert cached is not None
|
|
assert cached["cache"]["status"] == "hit"
|
|
assert cached["total"] == 4
|
|
|
|
assert (
|
|
get_cached_operator_summary(
|
|
"callback_replies",
|
|
key,
|
|
ttl_seconds=20,
|
|
now_monotonic=220.0,
|
|
)
|
|
is None
|
|
)
|