Files
Aniworld/tests/unit/test_error_controller.py
Lukas 5b3fbf36b9 Task 4: Add Services & Utilities tests (66 tests)
- test_media_utils.py: 29 tests for check_media_files, get_media_file_paths,
  has_all_images, count_video_files, has_video_files, constants
- test_nfo_factory.py: 11 tests for NFOServiceFactory.create, create_optional,
  get_nfo_factory singleton, create_nfo_service convenience
- test_series_manager_service.py: 15 tests for init, from_settings,
  process_nfo_for_series, scan_and_process_nfo, close
- test_templates_utils.py: 4 tests for TEMPLATES_DIR path resolution
- test_error_controller.py: 7 tests for 404/500 handlers (API vs HTML)
2026-02-15 17:49:11 +01:00

111 lines
3.9 KiB
Python

"""Unit tests for error controller module.
Tests custom 404 and 500 error handlers for both API and HTML responses.
"""
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from fastapi import HTTPException, Request
from src.server.controllers.error_controller import (
not_found_handler,
server_error_handler,
)
def _make_request(path: str = "/") -> MagicMock:
"""Create a mock Request object with a given path."""
request = MagicMock(spec=Request)
url = MagicMock()
url.path = path
request.url = url
return request
class TestNotFoundHandler:
"""Tests for the 404 not_found_handler."""
@pytest.mark.asyncio
async def test_api_path_returns_json(self):
"""API paths get a JSON response with 404 status."""
request = _make_request("/api/anime/123")
exc = HTTPException(status_code=404)
resp = await not_found_handler(request, exc)
assert resp.status_code == 404
assert resp.body is not None
@pytest.mark.asyncio
@patch("src.server.controllers.error_controller.render_template")
async def test_web_path_renders_template(self, mock_render):
"""Non-API paths render the error template."""
mock_render.return_value = MagicMock(status_code=404)
request = _make_request("/anime/details")
exc = HTTPException(status_code=404)
await not_found_handler(request, exc)
mock_render.assert_called_once_with(
"error.html",
request,
context={"error": "Page not found", "status_code": 404},
title="404 - Not Found",
)
@pytest.mark.asyncio
async def test_api_json_structure(self):
"""API 404 response has 'detail' field."""
import json
request = _make_request("/api/missing")
exc = HTTPException(status_code=404)
resp = await not_found_handler(request, exc)
body = json.loads(resp.body)
assert body["detail"] == "API endpoint not found"
class TestServerErrorHandler:
"""Tests for the 500 server_error_handler."""
@pytest.mark.asyncio
async def test_api_path_returns_json(self):
"""API paths get a JSON response with 500 status."""
request = _make_request("/api/download")
exc = RuntimeError("crash")
resp = await server_error_handler(request, exc)
assert resp.status_code == 500
@pytest.mark.asyncio
@patch("src.server.controllers.error_controller.render_template")
async def test_web_path_renders_template(self, mock_render):
"""Non-API paths render the error template."""
mock_render.return_value = MagicMock(status_code=500)
request = _make_request("/settings")
exc = RuntimeError("crash")
await server_error_handler(request, exc)
mock_render.assert_called_once_with(
"error.html",
request,
context={"error": "Internal server error", "status_code": 500},
title="500 - Server Error",
)
@pytest.mark.asyncio
async def test_api_error_does_not_expose_stack_trace(self):
"""API 500 response doesn't contain the actual error message."""
import json
request = _make_request("/api/vulnerable")
exc = RuntimeError("secret database credentials")
resp = await server_error_handler(request, exc)
body = json.loads(resp.body)
assert "secret" not in body["detail"]
assert body["detail"] == "Internal server error"
@pytest.mark.asyncio
async def test_api_path_detection(self):
"""Correctly distinguishes API vs web paths."""
api_request = _make_request("/api/test")
web_request = _make_request("/dashboard")
# API path returns JSONResponse
from fastapi.responses import JSONResponse
resp = await server_error_handler(api_request, Exception("err"))
assert isinstance(resp, JSONResponse)