Files
Aether/tests/unit/test_notification_email_module_toggle.py

165 lines
4.6 KiB
Python
Raw Normal View History

from __future__ import annotations
import time
from types import SimpleNamespace
from typing import Any, cast
from unittest.mock import AsyncMock
import pytest
from fastapi import HTTPException
from starlette.requests import Request
import src.database as database_module
from src.middleware.plugin_middleware import PluginMiddleware
from src.modules.notification_email import notification_email_module
from src.services.system.config import SystemConfigService
def _build_request(path: str = "/boom") -> Request:
scope = {
"type": "http",
"asgi": {"version": "3.0"},
"http_version": "1.1",
"method": "GET",
"scheme": "http",
"path": path,
"raw_path": path.encode("utf-8"),
"query_string": b"",
"headers": [],
"client": ("127.0.0.1", 12345),
"server": ("testserver", 80),
}
return Request(scope)
async def _dummy_app(scope, receive, send): # type: ignore[no-untyped-def]
return
def test_notification_email_module_validate_config_requires_smtp(
monkeypatch: pytest.MonkeyPatch,
) -> None:
monkeypatch.setattr(
"src.services.email.email_sender.EmailSenderService.is_smtp_configured",
lambda _db: False,
)
assert notification_email_module.validate_config is not None
ok, message = notification_email_module.validate_config(object()) # type: ignore[arg-type]
assert ok is False
assert "SMTP" in message
@pytest.mark.asyncio
async def test_call_error_plugins_skips_when_module_disabled(
monkeypatch: pytest.MonkeyPatch,
) -> None:
middleware = PluginMiddleware(_dummy_app)
send_error = AsyncMock()
middleware.plugin_manager = cast(
Any,
SimpleNamespace(
get_plugin=lambda *_args, **_kwargs: SimpleNamespace(
enabled=True, send_error=send_error
)
),
)
monkeypatch.setattr(
middleware,
"_is_notification_email_module_enabled",
AsyncMock(return_value=False),
)
await middleware._call_error_plugins(
_build_request(),
RuntimeError("boom"),
start_time=time.time(),
)
send_error.assert_not_awaited()
@pytest.mark.asyncio
async def test_call_error_plugins_sends_when_module_enabled(
monkeypatch: pytest.MonkeyPatch,
) -> None:
middleware = PluginMiddleware(_dummy_app)
send_error = AsyncMock()
middleware.plugin_manager = cast(
Any,
SimpleNamespace(
get_plugin=lambda *_args, **_kwargs: SimpleNamespace(
enabled=True, send_error=send_error
)
),
)
monkeypatch.setattr(
middleware,
"_is_notification_email_module_enabled",
AsyncMock(return_value=True),
)
request = _build_request("/internal-error")
request.state.request_id = "req-1"
await middleware._call_error_plugins(
request,
RuntimeError("boom"),
start_time=time.time(),
)
send_error.assert_awaited_once()
assert send_error.await_args is not None
kwargs = send_error.await_args.kwargs
assert kwargs["context"]["endpoint"] == "GET /internal-error"
assert kwargs["context"]["request_id"] == "req-1"
@pytest.mark.asyncio
async def test_notification_email_switch_reads_from_system_config(
monkeypatch: pytest.MonkeyPatch,
) -> None:
middleware = PluginMiddleware(_dummy_app)
request = _build_request("/x")
class _FakeDb:
closed = False
def close(self) -> None:
self.closed = True
fake_db = _FakeDb()
monkeypatch.setattr(database_module, "create_session", lambda: fake_db)
monkeypatch.setattr(SystemConfigService, "get_config", lambda *_args, **_kwargs: True)
enabled = await middleware._is_notification_email_module_enabled(request)
assert enabled is True
assert fake_db.closed is True
@pytest.mark.asyncio
async def test_call_error_plugins_ignores_http_4xx(
monkeypatch: pytest.MonkeyPatch,
) -> None:
middleware = PluginMiddleware(_dummy_app)
send_error = AsyncMock()
middleware.plugin_manager = cast(
Any,
SimpleNamespace(
get_plugin=lambda *_args, **_kwargs: SimpleNamespace(
enabled=True, send_error=send_error
)
),
)
monkeypatch.setattr(
middleware,
"_is_notification_email_module_enabled",
AsyncMock(return_value=True),
)
await middleware._call_error_plugins(
_build_request(),
HTTPException(status_code=400, detail="bad request"),
start_time=time.time(),
)
send_error.assert_not_awaited()