feat(ai): ecosysteme d'outils phase 2 - recherche a cle, cache/retry, Playwright, crawl, Gitea/GitHub, documents (#92)
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""Unit tests for the SQLite web cache (backend.tools.webcache, #92)."""
|
||||
|
||||
import pytest
|
||||
|
||||
from backend.tools import webcache
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def cache_enabled(tmp_path, monkeypatch):
|
||||
"""Enable the cache against an isolated file with a short TTL."""
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_PATH", str(tmp_path / "cache.sqlite3"))
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_TTL", "60")
|
||||
webcache._schema_ready = False
|
||||
yield
|
||||
webcache._schema_ready = False
|
||||
|
||||
|
||||
class TestCacheKey:
|
||||
def test_deterministic_and_payload_sensitive(self):
|
||||
a = webcache.cache_key("search", {"q": "pizza", "page": 1})
|
||||
b = webcache.cache_key("search", {"page": 1, "q": "pizza"})
|
||||
c = webcache.cache_key("search", {"q": "pasta", "page": 1})
|
||||
d = webcache.cache_key("fetch", {"q": "pizza", "page": 1})
|
||||
assert a == b
|
||||
assert a != c
|
||||
assert a != d
|
||||
|
||||
|
||||
class TestCacheRoundTrip:
|
||||
def test_set_get_roundtrip(self, cache_enabled):
|
||||
key = webcache.cache_key("search", {"q": "x"})
|
||||
webcache.cache_set(key, {"results": [1, 2, 3], "provider": "tavily"})
|
||||
assert webcache.cache_get(key) == {"results": [1, 2, 3], "provider": "tavily"}
|
||||
|
||||
def test_miss_returns_none(self, cache_enabled):
|
||||
assert webcache.cache_get("search:unknown") is None
|
||||
|
||||
def test_overwrite_updates_value(self, cache_enabled):
|
||||
key = webcache.cache_key("search", {"q": "x"})
|
||||
webcache.cache_set(key, {"v": 1})
|
||||
webcache.cache_set(key, {"v": 2})
|
||||
assert webcache.cache_get(key) == {"v": 2}
|
||||
|
||||
def test_ttl_expiry(self, tmp_path, monkeypatch):
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_PATH", str(tmp_path / "cache.sqlite3"))
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_TTL", "0.05")
|
||||
webcache._schema_ready = False
|
||||
key = webcache.cache_key("search", {"q": "x"})
|
||||
webcache.cache_set(key, {"v": 1})
|
||||
assert webcache.cache_get(key) == {"v": 1}
|
||||
import time
|
||||
|
||||
time.sleep(0.15)
|
||||
assert webcache.cache_get(key) is None
|
||||
|
||||
def test_disabled_when_ttl_zero(self, cache_enabled, monkeypatch):
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_TTL", "0")
|
||||
key = webcache.cache_key("search", {"q": "x"})
|
||||
webcache.cache_set(key, {"v": 1})
|
||||
assert webcache.cache_get(key) is None
|
||||
|
||||
def test_purge_expired(self, cache_enabled, monkeypatch):
|
||||
key = webcache.cache_key("search", {"q": "x"})
|
||||
webcache.cache_set(key, {"v": 1})
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_TTL", "0.05")
|
||||
import time
|
||||
|
||||
time.sleep(0.15)
|
||||
assert webcache.purge_expired() >= 1
|
||||
assert webcache.cache_get(key) is None
|
||||
|
||||
def test_corrupt_db_degrades_silently(self, tmp_path, monkeypatch):
|
||||
# A directory as cache file breaks sqlite3.connect: the cache must
|
||||
# disable itself instead of breaking the tools.
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_PATH", str(tmp_path))
|
||||
monkeypatch.setenv("OBSIGATE_WEB_CACHE_TTL", "60")
|
||||
webcache._schema_ready = False
|
||||
try:
|
||||
assert webcache.cache_get("search:x") is None
|
||||
webcache.cache_set("search:x", {"v": 1})
|
||||
finally:
|
||||
webcache._schema_ready = False
|
||||
Reference in New Issue
Block a user