import datetime from unittest import mock import pytest from aiocache.backends.memory import SimpleMemoryCache from aiocache.base import BaseCache as AsyncCache from cachelib import BaseCache as Cache, SimpleCache from fansifter_common.adapters.aws.secretsmanager import SecretsManager from fansifter_common.m2m_token import ( AsyncM2MTokenManager, M2MToken, M2MTokenManager, ) from fansifter_common.utils import timezone @pytest.fixture def secrets_manager_mock() -> mock.MagicMock: return mock.MagicMock(spec=SecretsManager) @pytest.fixture def cache() -> Cache: return SimpleCache() @pytest.fixture def async_cache() -> AsyncCache: return SimpleMemoryCache() @pytest.fixture def m2m_token_manager( secrets_manager_mock: mock.MagicMock, cache: Cache ) -> M2MTokenManager: return M2MTokenManager( secrets_manager=secrets_manager_mock, secret_name_key="key", secret_expire_name_key="expire", cache=cache, ) @pytest.fixture def async_m2m_token_manager( secrets_manager_mock: mock.MagicMock, async_cache: AsyncCache ) -> AsyncM2MTokenManager: return AsyncM2MTokenManager( secrets_manager=secrets_manager_mock, secret_name_key="key", secret_expire_name_key="expire", cache=async_cache, ) def test_m2m_token_manager_get_token_string( m2m_token_manager: M2MTokenManager, secrets_manager_mock: mock.MagicMock ) -> None: token_string = "test123123" secrets_manager_mock.get_secret.side_effect = [ token_string, datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d %H:%M:%S.%f"), ] assert m2m_token_manager.get_token_string() == token_string def test_m2m_token_manager_get_token_string_naive( m2m_token_manager: M2MTokenManager, secrets_manager_mock: mock.MagicMock ) -> None: token_string = "test123123" secrets_manager_mock.get_secret.side_effect = [ token_string, datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), ] assert m2m_token_manager.get_token_string() == token_string def test_m2m_token_manager_get_token_string_cached( m2m_token_manager: M2MTokenManager, cache: Cache, secrets_manager_mock: mock.MagicMock, ) -> None: token_string = "test123123" expires_at = timezone.now() + datetime.timedelta(hours=10) token = M2MToken(token_string=token_string, expires_at=expires_at) cache.set(M2MTokenManager.cache_key, value=token) assert m2m_token_manager.get_token_string() == token_string secrets_manager_mock.get_secret.assert_not_called() def test_m2m_token_manager_get_token_string_cached_expired( m2m_token_manager: M2MTokenManager, cache: Cache, secrets_manager_mock: mock.MagicMock, ) -> None: old_token_string = "old-token" old_expires_at = timezone.now() - datetime.timedelta(days=100) token = M2MToken(token_string=old_token_string, expires_at=old_expires_at) cache.set(M2MTokenManager.cache_key, value=token) new_token_string = "new-token" new_expires_at = timezone.now() + datetime.timedelta(hours=1) secrets_manager_mock.get_secret.side_effect = [ new_token_string, new_expires_at.strftime("%Y-%m-%d %H:%M:%S.%f"), ] assert m2m_token_manager.get_token_string() == new_token_string @pytest.mark.anyio async def test_async_m2m_token_manager_get_token_string( async_m2m_token_manager: AsyncM2MTokenManager, secrets_manager_mock: mock.MagicMock ) -> None: token_string = "test123123" secrets_manager_mock.get_secret.side_effect = [ token_string, datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d %H:%M:%S.%f"), ] assert await async_m2m_token_manager.get_token_string() == token_string @pytest.mark.anyio async def test_async_m2m_token_manager_get_token_string_cached( async_m2m_token_manager: AsyncM2MTokenManager, async_cache: AsyncCache, secrets_manager_mock: mock.MagicMock, ) -> None: token_string = "test123123" expires_at = timezone.now() + datetime.timedelta(hours=10) token = M2MToken(token_string=token_string, expires_at=expires_at) await async_cache.set(M2MTokenManager.cache_key, value=token) assert await async_m2m_token_manager.get_token_string() == token_string secrets_manager_mock.get_secret.assert_not_called() @pytest.mark.anyio async def test_async_m2m_token_manager_get_token_string_cached_expired( async_m2m_token_manager: AsyncM2MTokenManager, async_cache: AsyncCache, secrets_manager_mock: mock.MagicMock, ) -> None: old_token_string = "old-token" old_expires_at = timezone.now() - datetime.timedelta(days=100) token = M2MToken(token_string=old_token_string, expires_at=old_expires_at) await async_cache.set(M2MTokenManager.cache_key, value=token) new_token_string = "new-token" new_expires_at = timezone.now() + datetime.timedelta(hours=1) secrets_manager_mock.get_secret.side_effect = [ new_token_string, new_expires_at.strftime("%Y-%m-%d %H:%M:%S.%f"), ] assert await async_m2m_token_manager.get_token_string() == new_token_string def test_m2m_token_manager_get_token_string_new_expires_at_format( m2m_token_manager: M2MTokenManager, secrets_manager_mock: mock.MagicMock ) -> None: token_string = "test123123" secrets_manager_mock.get_secret.side_effect = [ token_string, datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%S.%f%z"), ] assert m2m_token_manager.get_token_string() == token_string @pytest.mark.anyio async def test_async_m2m_token_manager_get_token_string_with_new_expires_at_format( async_m2m_token_manager: AsyncM2MTokenManager, secrets_manager_mock: mock.MagicMock ) -> None: token_string = "test123123" secrets_manager_mock.get_secret.side_effect = [ token_string, datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%S.%f%z"), ] assert await async_m2m_token_manager.get_token_string() == token_string