test: improve test coverage for app/api/imap_profiles.py to 100%
Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com> Agent-Logs-Url: https://github.com/christianlouis/DocuElevate/sessions/55b54d8d-e154-48fc-bf8d-0d59c48cdd54
This commit is contained in:
@@ -1,7 +1,13 @@
|
|||||||
"""Tests for app/api/imap_profiles.py and app/utils/allowed_types category helpers."""
|
"""Tests for app/api/imap_profiles.py and app/utils/allowed_types category helpers."""
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from fastapi.testclient import TestClient
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
from sqlalchemy.pool import StaticPool
|
||||||
|
|
||||||
|
from app.database import Base, get_db
|
||||||
|
from app.models import ImapIngestionProfile
|
||||||
from app.utils.allowed_types import (
|
from app.utils.allowed_types import (
|
||||||
ALL_CATEGORIES,
|
ALL_CATEGORIES,
|
||||||
DEFAULT_CATEGORIES,
|
DEFAULT_CATEGORIES,
|
||||||
@@ -9,6 +15,104 @@ from app.utils.allowed_types import (
|
|||||||
get_allowed_types_for_categories,
|
get_allowed_types_for_categories,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration test constants
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
_OWNER = "profile_user@example.com"
|
||||||
|
_OTHER = "other_user@example.com"
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Shared integration fixtures
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def profile_engine():
|
||||||
|
"""In-memory SQLite engine for IMAP profile tests."""
|
||||||
|
engine = create_engine(
|
||||||
|
"sqlite:///:memory:",
|
||||||
|
connect_args={"check_same_thread": False},
|
||||||
|
poolclass=StaticPool,
|
||||||
|
)
|
||||||
|
Base.metadata.create_all(bind=engine)
|
||||||
|
yield engine
|
||||||
|
Base.metadata.drop_all(bind=engine)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def profile_session(profile_engine):
|
||||||
|
"""DB session scoped to one test."""
|
||||||
|
Session = sessionmaker(bind=profile_engine)
|
||||||
|
session = Session()
|
||||||
|
yield session
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def profile_client(profile_engine):
|
||||||
|
"""TestClient authenticated as _OWNER with DB overridden."""
|
||||||
|
from app.api.imap_profiles import _get_owner_id
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
def override_db():
|
||||||
|
Session = sessionmaker(bind=profile_engine)
|
||||||
|
session = Session()
|
||||||
|
try:
|
||||||
|
yield session
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def override_owner():
|
||||||
|
return _OWNER
|
||||||
|
|
||||||
|
app.dependency_overrides[get_db] = override_db
|
||||||
|
app.dependency_overrides[_get_owner_id] = override_owner
|
||||||
|
with TestClient(app, base_url="http://localhost", raise_server_exceptions=False) as c:
|
||||||
|
yield c
|
||||||
|
app.dependency_overrides.clear()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def anon_client(profile_engine):
|
||||||
|
"""TestClient without authentication (DB still overridden)."""
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
def override_db():
|
||||||
|
Session = sessionmaker(bind=profile_engine)
|
||||||
|
session = Session()
|
||||||
|
try:
|
||||||
|
yield session
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
app.dependency_overrides[get_db] = override_db
|
||||||
|
with TestClient(app, base_url="http://localhost", raise_server_exceptions=False) as c:
|
||||||
|
yield c
|
||||||
|
app.dependency_overrides.clear()
|
||||||
|
|
||||||
|
|
||||||
|
def _make_profile(
|
||||||
|
session,
|
||||||
|
owner: str | None = _OWNER,
|
||||||
|
name: str = "Test Profile",
|
||||||
|
categories_json: str = '["pdf","office"]',
|
||||||
|
is_builtin: bool = False,
|
||||||
|
) -> ImapIngestionProfile:
|
||||||
|
"""Create an ImapIngestionProfile row in the database."""
|
||||||
|
prof = ImapIngestionProfile(
|
||||||
|
name=name,
|
||||||
|
description="A test profile",
|
||||||
|
owner_id=owner,
|
||||||
|
allowed_categories=categories_json,
|
||||||
|
is_builtin=is_builtin,
|
||||||
|
)
|
||||||
|
session.add(prof)
|
||||||
|
session.commit()
|
||||||
|
session.refresh(prof)
|
||||||
|
return prof
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.unit
|
@pytest.mark.unit
|
||||||
class TestFileTypeCategories:
|
class TestFileTypeCategories:
|
||||||
@@ -156,3 +260,357 @@ class TestImapProfilesApiLogic:
|
|||||||
|
|
||||||
result = _to_response(profile)
|
result = _to_response(profile)
|
||||||
assert result["allowed_categories"] == []
|
assert result["allowed_categories"] == []
|
||||||
|
|
||||||
|
def test_get_owner_id_returns_owner_when_authenticated(self):
|
||||||
|
"""Test that _get_owner_id returns the owner_id when get_current_owner_id succeeds."""
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from app.api.imap_profiles import _get_owner_id
|
||||||
|
|
||||||
|
request = MagicMock()
|
||||||
|
with patch("app.api.imap_profiles.get_current_owner_id", return_value="user@example.com"):
|
||||||
|
result = _get_owner_id(request)
|
||||||
|
assert result == "user@example.com"
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – list categories endpoint
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestListCategories:
|
||||||
|
"""Tests for GET /api/imap-profiles/categories."""
|
||||||
|
|
||||||
|
def test_list_categories_returns_all(self, profile_client):
|
||||||
|
"""Authenticated request returns all available file-type categories."""
|
||||||
|
resp = profile_client.get("/api/imap-profiles/categories")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert isinstance(data, list)
|
||||||
|
keys = {item["key"] for item in data}
|
||||||
|
assert keys == set(FILE_TYPE_CATEGORIES.keys())
|
||||||
|
for item in data:
|
||||||
|
assert "key" in item
|
||||||
|
assert "label" in item
|
||||||
|
assert "description" in item
|
||||||
|
|
||||||
|
def test_list_categories_unauthenticated(self, anon_client):
|
||||||
|
"""Unauthenticated request returns 401."""
|
||||||
|
resp = anon_client.get("/api/imap-profiles/categories")
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – list profiles endpoint
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestListProfiles:
|
||||||
|
"""Tests for GET /api/imap-profiles/."""
|
||||||
|
|
||||||
|
def test_list_empty(self, profile_client, profile_session):
|
||||||
|
"""Listing profiles when none exist returns an empty list."""
|
||||||
|
resp = profile_client.get("/api/imap-profiles/")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json() == []
|
||||||
|
|
||||||
|
def test_list_includes_own_profiles(self, profile_client, profile_session):
|
||||||
|
"""Returns profiles owned by the current user."""
|
||||||
|
_make_profile(profile_session, owner=_OWNER, name="My Profile")
|
||||||
|
resp = profile_client.get("/api/imap-profiles/")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert any(p["name"] == "My Profile" for p in data)
|
||||||
|
|
||||||
|
def test_list_includes_global_profiles(self, profile_client, profile_session):
|
||||||
|
"""Returns system-global profiles (owner_id=None)."""
|
||||||
|
_make_profile(profile_session, owner=None, name="Global Profile", is_builtin=True)
|
||||||
|
resp = profile_client.get("/api/imap-profiles/")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert any(p["name"] == "Global Profile" for p in data)
|
||||||
|
|
||||||
|
def test_list_excludes_other_users_profiles(self, profile_client, profile_session):
|
||||||
|
"""Profiles owned by other users are not returned."""
|
||||||
|
_make_profile(profile_session, owner=_OTHER, name="Other Profile")
|
||||||
|
resp = profile_client.get("/api/imap-profiles/")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert not any(p["name"] == "Other Profile" for p in data)
|
||||||
|
|
||||||
|
def test_list_unauthenticated(self, anon_client):
|
||||||
|
"""Unauthenticated request returns 401."""
|
||||||
|
resp = anon_client.get("/api/imap-profiles/")
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – create profile endpoint
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestCreateProfile:
|
||||||
|
"""Tests for POST /api/imap-profiles/."""
|
||||||
|
|
||||||
|
def test_create_success(self, profile_client, profile_session):
|
||||||
|
"""Creating a valid profile returns 201 with the new profile data."""
|
||||||
|
payload = {"name": "New Profile", "description": "desc", "allowed_categories": ["pdf", "office"]}
|
||||||
|
resp = profile_client.post("/api/imap-profiles/", json=payload)
|
||||||
|
assert resp.status_code == 201
|
||||||
|
data = resp.json()
|
||||||
|
assert data["name"] == "New Profile"
|
||||||
|
assert data["description"] == "desc"
|
||||||
|
assert data["allowed_categories"] == ["pdf", "office"]
|
||||||
|
assert data["is_builtin"] is False
|
||||||
|
assert data["owner_id"] == _OWNER
|
||||||
|
assert "id" in data
|
||||||
|
|
||||||
|
def test_create_deduplicates_categories(self, profile_client):
|
||||||
|
"""Duplicate categories in the request are de-duplicated."""
|
||||||
|
payload = {"name": "Dedup Profile", "allowed_categories": ["pdf", "pdf", "office"]}
|
||||||
|
resp = profile_client.post("/api/imap-profiles/", json=payload)
|
||||||
|
assert resp.status_code == 201
|
||||||
|
assert resp.json()["allowed_categories"] == ["pdf", "office"]
|
||||||
|
|
||||||
|
def test_create_invalid_category_returns_422(self, profile_client):
|
||||||
|
"""Unknown category keys cause a 422 response."""
|
||||||
|
payload = {"name": "Bad Profile", "allowed_categories": ["pdf", "nonexistent"]}
|
||||||
|
resp = profile_client.post("/api/imap-profiles/", json=payload)
|
||||||
|
assert resp.status_code == 422
|
||||||
|
|
||||||
|
def test_create_missing_name_returns_422(self, profile_client):
|
||||||
|
"""Missing required 'name' field causes a 422 response."""
|
||||||
|
payload = {"allowed_categories": ["pdf"]}
|
||||||
|
resp = profile_client.post("/api/imap-profiles/", json=payload)
|
||||||
|
assert resp.status_code == 422
|
||||||
|
|
||||||
|
def test_create_empty_categories_returns_422(self, profile_client):
|
||||||
|
"""An empty allowed_categories list causes a 422 response."""
|
||||||
|
payload = {"name": "Empty Cats", "allowed_categories": []}
|
||||||
|
resp = profile_client.post("/api/imap-profiles/", json=payload)
|
||||||
|
assert resp.status_code == 422
|
||||||
|
|
||||||
|
def test_create_unauthenticated(self, anon_client):
|
||||||
|
"""Unauthenticated request returns 401."""
|
||||||
|
payload = {"name": "X", "allowed_categories": ["pdf"]}
|
||||||
|
resp = anon_client.post("/api/imap-profiles/", json=payload)
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – get single profile endpoint
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestGetProfile:
|
||||||
|
"""Tests for GET /api/imap-profiles/{id}."""
|
||||||
|
|
||||||
|
def test_get_own_profile(self, profile_client, profile_session):
|
||||||
|
"""Owner can retrieve their own profile."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
resp = profile_client.get(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
data = resp.json()
|
||||||
|
assert data["id"] == prof.id
|
||||||
|
assert data["name"] == prof.name
|
||||||
|
|
||||||
|
def test_get_global_profile(self, profile_client, profile_session):
|
||||||
|
"""Any authenticated user can retrieve a global (owner_id=None) profile."""
|
||||||
|
prof = _make_profile(profile_session, owner=None, name="Builtin", is_builtin=True)
|
||||||
|
resp = profile_client.get(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json()["name"] == "Builtin"
|
||||||
|
|
||||||
|
def test_get_not_found(self, profile_client):
|
||||||
|
"""Requesting a non-existent profile returns 404."""
|
||||||
|
resp = profile_client.get("/api/imap-profiles/99999")
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
def test_get_other_user_profile_returns_404(self, profile_client, profile_session):
|
||||||
|
"""Accessing another user's private profile returns 404."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OTHER, name="Private")
|
||||||
|
resp = profile_client.get(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
def test_get_unauthenticated(self, anon_client, profile_session):
|
||||||
|
"""Unauthenticated request returns 401."""
|
||||||
|
prof = _make_profile(profile_session, owner=None, is_builtin=True)
|
||||||
|
resp = anon_client.get(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – update profile endpoint
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestUpdateProfile:
|
||||||
|
"""Tests for PUT /api/imap-profiles/{id}."""
|
||||||
|
|
||||||
|
def test_update_name(self, profile_client, profile_session):
|
||||||
|
"""Updating the name of an owned profile returns the updated profile."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER, name="Old Name")
|
||||||
|
resp = profile_client.put(f"/api/imap-profiles/{prof.id}", json={"name": "New Name"})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json()["name"] == "New Name"
|
||||||
|
|
||||||
|
def test_update_categories(self, profile_client, profile_session):
|
||||||
|
"""Updating allowed_categories replaces the previous value."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER, categories_json='["pdf"]')
|
||||||
|
resp = profile_client.put(f"/api/imap-profiles/{prof.id}", json={"allowed_categories": ["office", "text"]})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json()["allowed_categories"] == ["office", "text"]
|
||||||
|
|
||||||
|
def test_update_description(self, profile_client, profile_session):
|
||||||
|
"""Setting description via model_fields_set path updates it."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
resp = profile_client.put(f"/api/imap-profiles/{prof.id}", json={"description": "Updated desc"})
|
||||||
|
assert resp.status_code == 200
|
||||||
|
assert resp.json()["description"] == "Updated desc"
|
||||||
|
|
||||||
|
def test_update_builtin_returns_403(self, profile_client, profile_session):
|
||||||
|
"""Attempting to update a built-in profile returns 403."""
|
||||||
|
prof = _make_profile(profile_session, owner=None, is_builtin=True)
|
||||||
|
resp = profile_client.put(f"/api/imap-profiles/{prof.id}", json={"name": "Renamed"})
|
||||||
|
assert resp.status_code == 403
|
||||||
|
|
||||||
|
def test_update_not_found(self, profile_client):
|
||||||
|
"""Updating a non-existent profile returns 404."""
|
||||||
|
resp = profile_client.put("/api/imap-profiles/99999", json={"name": "X"})
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
def test_update_other_user_profile_returns_404(self, profile_client, profile_session):
|
||||||
|
"""Updating another user's profile returns 404."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OTHER)
|
||||||
|
resp = profile_client.put(f"/api/imap-profiles/{prof.id}", json={"name": "X"})
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
def test_update_invalid_category_returns_422(self, profile_client, profile_session):
|
||||||
|
"""Updating with an invalid category key returns 422."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
resp = profile_client.put(f"/api/imap-profiles/{prof.id}", json={"allowed_categories": ["badcat"]})
|
||||||
|
assert resp.status_code == 422
|
||||||
|
|
||||||
|
def test_update_unauthenticated(self, anon_client, profile_session):
|
||||||
|
"""Unauthenticated request returns 401."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
resp = anon_client.put(f"/api/imap-profiles/{prof.id}", json={"name": "X"})
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – delete profile endpoint
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestDeleteProfile:
|
||||||
|
"""Tests for DELETE /api/imap-profiles/{id}."""
|
||||||
|
|
||||||
|
def test_delete_success(self, profile_client, profile_session):
|
||||||
|
"""Deleting an owned profile returns 204 and removes the row."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
resp = profile_client.delete(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 204
|
||||||
|
# Verify it is gone
|
||||||
|
get_resp = profile_client.get(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert get_resp.status_code == 404
|
||||||
|
|
||||||
|
def test_delete_builtin_returns_403(self, profile_client, profile_session):
|
||||||
|
"""Attempting to delete a built-in profile returns 403."""
|
||||||
|
prof = _make_profile(profile_session, owner=None, is_builtin=True)
|
||||||
|
resp = profile_client.delete(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 403
|
||||||
|
|
||||||
|
def test_delete_not_found(self, profile_client):
|
||||||
|
"""Deleting a non-existent profile returns 404."""
|
||||||
|
resp = profile_client.delete("/api/imap-profiles/99999")
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
def test_delete_other_user_profile_returns_404(self, profile_client, profile_session):
|
||||||
|
"""Deleting another user's private profile returns 404."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OTHER)
|
||||||
|
resp = profile_client.delete(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 404
|
||||||
|
|
||||||
|
def test_delete_unauthenticated(self, anon_client, profile_session):
|
||||||
|
"""Unauthenticated request returns 401."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
resp = anon_client.delete(f"/api/imap-profiles/{prof.id}")
|
||||||
|
assert resp.status_code == 401
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Integration tests – DB error rollback paths
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
class TestDbErrorRollback:
|
||||||
|
"""Tests for exception-handling / rollback paths in create, update, and delete."""
|
||||||
|
|
||||||
|
def _make_failing_client(self, profile_engine, profile_session, *, fail_on: str = "commit"):
|
||||||
|
"""Return a TestClient whose DB session raises RuntimeError on commit/delete."""
|
||||||
|
from app.api.imap_profiles import _get_owner_id
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
Session = sessionmaker(bind=profile_engine)
|
||||||
|
|
||||||
|
def override_db():
|
||||||
|
session = Session()
|
||||||
|
|
||||||
|
def raise_error(*args, **kwargs):
|
||||||
|
raise RuntimeError("Simulated DB failure")
|
||||||
|
|
||||||
|
setattr(session, fail_on, raise_error)
|
||||||
|
try:
|
||||||
|
yield session
|
||||||
|
finally:
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def override_owner():
|
||||||
|
return _OWNER
|
||||||
|
|
||||||
|
app.dependency_overrides[get_db] = override_db
|
||||||
|
app.dependency_overrides[_get_owner_id] = override_owner
|
||||||
|
return TestClient(app, base_url="http://localhost", raise_server_exceptions=False)
|
||||||
|
|
||||||
|
def test_create_db_error_returns_500(self, profile_engine, profile_session):
|
||||||
|
"""A DB error during create triggers rollback and returns 500."""
|
||||||
|
client = self._make_failing_client(profile_engine, profile_session)
|
||||||
|
try:
|
||||||
|
resp = client.post("/api/imap-profiles/", json={"name": "X", "allowed_categories": ["pdf"]})
|
||||||
|
finally:
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
app.dependency_overrides.clear()
|
||||||
|
assert resp.status_code == 500
|
||||||
|
|
||||||
|
def test_update_db_error_returns_500(self, profile_engine, profile_session):
|
||||||
|
"""A DB error during update triggers rollback and returns 500."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
client = self._make_failing_client(profile_engine, profile_session)
|
||||||
|
try:
|
||||||
|
resp = client.put(f"/api/imap-profiles/{prof.id}", json={"name": "New"})
|
||||||
|
finally:
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
app.dependency_overrides.clear()
|
||||||
|
assert resp.status_code == 500
|
||||||
|
|
||||||
|
def test_delete_db_error_returns_500(self, profile_engine, profile_session):
|
||||||
|
"""A DB error during delete triggers rollback and returns 500."""
|
||||||
|
prof = _make_profile(profile_session, owner=_OWNER)
|
||||||
|
client = self._make_failing_client(profile_engine, profile_session, fail_on="delete")
|
||||||
|
try:
|
||||||
|
resp = client.delete(f"/api/imap-profiles/{prof.id}")
|
||||||
|
finally:
|
||||||
|
from app.main import app
|
||||||
|
|
||||||
|
app.dependency_overrides.clear()
|
||||||
|
assert resp.status_code == 500
|
||||||
|
|||||||
Reference in New Issue
Block a user