"""Tests for the daily cache layer.""" from __future__ import annotations import tempfile import time import unittest from pathlib import Path from app import daily_cache class DailyCacheTest(unittest.TestCase): def setUp(self) -> None: self._tmp = tempfile.mkdtemp(prefix="cachemain_") self.cache = daily_cache.DailyCache(cache_dir=Path(self._tmp), ttl=0.5) def tearDown(self) -> None: import shutil shutil.rmtree(self._tmp, ignore_errors=True) def test_set_get_roundtrip(self) -> None: self.cache.set("tourism/2026-08-25", {"value": 123, "as_of": "2026-08"}) got = self.cache.get("tourism/2026-08-25") self.assertIsNotNone(got) self.assertEqual(got["value"], 123) def test_missing_key_returns_none(self) -> None: self.assertIsNone(self.cache.get("nope")) def test_fresh_after_set(self) -> None: self.cache.set("k", {"a": 1}) self.assertTrue(self.cache.fresh("k")) def test_expired_not_fresh(self) -> None: self.cache.set("k", {"a": 1}) time.sleep(0.7) self.assertFalse(self.cache.fresh("k")) def test_fetch_or_stale_caches_value(self) -> None: calls = {"n": 0} def fetcher(): calls["n"] += 1 return {"value": 42} v1 = self.cache.fetch_or_stale("k", fetcher) self.assertEqual(v1["value"], 42) self.assertEqual(calls["n"], 1) # second call within TTL -> cached, fetcher not re-invoked v2 = self.cache.fetch_or_stale("k", fetcher) self.assertIsNotNone(v2) self.assertEqual(v2["value"], 42) self.assertEqual(calls["n"], 1) def test_fetch_or_stale_falls_back_on_error(self) -> None: self.cache.set("k", {"value": 99}) def broken(): raise RuntimeError("network down") # expired cache so it tries to refetch time.sleep(0.7) v = self.cache.fetch_or_stale("k", broken) self.assertEqual(v["value"], 99) self.assertTrue(v.get("_stale")) def test_reload_persists(self) -> None: self.cache.set("k", {"x": 1}) cache2 = daily_cache.DailyCache(cache_dir=Path(self._tmp), ttl=0.5) self.assertEqual(cache2.get("k")["x"], 1) if __name__ == "__main__": unittest.main()