57 lines
2 KiB
Python
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
|