Merge pull request #715 from christianlouis/test-api-tokens-coverage-14568212820727238898

🧪 Add tests for api_tokens edge cases
This commit is contained in:
Christian Krakau-Louis
2026-03-16 10:49:04 +01:00
committed by GitHub
+81 -6
View File
@@ -101,6 +101,43 @@ def _cleanup(app):
app.dependency_overrides.clear()
# ---------------------------------------------------------------------------
# Tests Auth Helper
# ---------------------------------------------------------------------------
class TestGetOwnerId:
"""Tests for the _get_owner_id dependency helper."""
@pytest.mark.unit
def test_get_owner_id_unauthenticated(self):
"""_get_owner_id should raise a 401 if the user is not authenticated."""
from unittest.mock import MagicMock, patch
from fastapi import HTTPException
from app.api.api_tokens import _get_owner_id
mock_request = MagicMock()
with patch("app.api.api_tokens.get_current_owner_id", return_value=None):
with pytest.raises(HTTPException) as exc_info:
_get_owner_id(mock_request)
assert exc_info.value.status_code == 401
assert exc_info.value.detail == "Not authenticated"
@pytest.mark.unit
def test_get_owner_id_authenticated(self):
"""_get_owner_id should return owner_id if user is authenticated."""
from unittest.mock import MagicMock, patch
from app.api.api_tokens import _get_owner_id
mock_request = MagicMock()
with patch("app.api.api_tokens.get_current_owner_id", return_value="owner123"):
owner_id = _get_owner_id(mock_request)
assert owner_id == "owner123"
# ---------------------------------------------------------------------------
# Tests Token CRUD
# ---------------------------------------------------------------------------
@@ -157,6 +194,46 @@ class TestTokenCreate:
finally:
_cleanup(app)
@pytest.mark.unit
def test_create_token_database_error(self, tok_engine, tok_session):
"""Creating a token should rollback and raise 500 if database commit fails."""
from unittest.mock import patch
from sqlalchemy.orm import Session as SASession
from app.main import app
client = _make_client(tok_engine)
try:
# Wrap commit: flush first so changes are staged in the transaction,
# then raise to simulate a commit failure after data has been written.
def _fail_after_flush(self):
self.flush() # stage changes inside the open transaction
raise Exception("DB Failure")
# Spy on rollback so we can assert it is called.
rollback_called = False
real_rollback = SASession.rollback
def _spy_rollback(self):
nonlocal rollback_called
rollback_called = True
real_rollback(self)
with patch.object(SASession, "commit", _fail_after_flush):
with patch.object(SASession, "rollback", _spy_rollback):
resp = client.post("/api/api-tokens/", json={"name": "DB Error Create Test"})
assert resp.status_code == 500
# rollback() must have been called to undo the flushed changes.
assert rollback_called, "db.rollback() was not called after commit failure in create_token"
# After rollback the token must not exist in the database.
db_token = tok_session.query(ApiToken).filter(ApiToken.name == "DB Error Create Test").first()
assert db_token is None
finally:
_cleanup(app)
class TestTokenList:
"""Tests for GET /api/api-tokens/."""
@@ -326,12 +403,10 @@ class TestTokenRevoke:
rollback_called = True
real_rollback(self)
with (
patch.object(SASession, "commit", _fail_after_flush),
patch.object(SASession, "rollback", _spy_rollback),
):
resp = client.delete(f"/api/api-tokens/{token_id}")
assert resp.status_code == 500
with patch.object(SASession, "commit", _fail_after_flush):
with patch.object(SASession, "rollback", _spy_rollback):
resp = client.delete(f"/api/api-tokens/{token_id}")
assert resp.status_code == 500
# rollback() must have been called to undo the flushed changes.
assert rollback_called, "db.rollback() was not called after commit failure"