from __future__ import annotations from datetime import datetime from uuid import UUID, uuid4 import pytest from schemas.enums import NotificationTargetMode from v1.notifications.service import NotificationService class _FakeNotification: def __init__( self, *, id: UUID, target_mode: NotificationTargetMode = NotificationTargetMode.ALL_USERS, status: str = "published", deleted_at: datetime | None = None, ): self.id = id self.target_mode = target_mode self.status = status self.deleted_at = deleted_at class _TrackingNotificationRepository: def __init__(self, notifications: list[_FakeNotification]) -> None: self._notifications = notifications self.linked_notification_ids: list[list[UUID]] = [] self.linked_is_first: list[bool] = [] async def link_notifications_for_registered_user( self, *, user_id: UUID, is_first_registration: bool ) -> int: target_modes: list[NotificationTargetMode] if is_first_registration: target_modes = [ NotificationTargetMode.NEW_USERS, NotificationTargetMode.ALL_USERS, ] else: target_modes = [NotificationTargetMode.ALL_USERS] matched = [ n for n in self._notifications if n.status == "published" and n.deleted_at is None and n.target_mode in target_modes ] self.linked_notification_ids.append([n.id for n in matched]) self.linked_is_first.append(is_first_registration) return len(matched) @pytest.fixture def notification_new_users() -> _FakeNotification: return _FakeNotification(id=uuid4(), target_mode=NotificationTargetMode.NEW_USERS) @pytest.fixture def notification_all_users() -> _FakeNotification: return _FakeNotification(id=uuid4(), target_mode=NotificationTargetMode.ALL_USERS) @pytest.fixture def notification_exist_users() -> _FakeNotification: return _FakeNotification(id=uuid4(), target_mode=NotificationTargetMode.EXIST_USERS) class TestLinkNotificationsForRegisteredUser: @pytest.mark.asyncio async def test_first_registration_gets_new_users_and_all_users( self, notification_new_users: _FakeNotification, notification_all_users: _FakeNotification, notification_exist_users: _FakeNotification, ) -> None: repo = _TrackingNotificationRepository( [notification_new_users, notification_all_users, notification_exist_users] ) service = NotificationService(repository=repo) # type: ignore[arg-type] count = await service.link_notifications_for_registered_user( user_id=uuid4(), is_first_registration=True ) assert count == 2 linked_ids = repo.linked_notification_ids[0] assert notification_new_users.id in linked_ids assert notification_all_users.id in linked_ids assert notification_exist_users.id not in linked_ids @pytest.mark.asyncio async def test_reregistered_user_only_gets_all_users( self, notification_new_users: _FakeNotification, notification_all_users: _FakeNotification, notification_exist_users: _FakeNotification, ) -> None: repo = _TrackingNotificationRepository( [notification_new_users, notification_all_users, notification_exist_users] ) service = NotificationService(repository=repo) # type: ignore[arg-type] count = await service.link_notifications_for_registered_user( user_id=uuid4(), is_first_registration=False ) assert count == 1 linked_ids = repo.linked_notification_ids[0] assert notification_new_users.id not in linked_ids assert notification_all_users.id in linked_ids assert notification_exist_users.id not in linked_ids @pytest.mark.asyncio async def test_no_published_notifications_returns_zero(self) -> None: repo = _TrackingNotificationRepository([]) service = NotificationService(repository=repo) # type: ignore[arg-type] count = await service.link_notifications_for_registered_user( user_id=uuid4(), is_first_registration=True ) assert count == 0 @pytest.mark.asyncio async def test_only_new_users_notification_first_registration(self) -> None: n = _FakeNotification(id=uuid4(), target_mode=NotificationTargetMode.NEW_USERS) repo = _TrackingNotificationRepository([n]) service = NotificationService(repository=repo) # type: ignore[arg-type] count = await service.link_notifications_for_registered_user( user_id=uuid4(), is_first_registration=True ) assert count == 1 @pytest.mark.asyncio async def test_only_new_users_notification_reregistered(self) -> None: n = _FakeNotification(id=uuid4(), target_mode=NotificationTargetMode.NEW_USERS) repo = _TrackingNotificationRepository([n]) service = NotificationService(repository=repo) # type: ignore[arg-type] count = await service.link_notifications_for_registered_user( user_id=uuid4(), is_first_registration=False ) assert count == 0