mirror of
https://github.com/xlorepdarkhelm/numinar-coding-project.git
synced 2026-09-05 19:38:24 -04:00
211 lines
7.2 KiB
Python
211 lines
7.2 KiB
Python
"""Unit tests for the backend.routers.invitees module."""
|
|
|
|
from typing import Any
|
|
from unittest.mock import ANY
|
|
from unittest.mock import AsyncMock
|
|
from unittest.mock import MagicMock
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from fastapi.testclient import TestClient
|
|
from sqlalchemy.exc import SQLAlchemyError
|
|
|
|
from backend.models import Booking
|
|
from backend.models import Invitee
|
|
from backend.services.invitees import UserList
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_get_invitees_for_booking_success(
|
|
client: TestClient, sample_users: UserList, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test successful retrieval of all invitees for a booking.
|
|
|
|
Via GET /invitees/booking/{booking_id}. Verifies that the endpoint returns the
|
|
expected list of users with a 200 status.
|
|
"""
|
|
booking_id = 1
|
|
with patch(
|
|
"backend.routers.invitees.get_invitees_for_booking", new=AsyncMock()
|
|
) as mock_get_invitees:
|
|
mock_get_invitees.return_value = sample_users
|
|
|
|
response = client.get(f"/invitees/booking/{booking_id}")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json() == [
|
|
{"email": "user1@example.com", "name": "User One"},
|
|
{"email": "user2@example.com", "name": "User Two"},
|
|
]
|
|
mock_get_invitees.assert_called_once_with(ANY, booking_id)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_get_invitees_for_booking_empty(
|
|
client: TestClient, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test retrieval of invitees when none exist for a booking.
|
|
|
|
Via GET /invitees/booking/{booking_id}. Verifies that the endpoint returns an
|
|
empty list with a 200 status.
|
|
"""
|
|
booking_id = 1
|
|
with patch(
|
|
"backend.routers.invitees.get_invitees_for_booking", new=AsyncMock()
|
|
) as mock_get_invitees:
|
|
mock_get_invitees.return_value = []
|
|
|
|
response = client.get(f"/invitees/booking/{booking_id}")
|
|
|
|
assert response.status_code == 200
|
|
assert response.json() == []
|
|
mock_get_invitees.assert_called_once_with(ANY, booking_id)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_get_invitees_for_booking_database_error(
|
|
client: TestClient, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test handling of database errors in GET /invitees/booking/{booking_id}.
|
|
|
|
Verifies that the endpoint returns a 500 status on database failure.
|
|
"""
|
|
booking_id = 1
|
|
with patch(
|
|
"backend.routers.invitees.get_invitees_for_booking", new=AsyncMock()
|
|
) as mock_get_invitees:
|
|
mock_get_invitees.side_effect = SQLAlchemyError()
|
|
|
|
response = client.get(f"/invitees/booking/{booking_id}")
|
|
|
|
assert response.status_code == 500
|
|
assert "detail" in response.json()
|
|
mock_get_invitees.assert_called_once_with(ANY, booking_id)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_add_invitee_success(
|
|
client: TestClient,
|
|
sample_booking: Booking,
|
|
sample_users: UserList,
|
|
mock_logger: MagicMock,
|
|
) -> None:
|
|
"""Test successful addition of an invitee to a booking.
|
|
|
|
Via POST /invitees/booking/{booking_id}. Verifies that the endpoint returns the
|
|
created invitee with a 201 status.
|
|
"""
|
|
booking_id = 1
|
|
invitee_data: dict[str, Any] = {
|
|
"booking_id": booking_id,
|
|
"user_email": "user1@example.com",
|
|
}
|
|
created_invitee = Invitee(**invitee_data)
|
|
created_invitee.id = 1
|
|
created_invitee.booking = sample_booking
|
|
created_invitee.user = sample_users[0]
|
|
with patch(
|
|
"backend.routers.invitees.add_invitee_to_booking", new=AsyncMock()
|
|
) as mock_add_invitee:
|
|
mock_add_invitee.return_value = created_invitee
|
|
|
|
response = client.post(f"/invitees/booking/{booking_id}", json=invitee_data)
|
|
|
|
assert response.status_code == 201
|
|
assert response.json() == {
|
|
"id": 1,
|
|
"booking_id": booking_id,
|
|
"user_email": "user1@example.com",
|
|
"booking": {
|
|
"id": 1,
|
|
"room_id": 1,
|
|
"start_time": "2025-08-25T10:00:00",
|
|
"end_time": "2025-08-25T11:00:00",
|
|
},
|
|
"user": {
|
|
"email": "user1@example.com",
|
|
"name": "User One",
|
|
},
|
|
}
|
|
mock_add_invitee.assert_called_once_with(
|
|
ANY, booking_id, invitee_data["user_email"]
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_add_invitee_database_error(
|
|
client: TestClient, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test handling of database errors in POST /invitees/booking/{booking_id}.
|
|
|
|
Verifies that the endpoint returns a 400 status on database failure.
|
|
"""
|
|
booking_id = 1
|
|
invitee_data: dict[str, Any] = {
|
|
"booking_id": booking_id,
|
|
"user_email": "user1@example.com",
|
|
}
|
|
with patch(
|
|
"backend.routers.invitees.add_invitee_to_booking", new=AsyncMock()
|
|
) as mock_add_invitee:
|
|
mock_add_invitee.side_effect = SQLAlchemyError()
|
|
|
|
response = client.post(f"/invitees/booking/{booking_id}", json=invitee_data)
|
|
|
|
assert response.status_code == 400
|
|
assert "detail" in response.json()
|
|
mock_add_invitee.assert_called_once_with(
|
|
ANY, booking_id, invitee_data["user_email"]
|
|
)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_remove_invitee_success(
|
|
client: TestClient, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test successful removal of an invitee from a booking.
|
|
|
|
Via DELETE /invitees/booking/{booking_id}/user/{user_email}. Verifies that the
|
|
endpoint returns a 204 status on successful deletion.
|
|
"""
|
|
booking_id = 1
|
|
user_email = "user1@example.com"
|
|
with patch(
|
|
"backend.routers.invitees.remove_invitee_from_booking", new=AsyncMock()
|
|
) as mock_remove_invitee:
|
|
response = client.delete(f"/invitees/booking/{booking_id}/user/{user_email}")
|
|
|
|
assert response.status_code == 204
|
|
assert response.text == ""
|
|
mock_remove_invitee.assert_called_once_with(ANY, booking_id, user_email)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
@pytest.mark.parametrize("mock_logger", ["backend.routers.invitees"], indirect=True)
|
|
async def test_remove_invitee_database_error(
|
|
client: TestClient, mock_logger: MagicMock
|
|
) -> None:
|
|
"""Test handling of database errors for delete.
|
|
|
|
Via DELETE /invitees/booking/{booking_id}/user/{user_email}. Verifies that the
|
|
endpoint returns a 500 status on database failure.
|
|
"""
|
|
booking_id = 1
|
|
user_email = "user1@example.com"
|
|
with patch(
|
|
"backend.routers.invitees.remove_invitee_from_booking", new=AsyncMock()
|
|
) as mock_remove_invitee:
|
|
mock_remove_invitee.side_effect = SQLAlchemyError()
|
|
|
|
response = client.delete(f"/invitees/booking/{booking_id}/user/{user_email}")
|
|
|
|
assert response.status_code == 500
|
|
assert "detail" in response.json()
|
|
mock_remove_invitee.assert_called_once_with(ANY, booking_id, user_email)
|