Independent FastAPI backend for Maskan CRM. Owns contacts, organizations, leads, pipelines, activities, products, quotes, users, permissions, audit records and first-party integration credentials, with Alembic migrations against PostgreSQL. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
122 lines
3.5 KiB
Python
122 lines
3.5 KiB
Python
from fastapi.testclient import TestClient
|
|
|
|
|
|
def test_integration_credentials_can_be_listed_and_revoked(
|
|
client: TestClient,
|
|
auth_headers: dict[str, str],
|
|
) -> None:
|
|
created = client.post(
|
|
"/api/v1/integrations/credentials",
|
|
headers=auth_headers,
|
|
json={"name": "MaskanX production"},
|
|
)
|
|
assert created.status_code == 201, created.text
|
|
credential_id = created.json()["id"]
|
|
service_key = created.json()["key"]
|
|
|
|
listed = client.get(
|
|
"/api/v1/integrations/credentials",
|
|
headers=auth_headers,
|
|
)
|
|
assert listed.status_code == 200, listed.text
|
|
assert listed.json()[0]["id"] == credential_id
|
|
assert "key" not in listed.json()[0]
|
|
|
|
ready = client.get(
|
|
"/api/v1/integrations/status",
|
|
headers={"X-Integration-Key": service_key},
|
|
)
|
|
assert ready.status_code == 200, ready.text
|
|
assert ready.json()["status"] == "ready"
|
|
assert ready.json()["workspace"] == "maskan"
|
|
|
|
revoked = client.delete(
|
|
f"/api/v1/integrations/credentials/{credential_id}",
|
|
headers=auth_headers,
|
|
)
|
|
assert revoked.status_code == 204, revoked.text
|
|
|
|
rejected = client.get(
|
|
"/api/v1/integrations/status",
|
|
headers={"X-Integration-Key": service_key},
|
|
)
|
|
assert rejected.status_code == 401
|
|
|
|
|
|
def test_integration_lead_ingestion_is_idempotent(
|
|
client: TestClient,
|
|
auth_headers: dict[str, str],
|
|
) -> None:
|
|
credential = client.post(
|
|
"/api/v1/integrations/credentials",
|
|
headers=auth_headers,
|
|
json={"name": "MaskanX test"},
|
|
)
|
|
assert credential.status_code == 201, credential.text
|
|
service_key = credential.json()["key"]
|
|
assert service_key.startswith("mcrm_")
|
|
|
|
request_headers = {
|
|
"X-Integration-Key": service_key,
|
|
"Idempotency-Key": "meta-lead-123",
|
|
}
|
|
payload = {
|
|
"provider": "meta",
|
|
"external_id": "lead-123",
|
|
"first_name": "Asha",
|
|
"last_name": "Rao",
|
|
"email": "asha@example.com",
|
|
"company_name": "Northstar Systems",
|
|
"lead_title": "AI automation enquiry",
|
|
"source": "Meta Ads",
|
|
"score": 76,
|
|
"campaign": {
|
|
"campaign_id": "campaign-1",
|
|
"ad_id": "ad-4",
|
|
"form_id": "form-2",
|
|
},
|
|
}
|
|
|
|
first = client.post(
|
|
"/api/v1/integrations/leads",
|
|
headers=request_headers,
|
|
json=payload,
|
|
)
|
|
assert first.status_code == 200, first.text
|
|
assert first.json()["created"] is True
|
|
|
|
retry = client.post(
|
|
"/api/v1/integrations/leads",
|
|
headers=request_headers,
|
|
json=payload,
|
|
)
|
|
assert retry.status_code == 200, retry.text
|
|
assert retry.json() == first.json()
|
|
|
|
contacts = client.get("/api/v1/contacts", headers=auth_headers)
|
|
leads = client.get("/api/v1/leads", headers=auth_headers)
|
|
assert contacts.json()["total"] == 1
|
|
assert leads.json()["total"] == 1
|
|
|
|
|
|
def test_integration_lead_requires_idempotency_key(
|
|
client: TestClient,
|
|
auth_headers: dict[str, str],
|
|
) -> None:
|
|
credential = client.post(
|
|
"/api/v1/integrations/credentials",
|
|
headers=auth_headers,
|
|
json={"name": "MaskanX test"},
|
|
)
|
|
response = client.post(
|
|
"/api/v1/integrations/leads",
|
|
headers={"X-Integration-Key": credential.json()["key"]},
|
|
json={
|
|
"provider": "meta",
|
|
"external_id": "lead-456",
|
|
"first_name": "Maya",
|
|
},
|
|
)
|
|
assert response.status_code == 400
|
|
assert "Idempotency-Key" in response.json()["error"]["message"]
|