Add the Healthcare platform backend (phases 13.0–13.7) with Alembic migration revision fix, production deploy script, validation reports, shared UI exports, and loyalty list page client directives so Next.js build succeeds. Co-authored-by: Cursor <cursoragent@cursor.com>
166 lines
5.2 KiB
Python
166 lines
5.2 KiB
Python
"""API, health, tenant isolation, and foundation flow tests."""
|
|
from __future__ import annotations
|
|
|
|
from app.events.publisher import get_event_publisher
|
|
from app.tests.conftest import TENANT_A, TENANT_B, tenant_headers
|
|
|
|
|
|
async def test_health_capabilities_metrics(client):
|
|
health = await client.get("/health")
|
|
assert health.status_code == 200
|
|
body = health.json()
|
|
assert body["status"] == "ok"
|
|
assert body["service"] == "healthcare-service"
|
|
|
|
caps = await client.get("/capabilities")
|
|
assert caps.status_code == 200
|
|
c = caps.json()
|
|
assert c["phase"] == "13.7"
|
|
assert c["commercial_product"] == "Torbat Healthcare"
|
|
assert c["features"]["foundation"] is True
|
|
assert c["features"]["doctors"] is True
|
|
assert c["features"]["appointments"] is True
|
|
assert c["features"]["visits"] is True
|
|
assert c["features"]["patient_portal"] is True
|
|
assert c["features"]["medical_records"] is True
|
|
assert c["features"]["pharmacy"] is True
|
|
assert c["features"]["delivery_integration"] is True
|
|
assert c["independence"]["integration_mode"] == "api_and_events_only"
|
|
|
|
metrics = await client.get("/metrics")
|
|
assert metrics.status_code == 200
|
|
assert metrics.json()["phase"] == "13.7"
|
|
|
|
|
|
async def test_foundation_flow_and_events(client):
|
|
headers = tenant_headers(TENANT_A)
|
|
clinic = await client.post(
|
|
"/api/v1/clinics",
|
|
headers=headers,
|
|
json={"code": "CLN1", "name": "City Clinic", "status": "active"},
|
|
)
|
|
assert clinic.status_code == 201, clinic.text
|
|
clinic_id = clinic.json()["id"]
|
|
|
|
branch = await client.post(
|
|
"/api/v1/branches",
|
|
headers=headers,
|
|
json={
|
|
"clinic_id": clinic_id,
|
|
"code": "BR1",
|
|
"name": "Main Branch",
|
|
},
|
|
)
|
|
assert branch.status_code == 201, branch.text
|
|
|
|
department = await client.post(
|
|
"/api/v1/departments",
|
|
headers=headers,
|
|
json={
|
|
"clinic_id": clinic_id,
|
|
"code": "CARDIO",
|
|
"name": "Cardiology",
|
|
},
|
|
)
|
|
assert department.status_code == 201, department.text
|
|
|
|
doctor = await client.post(
|
|
"/api/v1/doctors",
|
|
headers=headers,
|
|
json={
|
|
"user_id": "user-doctor-1",
|
|
"clinic_id": clinic_id,
|
|
"code": "DOC1",
|
|
"display_name": "Dr. Smith",
|
|
},
|
|
)
|
|
assert doctor.status_code == 201, doctor.text
|
|
|
|
patient = await client.post(
|
|
"/api/v1/patients",
|
|
headers=headers,
|
|
json={
|
|
"user_id": "user-patient-1",
|
|
"code": "PAT1",
|
|
"display_name": "Jane Doe",
|
|
},
|
|
)
|
|
assert patient.status_code == 201, patient.text
|
|
|
|
provider = await client.post(
|
|
"/api/v1/external-providers",
|
|
headers=headers,
|
|
json={
|
|
"clinic_id": clinic_id,
|
|
"code": "COMM_X",
|
|
"name": "External Comm X",
|
|
"provider_kind": "communication",
|
|
"adapter_key": "mock_comm",
|
|
},
|
|
)
|
|
assert provider.status_code == 201, provider.text
|
|
|
|
cfg = await client.post(
|
|
"/api/v1/configurations",
|
|
headers=headers,
|
|
json={"clinic_id": clinic_id, "code": "DEFAULT"},
|
|
)
|
|
assert cfg.status_code == 201, cfg.text
|
|
|
|
setting = await client.put(
|
|
"/api/v1/settings",
|
|
headers=headers,
|
|
json={
|
|
"clinic_id": clinic_id,
|
|
"key": "default_locale",
|
|
"value": {"code": "fa"},
|
|
},
|
|
)
|
|
assert setting.status_code == 200, setting.text
|
|
|
|
audit = await client.get(
|
|
"/api/v1/audit",
|
|
headers=headers,
|
|
params={"entity_type": "clinic", "entity_id": clinic_id},
|
|
)
|
|
assert audit.status_code == 200
|
|
assert len(audit.json()) >= 1
|
|
|
|
published = [e.event_type for e in get_event_publisher().published]
|
|
assert "healthcare.clinic.created" in published
|
|
assert "healthcare.branch.created" in published
|
|
assert "healthcare.department.created" in published
|
|
assert "healthcare.doctor.created" in published
|
|
assert "healthcare.patient.created" in published
|
|
assert "healthcare.external_provider.registered" in published
|
|
assert "healthcare.setting.updated" in published
|
|
|
|
|
|
async def test_tenant_isolation(client):
|
|
headers_a = tenant_headers(TENANT_A)
|
|
headers_b = tenant_headers(TENANT_B)
|
|
|
|
created = await client.post(
|
|
"/api/v1/clinics",
|
|
headers=headers_a,
|
|
json={"code": "ISO1", "name": "Tenant A Clinic"},
|
|
)
|
|
assert created.status_code == 201
|
|
clinic_id = created.json()["id"]
|
|
|
|
denied = await client.get(f"/api/v1/clinics/{clinic_id}", headers=headers_b)
|
|
assert denied.status_code == 404
|
|
|
|
listed_b = await client.get("/api/v1/clinics", headers=headers_b)
|
|
assert listed_b.status_code == 200
|
|
assert listed_b.json() == []
|
|
|
|
listed_a = await client.get("/api/v1/clinics", headers=headers_a)
|
|
assert listed_a.status_code == 200
|
|
assert len(listed_a.json()) == 1
|
|
|
|
|
|
async def test_missing_tenant_header_rejected(client):
|
|
res = await client.get("/api/v1/clinics")
|
|
assert res.status_code in (400, 422)
|