ForcePilot/backend/test/unit/channel/routing/test_cache.py
Kris bab30f2715
Some checks failed
Deploy VitePress site to Pages / build (push) Has been cancelled
Ruff Format Check / Ruff Format & Lint (push) Has been cancelled
Deploy VitePress site to Pages / Deploy (push) Has been cancelled
feat:0715
2026-07-15 12:30:58 +08:00

117 lines
4.0 KiB
Python

from __future__ import annotations
import asyncio
import time
from yuxi.channel.routing.cache import RouteCache, get_default_route_cache
class TestRouteCache:
async def test_get_returns_none_for_missing_key(self):
cache = RouteCache()
assert await cache.get("missing") is None
async def test_set_and_get(self):
cache = RouteCache()
await cache.set("key", "value")
assert await cache.get("key") == "value"
async def test_get_moves_entry_to_end(self):
cache = RouteCache(maxsize=2)
await cache.set("a", 1)
await cache.set("b", 2)
await cache.get("a")
await cache.set("c", 3)
assert await cache.get("a") == 1
assert await cache.get("b") is None
assert await cache.get("c") == 3
async def test_expired_entry_is_removed(self):
cache = RouteCache(ttl_seconds=0.01)
await cache.set("key", "value")
await asyncio.sleep(0.02)
assert await cache.get("key") is None
async def test_set_updates_existing_key(self):
cache = RouteCache()
await cache.set("key", "old")
await cache.set("key", "new")
assert await cache.get("key") == "new"
async def test_maxsize_evicts_oldest(self):
cache = RouteCache(maxsize=2)
await cache.set("a", 1)
await cache.set("b", 2)
await cache.set("c", 3)
assert await cache.get("a") is None
assert await cache.get("b") == 2
assert await cache.get("c") == 3
async def test_maxsize_at_least_one(self):
cache = RouteCache(maxsize=0)
await cache.set("a", 1)
await cache.set("b", 2)
assert await cache.get("a") is None
assert await cache.get("b") == 2
async def test_clear_removes_all(self):
cache = RouteCache()
await cache.set("a", 1)
await cache.set("b", 2)
await cache.clear()
assert await cache.get("a") is None
assert await cache.get("b") is None
async def test_invalidate_by_channel(self):
cache = RouteCache()
await cache.set("feishu:acc1:dm:user1", 1)
await cache.set("feishu:acc1:dm:user2", 2)
await cache.set("slack:acc1:dm:user1", 3)
removed = await cache.invalidate_by_channel("feishu")
assert removed == 2
assert await cache.get("feishu:acc1:dm:user1") is None
assert await cache.get("slack:acc1:dm:user1") == 3
async def test_invalidate_by_account(self):
cache = RouteCache()
await cache.set("feishu:acc1:dm:user1", 1)
await cache.set("feishu:acc2:dm:user1", 2)
await cache.set("feishu:acc1:group:g1", 3)
removed = await cache.invalidate_by_account("feishu", "acc1")
assert removed == 2
assert await cache.get("feishu:acc1:dm:user1") is None
assert await cache.get("feishu:acc2:dm:user1") == 2
async def test_concurrent_access_does_not_raise(self):
cache = RouteCache()
async def worker(idx: int) -> None:
for i in range(20):
await cache.set(f"key-{idx}-{i}", i)
await cache.get(f"key-{idx}-{i}")
await asyncio.gather(*[worker(i) for i in range(5)])
async def test_custom_ttl_is_used(self, monkeypatch):
cache = RouteCache(ttl_seconds=10)
now = time.time()
monkeypatch.setattr(time, "time", lambda: now)
await cache.set("key", "value")
monkeypatch.setattr(time, "time", lambda: now + 5)
assert await cache.get("key") == "value"
monkeypatch.setattr(time, "time", lambda: now + 11)
assert await cache.get("key") is None
class TestDefaultRouteCache:
def test_returns_same_instance(self):
first = get_default_route_cache()
second = get_default_route_cache()
assert first is second
assert isinstance(first, RouteCache)
def test_global_instance_has_expected_defaults(self):
cache = get_default_route_cache()
assert cache.maxsize == 4000
assert cache.ttl == 60