indie-status-page/tests/test_api_services.py
IndieStatusBot 902133edd3 feat: indie status page MVP -- FastAPI + SQLite
- 8 DB models (services, incidents, monitors, subscribers, etc.)
- Full CRUD API for services, incidents, monitors
- Public status page with live data
- Incident detail page with timeline
- API key authentication
- Uptime monitoring scheduler
- 13 tests passing
- TECHNICAL_DESIGN.md with full spec
2026-04-25 05:00:00 +00:00

119 lines
No EOL
3.4 KiB
Python

"""Test Services API endpoints."""
import pytest
@pytest.mark.asyncio
async def test_create_service(client, api_key):
"""Should create a new service."""
response = await client.post(
"/api/v1/services/",
json={
"name": "API Server",
"slug": "api-server",
},
headers={"X-API-Key": api_key},
)
assert response.status_code == 201
data = response.json()
assert data["name"] == "API Server"
assert data["slug"] == "api-server"
assert data["is_visible"] is True
@pytest.mark.asyncio
async def test_list_services(client, api_key):
"""Should list all services."""
# Create a service first
await client.post(
"/api/v1/services/",
json={"name": "Database", "slug": "database"},
headers={"X-API-Key": api_key},
)
response = await client.get("/api/v1/services/")
assert response.status_code == 200
data = response.json()
assert isinstance(data, list)
assert len(data) >= 1
@pytest.mark.asyncio
async def test_api_key_required(client):
"""Should reject requests without API key for protected routes."""
response = await client.post(
"/api/v1/services/",
json={"name": "Unauthorized", "slug": "unauth"},
)
assert response.status_code == 422 # Missing required header
@pytest.mark.asyncio
async def test_get_service(client, api_key):
"""Should get a single service by ID."""
create_resp = await client.post(
"/api/v1/services/",
json={"name": "Web App", "slug": "web-app"},
headers={"X-API-Key": api_key},
)
assert create_resp.status_code == 201
service_id = create_resp.json()["id"]
response = await client.get(f"/api/v1/services/{service_id}")
assert response.status_code == 200
data = response.json()
assert data["id"] == service_id
assert data["name"] == "Web App"
@pytest.mark.asyncio
async def test_update_service(client, api_key):
"""Should update a service with PATCH."""
create_resp = await client.post(
"/api/v1/services/",
json={"name": "Old Name", "slug": "old-slug"},
headers={"X-API-Key": api_key},
)
service_id = create_resp.json()["id"]
response = await client.patch(
f"/api/v1/services/{service_id}",
json={"name": "New Name"},
headers={"X-API-Key": api_key},
)
assert response.status_code == 200
data = response.json()
assert data["name"] == "New Name"
assert data["slug"] == "old-slug" # unchanged
@pytest.mark.asyncio
async def test_delete_service(client, api_key):
"""Should delete a service."""
create_resp = await client.post(
"/api/v1/services/",
json={"name": "Delete Me", "slug": "delete-me"},
headers={"X-API-Key": api_key},
)
service_id = create_resp.json()["id"]
response = await client.delete(
f"/api/v1/services/{service_id}",
headers={"X-API-Key": api_key},
)
assert response.status_code == 204
# Verify it's gone
get_resp = await client.get(f"/api/v1/services/{service_id}")
assert get_resp.status_code == 404
@pytest.mark.asyncio
async def test_update_service_not_found(client, api_key):
"""Should return 404 when updating nonexistent service."""
response = await client.patch(
"/api/v1/services/00000000-0000-0000-0000-000000000000",
json={"name": "Ghost"},
headers={"X-API-Key": api_key},
)
assert response.status_code == 404