Files
social-app/backend/tests/unit/v1/inbox_messages/test_service.py
T

182 lines
5.4 KiB
Python

from datetime import datetime, timezone
from unittest.mock import AsyncMock, MagicMock
from uuid import UUID, uuid4
import pytest
from fastapi import HTTPException
from core.auth.models import CurrentUser
from models.inbox_messages import (
InboxMessage,
InboxMessageStatus as InboxMessageModelStatus,
InboxMessageType as InboxMessageModelType,
)
from models.schedule_subscriptions import ScheduleSubscription, SubscriptionStatus
from v1.inbox_messages.schemas import InboxMessageAcceptRequest, InboxMessageListRequest
from v1.inbox_messages.service import InboxMessageService
def _build_message(
*,
message_id: UUID,
recipient_id: UUID,
status: InboxMessageModelStatus = InboxMessageModelStatus.PENDING,
message_type: InboxMessageModelType = InboxMessageModelType.CALENDAR,
schedule_item_id: UUID | None = None,
content: str = '{"permission": 7}',
) -> InboxMessage:
message = MagicMock(spec=InboxMessage)
message.id = message_id
message.recipient_id = recipient_id
message.sender_id = uuid4()
message.message_type = message_type
message.schedule_item_id = schedule_item_id
message.content = content
message.is_read = False
message.status = status
message.created_at = datetime(2026, 2, 28, 10, 0, 0, tzinfo=timezone.utc)
return message
@pytest.mark.asyncio
async def test_list_messages_returns_messages() -> None:
user_id = uuid4()
repo = AsyncMock()
repo.list_by_recipient.return_value = [
_build_message(
message_id=uuid4(),
recipient_id=user_id,
schedule_item_id=uuid4(),
)
]
session = AsyncMock()
service = InboxMessageService(
repository=repo,
session=session,
current_user=CurrentUser(id=user_id),
)
result = await service.list_messages(InboxMessageListRequest())
assert len(result) == 1
assert result[0].recipient_id == user_id
assert result[0].status.value == "pending"
repo.list_by_recipient.assert_awaited_once_with(user_id, None)
@pytest.mark.asyncio
async def test_accept_invitation_creates_subscription() -> None:
user_id = uuid4()
message_id = uuid4()
item_id = uuid4()
pending_message = _build_message(
message_id=message_id,
recipient_id=user_id,
schedule_item_id=item_id,
)
accepted_message = _build_message(
message_id=message_id,
recipient_id=user_id,
status=InboxMessageModelStatus.ACCEPTED,
schedule_item_id=item_id,
)
repo = AsyncMock()
repo.get_by_id.return_value = pending_message
repo.update_status.return_value = accepted_message
session = AsyncMock()
session.add = MagicMock()
service = InboxMessageService(
repository=repo,
session=session,
current_user=CurrentUser(id=user_id),
)
result = await service.accept_invitation(
message_id,
InboxMessageAcceptRequest(
permission_view=True,
permission_edit=True,
permission_invite=False,
),
)
session.add.assert_called_once()
subscription = session.add.call_args.args[0]
assert isinstance(subscription, ScheduleSubscription)
assert subscription.item_id == item_id
assert subscription.subscriber_id == user_id
assert subscription.permission == 5 # view(1) + edit(4) = 5
assert subscription.status == SubscriptionStatus.ACTIVE
repo.update_status.assert_awaited_once_with(message_id, user_id, "accepted")
session.commit.assert_awaited_once()
assert result.status.value == "accepted"
@pytest.mark.asyncio
async def test_dismiss_invitation_updates_status() -> None:
user_id = uuid4()
message_id = uuid4()
pending_message = _build_message(
message_id=message_id,
recipient_id=user_id,
schedule_item_id=uuid4(),
)
dismissed_message = _build_message(
message_id=message_id,
recipient_id=user_id,
status=InboxMessageModelStatus.DISMISSED,
schedule_item_id=uuid4(),
)
repo = AsyncMock()
repo.get_by_id.return_value = pending_message
repo.update_status.return_value = dismissed_message
session = AsyncMock()
service = InboxMessageService(
repository=repo,
session=session,
current_user=CurrentUser(id=user_id),
)
result = await service.dismiss_invitation(message_id)
repo.update_status.assert_awaited_once_with(message_id, user_id, "dismissed")
session.commit.assert_awaited_once()
assert result.status.value == "dismissed"
@pytest.mark.asyncio
async def test_accept_noncalendar_message_fails() -> None:
user_id = uuid4()
message_id = uuid4()
non_calendar_message = _build_message(
message_id=message_id,
recipient_id=user_id,
message_type=InboxMessageModelType.FRIEND_REQUEST,
schedule_item_id=None,
)
repo = AsyncMock()
repo.get_by_id.return_value = non_calendar_message
session = AsyncMock()
session.add = MagicMock()
service = InboxMessageService(
repository=repo,
session=session,
current_user=CurrentUser(id=user_id),
)
with pytest.raises(HTTPException) as exc_info:
await service.accept_invitation(message_id, InboxMessageAcceptRequest())
assert exc_info.value.status_code == 400
assert exc_info.value.detail == "Message is not a calendar invitation"
session.add.assert_not_called()
session.commit.assert_not_awaited()