Files
delphi-database/tests/test_support_api.py
2025-08-13 18:53:35 -05:00

123 lines
4.2 KiB
Python

import os
import uuid
import pytest
from fastapi.testclient import TestClient
# Ensure required env vars for app import/config
os.environ.setdefault("SECRET_KEY", "x" * 32)
os.environ.setdefault("DATABASE_URL", "sqlite:////tmp/delphi_test.sqlite")
from app.main import app # noqa: E402
from app.auth.security import get_current_user, get_admin_user # noqa: E402
from tests.helpers import assert_validation_error, assert_http_error # noqa: E402
@pytest.fixture(scope="module")
def client():
class _Admin:
def __init__(self):
self.id = 1
self.username = "admin"
self.is_admin = True
self.is_active = True
self.first_name = "Admin"
self.last_name = "User"
# For public create, current_user is optional; override admin endpoints
app.dependency_overrides[get_admin_user] = lambda: _Admin()
app.dependency_overrides[get_current_user] = lambda: _Admin()
try:
yield TestClient(app)
finally:
app.dependency_overrides.pop(get_admin_user, None)
app.dependency_overrides.pop(get_current_user, None)
def test_create_ticket_validation_errors(client: TestClient):
# Missing required fields
resp = client.post("/api/support/tickets", json={})
assert_validation_error(resp, "subject")
# Too short subject/description and invalid email
payload = {
"subject": "Hey",
"description": "short",
"contact_name": "",
"contact_email": "not-an-email",
}
resp = client.post("/api/support/tickets", json=payload)
assert_validation_error(resp, "subject")
assert_validation_error(resp, "description")
assert_validation_error(resp, "contact_name")
assert_validation_error(resp, "contact_email")
def _valid_ticket_payload() -> dict:
token = uuid.uuid4().hex[:6]
return {
"subject": f"Support issue {token}",
"description": "A reproducible problem description long enough",
"category": "bug_report",
"priority": "medium",
"contact_name": "John Tester",
"contact_email": f"john.{token}@example.com",
"current_page": "/dashboard",
"browser_info": "pytest-agent",
}
def test_ticket_lifecycle_and_404s_with_audit(client: TestClient):
# Create ticket (public)
payload = _valid_ticket_payload()
resp = client.post("/api/support/tickets", json=payload)
assert resp.status_code == 200
body = resp.json()
ticket_id = body["ticket_id"]
assert body["status"] == "created"
# Get ticket as admin
resp = client.get(f"/api/support/tickets/{ticket_id}")
assert resp.status_code == 200
detail = resp.json()
assert detail["status"] == "open"
assert isinstance(detail.get("responses"), list)
# 404 on missing ticket get/update/respond
resp = client.get("/api/support/tickets/999999")
assert_http_error(resp, 404, "Ticket not found")
resp = client.put("/api/support/tickets/999999", json={"status": "in_progress"})
assert_http_error(resp, 404, "Ticket not found")
resp = client.post("/api/support/tickets/999999/responses", json={"message": "x"})
assert_http_error(resp, 404, "Ticket not found")
# State transitions: open -> in_progress -> resolved
resp = client.put(f"/api/support/tickets/{ticket_id}", json={"status": "in_progress"})
assert resp.status_code == 200
resp = client.get(f"/api/support/tickets/{ticket_id}")
assert resp.status_code == 200
assert resp.json()["status"] == "in_progress"
# Add public response
resp = client.post(
f"/api/support/tickets/{ticket_id}/responses",
json={"message": "We are working on it", "is_internal": False},
)
assert resp.status_code == 200
# Resolve ticket
resp = client.put(f"/api/support/tickets/{ticket_id}", json={"status": "resolved"})
assert resp.status_code == 200
resp = client.get(f"/api/support/tickets/{ticket_id}")
data = resp.json()
assert data["status"] == "resolved"
assert data["resolved_at"] is not None
# Basic list with pagination params should 200
resp = client.get("/api/support/tickets", params={"skip": 0, "limit": 10})
assert resp.status_code == 200
assert isinstance(resp.json(), list)