from __future__ import annotations from datetime import datetime, timedelta, timezone from types import SimpleNamespace from unittest import TestCase from unittest.mock import MagicMock, patch from govoplan_access.backend.security.api_keys import authenticate_api_key from govoplan_access.backend.security.sessions import authenticate_session_token class AuthenticationActivityTouchTests(TestCase): def test_session_activity_is_touched_only_after_the_interval(self) -> None: now = datetime(2026, 7, 29, 10, 0, tzinfo=timezone.utc) for age_seconds, should_touch in ((60, False), (301, True)): with self.subTest(age_seconds=age_seconds): model = SimpleNamespace( expires_at=now + timedelta(hours=1), last_seen_at=now - timedelta(seconds=age_seconds), ) session = MagicMock() ( session.query.return_value.options.return_value .filter.return_value.one_or_none ).return_value = model with ( patch( "govoplan_access.backend.security.sessions.hash_session_token", return_value="hashed", ), patch( "govoplan_access.backend.security.sessions.utc_now", return_value=now, ), ): result = authenticate_session_token( session, "token", touch_interval_seconds=300, ) self.assertIs(model, result) if should_touch: self.assertEqual(now, model.last_seen_at) session.add.assert_called_once_with(model) else: self.assertEqual( now - timedelta(seconds=age_seconds), model.last_seen_at, ) session.add.assert_not_called() def test_api_key_activity_is_touched_only_after_the_interval(self) -> None: now = datetime(2026, 7, 29, 10, 0, tzinfo=timezone.utc) for age_seconds, should_touch in ((60, False), (301, True)): with self.subTest(age_seconds=age_seconds): model = SimpleNamespace( expires_at=None, last_used_at=now - timedelta(seconds=age_seconds), key_hash="hashed", ) session = MagicMock() ( session.query.return_value.options.return_value .filter.return_value.all ).return_value = [model] with ( patch( "govoplan_access.backend.security.api_keys.verify_api_key", return_value=True, ), patch( "govoplan_access.backend.security.api_keys.utc_now", return_value=now, ), ): result = authenticate_api_key( session, "mm_test-token", touch_interval_seconds=300, ) self.assertIs(model, result) if should_touch: self.assertEqual(now, model.last_used_at) session.add.assert_called_once_with(model) else: self.assertEqual( now - timedelta(seconds=age_seconds), model.last_used_at, ) session.add.assert_not_called() if __name__ == "__main__": import unittest unittest.main()