"""Tests for the mail signature PATCH/DELETE and label DELETE endpoints (I-D fix). Proves the previously missing routes now work end-to-end: - PATCH /api/v1/mail/signatures/{id} -> 200 with updated values - DELETE /api/v1/mail/signatures/{id} -> 204, row gone - DELETE /api/v1/mail/labels/{id} -> 204, row gone - 404 for unknown IDs """ from __future__ import annotations import pytest import pytest_asyncio from httpx import ASGITransport, AsyncClient from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker from app.core.db import close_engine, reset_engine_for_testing from app.core.permission_registry import init_permission_registry from app.core.service_container import get_container from app.main import create_app from app.plugins.builtins.mail import MailPlugin from app.plugins.registry import reset_registry_for_testing from app.services.plugin_service import reset_plugin_service_for_testing from tests.conftest import ORIGIN_HEADER, login_client, seed_tenant_and_users @pytest_asyncio.fixture async def mail_app(engine: AsyncEngine, redis_client): """FastAPI app with Mail plugin registered.""" reset_engine_for_testing(engine) app = create_app() registry = reset_registry_for_testing() registry.initialize(engine, app) init_permission_registry(active_plugin_names={"mail"}) container = get_container() await container.initialize() registry.register_plugin(MailPlugin()) reset_plugin_service_for_testing(registry) sf = async_sessionmaker(bind=engine, expire_on_commit=False, class_=AsyncSession) async with sf() as session: await registry.install(session, "mail") await registry.activate(session, "mail") await session.commit() yield app await close_engine() @pytest_asyncio.fixture async def mail_client(mail_app) -> AsyncClient: transport = ASGITransport(app=mail_app) async with AsyncClient(transport=transport, base_url="http://test") as c: yield c @pytest_asyncio.fixture async def authed_client( mail_client: AsyncClient, db_session: AsyncSession ) -> AsyncClient: seed = await seed_tenant_and_users(db_session) assert seed is not None await login_client(mail_client, "admin@tenanta.com") return mail_client async def _create_signature(client: AsyncClient) -> dict: resp = await client.post( "/api/v1/mail/signatures", json={"name": "Old Name", "body_html": "

old

", "is_default": False}, headers=ORIGIN_HEADER, ) assert resp.status_code == 201, resp.text return resp.json() async def _create_label(client: AsyncClient) -> dict: resp = await client.post( "/api/v1/mail/labels", json={"name": "Temp Label", "color": "#ff0000"}, headers=ORIGIN_HEADER, ) assert resp.status_code == 201, resp.text return resp.json() @pytest.mark.asyncio async def test_update_signature(authed_client: AsyncClient): sig = await _create_signature(authed_client) resp = await authed_client.patch( f"/api/v1/mail/signatures/{sig['id']}", json={"name": "New Name", "body_html": "

new

", "is_default": True}, headers=ORIGIN_HEADER, ) assert resp.status_code == 200, resp.text data = resp.json() assert data["name"] == "New Name" assert data["body_html"] == "

new

" assert data["is_default"] is True @pytest.mark.asyncio async def test_delete_signature(authed_client: AsyncClient): sig = await _create_signature(authed_client) resp = await authed_client.delete( f"/api/v1/mail/signatures/{sig['id']}", headers=ORIGIN_HEADER, ) assert resp.status_code == 204, resp.text lst = await authed_client.get("/api/v1/mail/signatures", headers=ORIGIN_HEADER) assert all(s["id"] != sig["id"] for s in lst.json()) @pytest.mark.asyncio async def test_delete_label(authed_client: AsyncClient): label = await _create_label(authed_client) resp = await authed_client.delete( f"/api/v1/mail/labels/{label['id']}", headers=ORIGIN_HEADER, ) assert resp.status_code == 204, resp.text lst = await authed_client.get("/api/v1/mail/labels", headers=ORIGIN_HEADER) assert all(lb["id"] != label["id"] for lb in lst.json()) @pytest.mark.asyncio async def test_delete_unknown_signature_404(authed_client: AsyncClient): resp = await authed_client.delete( "/api/v1/mail/signatures/00000000-0000-0000-0000-000000000000", headers=ORIGIN_HEADER, ) assert resp.status_code == 404, resp.text @pytest.mark.asyncio async def test_delete_unknown_label_404(authed_client: AsyncClient): resp = await authed_client.delete( "/api/v1/mail/labels/00000000-0000-0000-0000-000000000000", headers=ORIGIN_HEADER, ) assert resp.status_code == 404, resp.text