import json import os import sys import tempfile import time from unittest.mock import MagicMock, patch import pytest sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) from cache_manager import CacheManager class TestCacheManager: @pytest.fixture def tmp_cache_dir(self): with tempfile.TemporaryDirectory() as tmpdir: yield tmpdir @pytest.fixture def manager(self, tmp_cache_dir): return CacheManager(tmp_cache_dir) def test_read_cache_missing_returns_none(self, manager): result = manager.read_cache("nonexistent") assert result is None def test_write_and_read_cache_roundtrip(self, manager): data = {"hash": "abc123", "name": "Test Model", "triggerWords": ["style"]} manager.write_cache("abc123", data) result = manager.read_cache("abc123") assert result == data def test_read_corrupted_cache_auto_deletes(self, manager): cache_path = os.path.join(manager.cache_dir, "bad.json") os.makedirs(manager.cache_dir, exist_ok=True) with open(cache_path, "w") as f: f.write("not json{") result = manager.read_cache("bad") assert result is None assert not os.path.exists(cache_path) def test_is_stale_expired(self, manager): old_time = time.time() - (8 * 24 * 3600) # 8 days ago data = {"fetched_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(old_time))} assert manager.is_stale(data) is True def test_is_stale_fresh(self, manager): recent_time = time.time() - (1 * 24 * 3600) # 1 day ago data = {"fetched_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(recent_time))} assert manager.is_stale(data) is False def test_is_stale_no_fetched_at(self, manager): data = {"name": "No timestamp"} assert manager.is_stale(data) is True def test_is_stale_naive_datetime(self, manager): old_time = time.time() - (8 * 24 * 3600) data = {"fetched_at": time.strftime("%Y-%m-%dT%H:%M:%S", time.gmtime(old_time))} assert manager.is_stale(data) is True def test_clear_cache_deletes_files(self, manager): data = {"hash": "xyz"} manager.write_cache("xyz", data) manager.clear_cache("xyz") assert manager.read_cache("xyz") is None def test_get_image_path(self, manager): path = manager.get_image_path("abc123", 0) assert path.endswith("abc123/preview_0.jpg") assert os.path.dirname(path).endswith("abc123") def test_clear_cache_deletes_images(self, manager): data = {"hash": "xyz"} manager.write_cache("xyz", data) # Create a fake image file in the image dir img_dir = os.path.join(manager.cache_dir, "xyz") os.makedirs(img_dir, exist_ok=True) img_path = os.path.join(img_dir, "preview_0.jpg") with open(img_path, "w") as f: f.write("fake image") manager.clear_cache("xyz") assert manager.read_cache("xyz") is None assert not os.path.exists(img_path) assert not os.path.exists(img_dir) def test_get_cache_for_file_sync_uses_hash(self, manager): mock_hash_fn = MagicMock(return_value="mockhash") with patch("cache_manager._import_compute_file_hash_sync", return_value=mock_hash_fn): with patch.object(manager, "read_cache", return_value={"name": "Cached", "hash": "existing"}): result = manager.get_cache_for_file_sync("/fake/path/lora.safetensors") assert result == {"name": "Cached", "hash": "existing"} def test_get_cache_for_file_sync_injects_hash(self, manager): mock_hash_fn = MagicMock(return_value="injected") with patch("cache_manager._import_compute_file_hash_sync", return_value=mock_hash_fn): with patch.object(manager, "read_cache", return_value={"name": "Cached"}): result = manager.get_cache_for_file_sync("/fake/path/lora.safetensors") assert result["hash"] == "injected" def test_get_cache_for_file_sync_file_not_found(self, manager): mock_hash_fn = MagicMock(side_effect=FileNotFoundError()) with patch("cache_manager._import_compute_file_hash_sync", return_value=mock_hash_fn): result = manager.get_cache_for_file_sync("/missing/file.safetensors") assert result is None