Spaces:
Sleeping
Sleeping
| from __future__ import annotations | |
| import json | |
| from pathlib import Path | |
| import pytest | |
| from PIL import Image | |
| from ai_agent.utils import previews | |
| from ai_agent.utils import cache_db | |
| from ai_agent.utils.cache_db import CacheDB, reset_cache_db | |
| def _isolated_cache_db(): | |
| """Give every test a fresh in-memory SQLite cache.""" | |
| db = CacheDB(":memory:") | |
| reset_cache_db(db) | |
| yield | |
| reset_cache_db(None) | |
| def test_preview_cache_roundtrip_hit(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): | |
| key = ("/tmp/example.png::1::1",) | |
| preview_file = tmp_path / "preview.png" | |
| preview_file.write_bytes(b"x") | |
| monkeypatch.setattr(previews, "PREVIEW_CACHE_TTL_SECONDS", 30) | |
| previews._preview_cache_set(key, str(preview_file), "meta") | |
| out_path, out_meta = previews._preview_cache_get(key) | |
| assert out_path == str(preview_file) | |
| assert out_meta == "meta" | |
| def test_preview_cache_evicts_expired_entries( | |
| tmp_path: Path, monkeypatch: pytest.MonkeyPatch | |
| ): | |
| key = ("/tmp/expired.png::1::1",) | |
| preview_file = tmp_path / "expired.png" | |
| preview_file.write_bytes(b"x") | |
| now = {"t": 1_000_000.0} | |
| monkeypatch.setattr(cache_db.time, "time", lambda: now["t"]) | |
| monkeypatch.setattr(previews, "PREVIEW_CACHE_TTL_SECONDS", 5) | |
| previews._preview_cache_set(key, str(preview_file), "meta") | |
| now["t"] = 1_000_006.0 # past TTL | |
| out_path, out_meta = previews._preview_cache_get(key) | |
| assert out_path is None | |
| assert out_meta is None | |
| def test_preview_cache_drops_missing_file_entry(monkeypatch: pytest.MonkeyPatch): | |
| key = ("/tmp/missing.png::1::1",) | |
| monkeypatch.setattr(previews, "PREVIEW_CACHE_TTL_SECONDS", 3000) | |
| # Manually insert an entry pointing to a non-existent file | |
| db_key = json.dumps(key) | |
| value = json.dumps({"path": "/tmp/does-not-exist.png", "meta": "meta"}) | |
| cache_db.get_cache_db().set( | |
| previews._PREVIEW_NS, db_key, value, ttl_seconds=3000 | |
| ) | |
| out_path, out_meta = previews._preview_cache_get(key) | |
| assert out_path is None | |
| assert out_meta is None | |
| def test_preview_cache_capacity_eviction(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): | |
| monkeypatch.setattr(previews, "PREVIEW_CACHE_TTL_SECONDS", 100) | |
| monkeypatch.setattr(previews, "PREVIEW_CACHE_MAX_ENTRIES", 2) | |
| now = {"t": 1_000_000.0} | |
| monkeypatch.setattr(cache_db.time, "time", lambda: now["t"]) | |
| a = tmp_path / "a.png" | |
| b = tmp_path / "b.png" | |
| c = tmp_path / "c.png" | |
| a.write_bytes(b"a") | |
| b.write_bytes(b"b") | |
| c.write_bytes(b"c") | |
| key_a = ("a",) | |
| key_b = ("b",) | |
| key_c = ("c",) | |
| now["t"] = 1_000_001.0 | |
| previews._preview_cache_set(key_a, str(a), "a") | |
| now["t"] = 1_000_002.0 | |
| previews._preview_cache_set(key_b, str(b), "b") | |
| now["t"] = 1_000_003.0 | |
| previews._preview_cache_set(key_c, str(c), "c") | |
| # key_a should have been evicted (oldest-accessed, capacity=2) | |
| assert previews._preview_cache_get(key_a) == (None, None) | |
| assert previews._preview_cache_get(key_b)[0] == str(b) | |
| assert previews._preview_cache_get(key_c)[0] == str(c) | |
| def test_preview_cache_clear_helper_empties_cache(tmp_path: Path, monkeypatch: pytest.MonkeyPatch): | |
| monkeypatch.setattr(previews, "PREVIEW_CACHE_TTL_SECONDS", 30) | |
| preview_file = tmp_path / "x.png" | |
| preview_file.write_bytes(b"x") | |
| previews._preview_cache_set(("x",), str(preview_file), "meta") | |
| previews._clear_preview_cache_for_tests() | |
| assert previews._preview_cache_get(("x",)) == (None, None) | |
| def test_resize_for_preview_preserves_aspect_ratio(): | |
| img = Image.new("L", (2000, 1000), color=128) | |
| resized = previews._resize_for_preview(img, max_side_px=500) | |
| assert resized.size == (500, 250) | |
| def test_resize_for_preview_does_not_upscale(): | |
| img = Image.new("RGB", (320, 200), color=(0, 0, 0)) | |
| resized = previews._resize_for_preview(img, max_side_px=500) | |
| assert resized.size == (320, 200) |