Skip to content
30 changes: 30 additions & 0 deletions tests/trestle/core/remote/cache_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# limitations under the License.
"""Testing for cache functionality."""

import datetime
import getpass
import pathlib
import random
Expand Down Expand Up @@ -68,6 +69,35 @@ def get_catalog_fetcher(
return fetcher, catalog_data


def test_time_since_modification_uses_utc(monkeypatch: MonkeyPatch) -> None:
"""Test cache age calculation uses UTC-aware datetimes."""

class _StatResult:
st_mtime = 1234.5

class _FakePath:
def stat(self) -> _StatResult:
return _StatResult()

expected_last_mod = datetime.datetime(2026, 3, 15, 11, 0, 0, tzinfo=datetime.timezone.utc)
expected_now = datetime.datetime(2026, 3, 15, 12, 30, 0, tzinfo=datetime.timezone.utc)

class _FakeDateTime:
@classmethod
def fromtimestamp(cls, ts: float, tz: datetime.tzinfo | None = None) -> datetime.datetime:
assert ts == _StatResult.st_mtime
assert tz == datetime.timezone.utc
return expected_last_mod

@classmethod
def now(cls, tz: datetime.tzinfo | None = None) -> datetime.datetime:
assert tz == datetime.timezone.utc
return expected_now

monkeypatch.setattr(cache.datetime, 'datetime', _FakeDateTime)
assert cache.FetcherBase._time_since_modification(_FakePath()) == datetime.timedelta(hours=1, minutes=30)


def test_fetcher_oscal(tmp_trestle_dir: pathlib.Path) -> None:
"""Test whether fetcher can get an object from the cache as an oscal model."""
fetcher, catalog_data = get_catalog_fetcher(tmp_trestle_dir)
Expand Down
4 changes: 2 additions & 2 deletions trestle/core/remote/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ def __init__(self, trestle_root: pathlib.Path, uri: str) -> None:
@staticmethod
def _time_since_modification(file_path: pathlib.Path) -> datetime.timedelta:
"""Get time since last modification."""
last_modification = datetime.datetime.fromtimestamp(file_path.stat().st_mtime)
return datetime.datetime.now() - last_modification
last_modification = datetime.datetime.fromtimestamp(file_path.stat().st_mtime, tz=datetime.timezone.utc)
return datetime.datetime.now(datetime.timezone.utc) - last_modification

@abstractmethod
def _do_fetch(self) -> None:
Expand Down
Loading