Files
AareDAQ/tests/unit/daq/test_server_exception_handler.py
T

100 lines
4.1 KiB
Python

import pytest
from fastapi import FastAPI, HTTPException
from starlette.requests import Request
from starlette.responses import JSONResponse
from unittest.mock import MagicMock
import asyncio
from aare.daq.server_exception_handler import register_exception_handlers
from aare.common.exception_handler import (
MountingFailed, WarningTellException, CriticalTellException,
LoopCenteringFailed, TransformationInvalidException, BeamlineBusyException,
AuthenticationException, SampleException, UserRightsException,
SmargonCommunicationError, TellCommunicationError, JFJochCommunicationError,
AerotechCommunicationError, DataCollectionException, RasterScanException,
UnmountingFailed, AXCFailed, AareDBCommunicationError,
MagnetPositionSensorErorr, ManualMountException, SmartMagnetFaultException,
TellMountFailedException, TellCommandWhileBusyException, TellConnectionException
)
@pytest.fixture
def app():
app = FastAPI()
register_exception_handlers(app)
return app
@pytest.fixture
def mock_request():
return MagicMock(spec=Request)
@pytest.mark.asyncio
async def test_http_exception_handler(app, mock_request):
exc = HTTPException(status_code=418, detail="I'm a teapot")
handler = app.exception_handlers[HTTPException]
response = await handler(mock_request, exc)
assert response.status_code == 418
assert response.body == b'{"code":"HTTP_ERROR","message":"I\'m a teapot"}'
@pytest.mark.asyncio
async def test_mounting_failed_handler(app, mock_request):
exc = MountingFailed("Mount failed")
handler = app.exception_handlers[MountingFailed]
response = await handler(mock_request, exc)
assert response.status_code == 404
assert b"MOUNTING_FAILED" in response.body
@pytest.mark.asyncio
async def test_unmounting_failed_handler(app, mock_request):
exc = UnmountingFailed("Unmount failed")
handler = app.exception_handlers[UnmountingFailed]
response = await handler(mock_request, exc)
assert response.status_code == 500
assert b"UNMOUNTING_FAILED" in response.body
@pytest.mark.asyncio
async def test_smargon_comm_handler(app, mock_request):
exc = SmargonCommunicationError("Smargon dead", operation="MOVE", endpoint="/move")
handler = app.exception_handlers[SmargonCommunicationError]
response = await handler(mock_request, exc)
assert response.status_code == 503
assert b"SMARGON_UNAVAILABLE" in response.body
assert b"MOVE" in response.body
@pytest.mark.asyncio
async def test_unhandled_exception_handler(app, mock_request):
exc = ValueError("Something went wrong")
handler = app.exception_handlers[Exception]
response = await handler(mock_request, exc)
assert response.status_code == 500
assert b"INTERNAL_SERVER_ERROR" in response.body
@pytest.mark.asyncio
async def test_all_handlers_and_payloads(app, mock_request):
# Test all registered handlers to ensure they return JSONResponse and cover the code
for exc_class, handler in app.exception_handlers.items():
if exc_class in (HTTPException, Exception, Request):
continue
# Try to instantiate the exception
try:
# Some exceptions might need specific args, but most in aare.common.exception_handler
# have defaults or take a message
if exc_class in (SmargonCommunicationError, AareDBCommunicationError, TellCommunicationError,
JFJochCommunicationError, AerotechCommunicationError):
exc = exc_class("error", operation="OP", endpoint="/EP")
else:
exc = exc_class("error")
response = await handler(mock_request, exc)
assert isinstance(response, JSONResponse)
assert response.status_code != 200
except Exception as e:
print(f"Skipping {exc_class} due to {e}")
# Special case for HTTPException with dict detail
exc = HTTPException(status_code=400, detail={"code": "CUSTOM", "message": "Msg"})
handler = app.exception_handlers[HTTPException]
response = await handler(mock_request, exc)
assert response.status_code == 400
assert b"CUSTOM" in response.body