mirror of
https://github.com/xlorepdarkhelm/numinar-coding-project.git
synced 2026-09-06 00:28:25 -04:00
268 lines
9.8 KiB
Python
268 lines
9.8 KiB
Python
"""Unit tests for the backend.services.invitees module."""
|
|
|
|
from unittest.mock import AsyncMock
|
|
from unittest.mock import MagicMock
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from sqlalchemy import delete
|
|
from sqlalchemy import select
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from backend.models import Invitee
|
|
from backend.models import InviteeList
|
|
from backend.services.invitees import add_invitee_to_booking
|
|
from backend.services.invitees import get_invitees_for_booking
|
|
from backend.services.invitees import remove_invitee_from_booking
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
async def test_get_invitees_for_booking_success(
|
|
async_session: AsyncSession, sample_invitees: InviteeList, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test successful retrieval of all invitees for a booking.
|
|
|
|
Verifies that get_invitees_for_booking returns the expected list of users and constructs
|
|
the correct SQLAlchemy query.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
sample_invitees: The mocked list of invitees to return.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
booking_id = 1
|
|
mock_scalars_result = AsyncMock()
|
|
mock_scalars_result.all = MagicMock(return_value=sample_invitees)
|
|
mock_scalars = AsyncMock(return_value=mock_scalars_result)
|
|
with patch.object(async_session, "scalars", mock_scalars):
|
|
result = await get_invitees_for_booking(async_session, booking_id)
|
|
assert isinstance(result, list)
|
|
assert len(result) == 2
|
|
assert result == sample_invitees
|
|
mock_scalars.assert_called_once()
|
|
assert mock_scalars.call_args.args[0].compare(
|
|
select(Invitee).where(Invitee.booking_id == booking_id)
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
async def test_get_invitees_for_booking_empty(
|
|
async_session: AsyncSession, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test retrieval of invitees when none exist for the booking.
|
|
|
|
Verifies that get_invitees_for_booking returns an empty list when no invitees are found.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
booking_id = 1
|
|
mock_scalars_result = AsyncMock()
|
|
mock_scalars_result.all = AsyncMock(return_value=[])
|
|
mock_scalars = AsyncMock(return_value=mock_scalars_result)
|
|
with patch.object(async_session, "scalars", mock_scalars):
|
|
result = await get_invitees_for_booking(async_session, booking_id)
|
|
assert isinstance(result, list)
|
|
assert len(result) == 0
|
|
mock_scalars.assert_called_once()
|
|
assert mock_scalars.call_args.args[0].compare(
|
|
select(Invitee).where(Invitee.booking_id == booking_id)
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
async def test_get_invitees_for_booking_database_error(
|
|
async_session: AsyncSession, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test handling of database errors in get_invitees_for_booking.
|
|
|
|
Verifies that get_invitees_for_booking raises an exception on database failure.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
booking_id = 1
|
|
mock_scalars = AsyncMock(side_effect=SQLAlchemyError("Database error"))
|
|
with patch.object(async_session, "scalars", mock_scalars):
|
|
with pytest.raises(SQLAlchemyError):
|
|
await get_invitees_for_booking(async_session, booking_id)
|
|
mock_scalars.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
async def test_add_invitee_to_booking_success(
|
|
async_session: AsyncSession,
|
|
sample_invitee: Invitee,
|
|
mock_logger: MagicMock,
|
|
) -> None:
|
|
"""Test successful addition of an invitee to a booking.
|
|
|
|
Verifies that add_invitee_to_booking adds the invitee, commits the session,
|
|
and returns the invitee.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
sample_invitee: The mocked invitee object.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
mock_scalars_result = AsyncMock()
|
|
mock_scalars_result.first = MagicMock(return_value=None)
|
|
mock_scalars_result.all = MagicMock(return_value=[])
|
|
with (
|
|
patch.object(async_session, "add", new_callable=MagicMock) as mock_add,
|
|
patch.object(async_session, "commit", new_callable=AsyncMock) as mock_commit,
|
|
patch.object(
|
|
async_session, "scalars", AsyncMock(return_value=mock_scalars_result)
|
|
),
|
|
patch(
|
|
"backend.services.bookings.get_booking",
|
|
new=AsyncMock(return_value=MagicMock(room_id=1)),
|
|
),
|
|
patch(
|
|
"backend.services.rooms.get_room",
|
|
new=AsyncMock(return_value=MagicMock(capacity=10)),
|
|
),
|
|
patch(
|
|
"backend.services.invitees.get_invitees_for_booking",
|
|
new=AsyncMock(return_value=[]),
|
|
),
|
|
):
|
|
result = await add_invitee_to_booking(
|
|
async_session, sample_invitee.booking_id, sample_invitee.user_email
|
|
)
|
|
assert result.booking_id == sample_invitee.booking_id
|
|
assert result.user_email == sample_invitee.user_email
|
|
mock_add.assert_called_once()
|
|
mock_commit.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
async def test_add_invitee_to_booking_database_error(
|
|
async_session: AsyncSession, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test handling of database errors in add_invitee_to_booking.
|
|
|
|
Verifies that add_invitee_to_booking rolls back the session on database failure.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
booking_id = 1
|
|
user_email = "user1@example.com"
|
|
invitee = Invitee(booking_id=booking_id, user_email=user_email)
|
|
mock_scalars_result = AsyncMock()
|
|
mock_scalars_result.first = MagicMock(return_value=None)
|
|
mock_scalars_result.all = MagicMock(return_value=[])
|
|
with (
|
|
patch.object(async_session, "add", MagicMock()) as mock_add,
|
|
patch.object(
|
|
async_session,
|
|
"commit",
|
|
AsyncMock(side_effect=SQLAlchemyError("Database error")),
|
|
) as mock_commit,
|
|
patch.object(async_session, "rollback", AsyncMock()) as mock_rollback,
|
|
patch.object(
|
|
async_session, "scalars", AsyncMock(return_value=mock_scalars_result)
|
|
),
|
|
patch(
|
|
"backend.services.bookings.get_booking",
|
|
new=AsyncMock(return_value=MagicMock(room_id=1)),
|
|
),
|
|
patch(
|
|
"backend.services.rooms.get_room",
|
|
new=AsyncMock(return_value=MagicMock(capacity=10)),
|
|
),
|
|
patch(
|
|
"backend.services.invitees.get_invitees_for_booking",
|
|
new=AsyncMock(return_value=[]),
|
|
),
|
|
):
|
|
with pytest.raises(SQLAlchemyError):
|
|
await add_invitee_to_booking(async_session, booking_id, user_email)
|
|
mock_add.assert_called_once_with(invitee)
|
|
mock_commit.assert_called_once()
|
|
mock_rollback.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
@pytest.mark.parametrize(
|
|
"booking_id, user_email",
|
|
[
|
|
(1, "user1@example.com"),
|
|
(2, "user2@example.com"),
|
|
],
|
|
ids=["invitee1", "invitee2"],
|
|
)
|
|
async def test_remove_invitee_from_booking_success(
|
|
async_session: AsyncSession,
|
|
booking_id: int,
|
|
user_email: str,
|
|
mock_logger: MagicMock,
|
|
) -> None:
|
|
"""Test successful removal of an invitee from a booking.
|
|
|
|
Verifies that remove_invitee_from_booking deletes the invitee and commits the session.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
booking_id: The ID of the booking to remove the invitee from.
|
|
user_email: The email of the user to remove as an invitee.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
mock_execute_result = MagicMock(rowcount=1)
|
|
async_session.execute = AsyncMock( # type: ignore [method-assign]
|
|
return_value=mock_execute_result
|
|
)
|
|
async_session.commit = AsyncMock() # type: ignore [method-assign]
|
|
|
|
await remove_invitee_from_booking(async_session, booking_id, user_email)
|
|
|
|
async_session.execute.assert_called_once()
|
|
assert async_session.execute.call_args.args[0].compare(
|
|
delete(Invitee).where(
|
|
Invitee.booking_id == booking_id, Invitee.user_email == user_email
|
|
)
|
|
)
|
|
async_session.commit.assert_called_once()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.services.invitees"], indirect=True)
|
|
async def test_remove_invitee_from_booking_database_error(
|
|
async_session: AsyncSession, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test handling of database errors in remove_invitee_from_booking.
|
|
|
|
Verifies that remove_invitee_from_booking rolls back the session on database failure.
|
|
|
|
Args:
|
|
async_session: The asynchronous database session.
|
|
mock_logger: The mocked logger instance.
|
|
"""
|
|
booking_id = 1
|
|
user_email = "user1@example.com"
|
|
async_session.execute = AsyncMock( # type: ignore [method-assign]
|
|
side_effect=SQLAlchemyError("Database error")
|
|
)
|
|
async_session.rollback = AsyncMock() # type: ignore [method-assign]
|
|
|
|
with pytest.raises(SQLAlchemyError):
|
|
await remove_invitee_from_booking(async_session, booking_id, user_email)
|
|
async_session.execute.assert_called_once()
|
|
assert async_session.execute.call_args.args[0].compare(
|
|
delete(Invitee).where(
|
|
Invitee.booking_id == booking_id, Invitee.user_email == user_email
|
|
)
|
|
)
|
|
async_session.rollback.assert_called_once()
|