feat: T03+T04 backend - FastAPI, DB models, Rentman integration, admin auth, APScheduler
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""Tests for admin sync endpoints (T04)."""
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, patch, MagicMock
|
||||
from app.services.sync_service import SyncService
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_without_token(client):
|
||||
"""POST /api/admin/sync without JWT returns 401."""
|
||||
resp = await client.post("/api/admin/sync")
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_status_without_token(client):
|
||||
"""GET /api/admin/sync-status without JWT returns 401."""
|
||||
resp = await client.get("/api/admin/sync-status")
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_log_without_token(client):
|
||||
"""GET /api/admin/sync-log without JWT returns 401."""
|
||||
resp = await client.get("/api/admin/sync-log")
|
||||
assert resp.status_code == 401
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_with_valid_token(client, seeded_admin, test_db):
|
||||
"""POST /api/admin/sync with valid JWT triggers equipment sync."""
|
||||
# Login
|
||||
login_resp = await client.post("/api/admin/login", json={
|
||||
"username": "admin",
|
||||
"password": "testpassword",
|
||||
})
|
||||
token = login_resp.json()["access_token"]
|
||||
|
||||
# Mock sync service
|
||||
with patch.object(SyncService, "run_sync", new_callable=AsyncMock) as mock_sync:
|
||||
mock_sync.return_value = {"sync_id": 42, "items_processed": 10, "items_failed": 0, "status": "completed"}
|
||||
resp = await client.post("/api/admin/sync", cookies={"hms_admin_token": token})
|
||||
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["sync_id"] == 42
|
||||
assert data["status"] == "completed"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_status_with_valid_token(client, seeded_admin):
|
||||
"""GET /api/admin/sync-status with valid JWT returns status."""
|
||||
login_resp = await client.post("/api/admin/login", json={
|
||||
"username": "admin",
|
||||
"password": "testpassword",
|
||||
})
|
||||
token = login_resp.json()["access_token"]
|
||||
|
||||
with patch.object(SyncService, "get_last_sync", new_callable=AsyncMock) as mock_status:
|
||||
mock_status.return_value = {"last_sync": None, "items_processed": 0, "status": "never"}
|
||||
resp = await client.get("/api/admin/sync-status", cookies={"hms_admin_token": token})
|
||||
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["status"] == "never"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sync_log_with_valid_token(client, seeded_admin):
|
||||
"""GET /api/admin/sync-log with valid JWT returns paginated log."""
|
||||
login_resp = await client.post("/api/admin/login", json={
|
||||
"username": "admin",
|
||||
"password": "testpassword",
|
||||
})
|
||||
token = login_resp.json()["access_token"]
|
||||
|
||||
mock_log = MagicMock()
|
||||
mock_log.id = 1
|
||||
mock_log.sync_type = "equipment"
|
||||
mock_log.status = "completed"
|
||||
mock_log.items_processed = 100
|
||||
mock_log.items_failed = 0
|
||||
mock_log.error_message = None
|
||||
from datetime import datetime
|
||||
mock_log.started_at = datetime(2026, 7, 9, 12, 0, 0)
|
||||
mock_log.completed_at = datetime(2026, 7, 9, 12, 5, 0)
|
||||
|
||||
with patch.object(SyncService, "get_sync_log_paginated", new_callable=AsyncMock) as mock_log_fn:
|
||||
mock_log_fn.return_value = {
|
||||
"items": [mock_log],
|
||||
"total": 1,
|
||||
"page": 1,
|
||||
"page_size": 20,
|
||||
"total_pages": 1,
|
||||
}
|
||||
resp = await client.get("/api/admin/sync-log", cookies={"hms_admin_token": token})
|
||||
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["total"] == 1
|
||||
assert len(data["items"]) == 1
|
||||
assert data["items"][0]["status"] == "completed"
|
||||
Reference in New Issue
Block a user