test: enhance admin API tests with database session mocking
All checks were successful
CI / lint-and-test (push) Successful in 1m6s
All checks were successful
CI / lint-and-test (push) Successful in 1m6s
- Introduced a mock database session for admin API tests to prevent real database access during CI. - Updated test cases for the `/api/admin/me` endpoint to ensure consistent behavior without a real database. - Improved error handling and clarity in tests by utilizing dependency overrides for session management. - Ensured proper cleanup of dependency overrides after tests to maintain test isolation.
This commit is contained in:
@@ -4,8 +4,10 @@ from unittest.mock import ANY, MagicMock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from duty_teller.api.app import app
|
from duty_teller.api.app import app
|
||||||
|
from duty_teller.api.dependencies import get_db_session
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -13,15 +15,31 @@ def client():
|
|||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def _override_get_db_session(mock_session: MagicMock):
|
||||||
|
"""Dependency override that returns mock_session (no real DB). Used as get_db_session override."""
|
||||||
|
|
||||||
|
def _override() -> Session:
|
||||||
|
return mock_session
|
||||||
|
|
||||||
|
return _override
|
||||||
|
|
||||||
|
|
||||||
# --- GET /api/admin/me ---
|
# --- GET /api/admin/me ---
|
||||||
|
|
||||||
|
|
||||||
@patch("duty_teller.api.dependencies.config.MINI_APP_SKIP_AUTH", True)
|
@patch("duty_teller.api.dependencies.config.MINI_APP_SKIP_AUTH", True)
|
||||||
def test_admin_me_skip_auth_returns_is_admin_false(client):
|
def test_admin_me_skip_auth_returns_is_admin_false(client):
|
||||||
"""With MINI_APP_SKIP_AUTH, GET /api/admin/me returns is_admin: false (no real user)."""
|
"""With MINI_APP_SKIP_AUTH, GET /api/admin/me returns is_admin: false (no real user)."""
|
||||||
|
# Override get_db_session so the endpoint does not open the real DB (CI has no data/ dir).
|
||||||
|
mock_session = MagicMock()
|
||||||
|
mock_session.query.return_value.filter.return_value.first.return_value = None
|
||||||
|
app.dependency_overrides[get_db_session] = _override_get_db_session(mock_session)
|
||||||
|
try:
|
||||||
r = client.get("/api/admin/me")
|
r = client.get("/api/admin/me")
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
assert r.json() == {"is_admin": False}
|
assert r.json() == {"is_admin": False}
|
||||||
|
finally:
|
||||||
|
app.dependency_overrides.pop(get_db_session, None)
|
||||||
|
|
||||||
|
|
||||||
@patch("duty_teller.api.app.is_admin_for_telegram_user")
|
@patch("duty_teller.api.app.is_admin_for_telegram_user")
|
||||||
@@ -245,9 +263,8 @@ def test_admin_reassign_400_when_user_not_found(
|
|||||||
)
|
)
|
||||||
mock_session = MagicMock()
|
mock_session = MagicMock()
|
||||||
mock_session.get.return_value = None # User not found
|
mock_session.get.return_value = None # User not found
|
||||||
with patch("duty_teller.api.app.get_db_session") as mock_db:
|
app.dependency_overrides[get_db_session] = _override_get_db_session(mock_session)
|
||||||
mock_db.return_value.__enter__.return_value = mock_session
|
try:
|
||||||
mock_db.return_value.__exit__.return_value = None
|
|
||||||
r = client.patch(
|
r = client.patch(
|
||||||
"/api/admin/duties/1",
|
"/api/admin/duties/1",
|
||||||
json={"user_id": 999},
|
json={"user_id": 999},
|
||||||
@@ -255,6 +272,8 @@ def test_admin_reassign_400_when_user_not_found(
|
|||||||
"X-Telegram-Init-Data": "auth_date=1&user=%7B%22id%22%3A1%7D&hash=x"
|
"X-Telegram-Init-Data": "auth_date=1&user=%7B%22id%22%3A1%7D&hash=x"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
app.dependency_overrides.pop(get_db_session, None)
|
||||||
assert r.status_code == 400
|
assert r.status_code == 400
|
||||||
mock_update.assert_not_called()
|
mock_update.assert_not_called()
|
||||||
mock_invalidate.assert_not_called()
|
mock_invalidate.assert_not_called()
|
||||||
@@ -301,9 +320,8 @@ def test_admin_reassign_200_updates_and_invalidates(
|
|||||||
mock_update_duty_user.return_value = updated_duty
|
mock_update_duty_user.return_value = updated_duty
|
||||||
mock_session = MagicMock()
|
mock_session = MagicMock()
|
||||||
mock_session.get.return_value = SimpleNamespace(id=2) # User exists
|
mock_session.get.return_value = SimpleNamespace(id=2) # User exists
|
||||||
with patch("duty_teller.api.app.get_db_session") as mock_db:
|
app.dependency_overrides[get_db_session] = _override_get_db_session(mock_session)
|
||||||
mock_db.return_value.__enter__.return_value = mock_session
|
try:
|
||||||
mock_db.return_value.__exit__.return_value = None
|
|
||||||
r = client.patch(
|
r = client.patch(
|
||||||
"/api/admin/duties/1",
|
"/api/admin/duties/1",
|
||||||
json={"user_id": 2},
|
json={"user_id": 2},
|
||||||
@@ -311,6 +329,8 @@ def test_admin_reassign_200_updates_and_invalidates(
|
|||||||
"X-Telegram-Init-Data": "auth_date=1&user=%7B%22id%22%3A1%7D&hash=x"
|
"X-Telegram-Init-Data": "auth_date=1&user=%7B%22id%22%3A1%7D&hash=x"
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
finally:
|
||||||
|
app.dependency_overrides.pop(get_db_session, None)
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
data = r.json()
|
data = r.json()
|
||||||
assert data["id"] == 1
|
assert data["id"] == 1
|
||||||
|
|||||||
Reference in New Issue
Block a user