gateway/tests/test_service_redmine_stats_cache.py
2026-04-26 08:31:35 +02:00

57 lines
2 KiB
Python

# Copyright (c) 2026 Patrick Motsch
# All rights reserved.
"""Unit tests for ``RedmineStatsCache``.
Verifies TTL expiry, key composition, instance invalidation and process-wide
singleton behaviour.
"""
from __future__ import annotations
import time
from modules.features.redmine.serviceRedmineStatsCache import (
RedmineStatsCache,
getStatsCache,
)
class TestRedmineStatsCache:
def test_getReturnsNoneOnMiss(self) -> None:
c = RedmineStatsCache(ttlSeconds=60)
key = c.buildKey("inst-a", "2026-01-01", "2026-01-31", "week", [1, 2])
assert c.get(key) is None
def test_setAndGetRoundTrip(self) -> None:
c = RedmineStatsCache(ttlSeconds=60)
key = c.buildKey("inst-a", None, None, "week", [])
c.set(key, {"answer": 42})
assert c.get(key) == {"answer": 42}
def test_keyIsOrderInsensitiveForTrackerIds(self) -> None:
c = RedmineStatsCache()
k1 = c.buildKey("inst-a", None, None, "week", [3, 1, 2])
k2 = c.buildKey("inst-a", None, None, "week", [1, 2, 3])
assert k1 == k2
def test_ttlExpiry(self) -> None:
c = RedmineStatsCache(ttlSeconds=0.05)
key = c.buildKey("inst-a", None, None, "week", [])
c.set(key, "value")
time.sleep(0.06)
assert c.get(key) is None
def test_invalidateInstanceDropsAllKeysForThatInstance(self) -> None:
c = RedmineStatsCache(ttlSeconds=60)
c.set(c.buildKey("inst-a", None, None, "week", []), "v1")
c.set(c.buildKey("inst-a", "2026-01-01", "2026-01-31", "month", [1]), "v2")
c.set(c.buildKey("inst-b", None, None, "week", []), "v3")
dropped = c.invalidateInstance("inst-a")
assert dropped == 2
assert c.get(c.buildKey("inst-a", None, None, "week", [])) is None
assert c.get(c.buildKey("inst-b", None, None, "week", [])) == "v3"
def test_singletonIsStable(self) -> None:
a = getStatsCache()
b = getStatsCache()
assert a is b