TradeFlowAI / tests /integration /test_e2e_flow.py
muhammadghiffari's picture
Deploy TradeFlow API to HF
db4ba8d
Raw
History Blame Contribute Delete
4.19 kB
import os
import time
from typing import Any
import pytest
from fastapi.testclient import TestClient
from src.main import app
@pytest.mark.integration
def test_full_e2e_upload_process_review_submit(monkeypatch):
"""Full end-to-end flow: upload -> process -> review -> submit.
This test is intentionally guarded and only runs when the environment
variable `RUN_FULL_E2E` is set to `1`. It also supports shortcuts for
local development:
- Set `SKIP_AUTH=1` to bypass Keycloak by monkeypatching `get_current_user`.
- Set `SKIP_WORKER=1` to invoke processing tasks inline after upload.
Requirements when enabled:
- Keycloak, Supabase (db + storage), Redis, MinIO, ChromaDB all running
- A valid bearer token available via `E2E_BEARER_TOKEN` OR use `SKIP_AUTH`
"""
if os.getenv("RUN_FULL_E2E") != "1":
pytest.skip("Set RUN_FULL_E2E=1 to run full end-to-end tests")
client = TestClient(app)
# Optionally bypass auth for local runs
if os.getenv("SKIP_AUTH") == "1":
from src.dependencies import CurrentUser
def _fake_user(*a: Any, **k: Any) -> CurrentUser:
return CurrentUser(
sub="e2e-user",
email="e2e@example.com",
full_name="E2E User",
roles=["operator"],
tier="enterprise",
company_id="e2e-company",
raw_token="e2e",
)
monkeypatch.setattr("src.dependencies.get_current_user", lambda *a, **k: _fake_user())
# Prepare upload payload (single minimal PDF)
files = [
("files", ("bl.pdf", b"%PDF-1.4\n%EOF\n", "application/pdf")),
]
data = {"doc_types": "bill_of_lading"}
auth_header = {}
token = os.getenv("E2E_BEARER_TOKEN")
if token:
auth_header = {"Authorization": f"Bearer {token}"}
else:
# If a .env.e2e file exists (produced by provisioning script), load it
envfile = os.path.join(os.path.dirname(__file__), "../../..", ".env.e2e")
try:
envfile = os.path.abspath(envfile)
if os.path.exists(envfile):
with open(envfile, encoding="utf-8") as f:
for line in f:
if line.strip().startswith("E2E_BEARER_TOKEN="):
token = line.strip().split("=", 1)[1]
auth_header = {"Authorization": f"Bearer {token}"}
break
except Exception:
pass
resp = client.post("/api/v1/batches", files=files, data=data, headers=auth_header)
assert resp.status_code in (200, 201), f"Upload failed: {resp.text}"
batch_id = resp.json().get("batch_id")
assert batch_id, "No batch_id returned"
# Optionally trigger processing inline when no worker is available
if os.getenv("SKIP_WORKER") == "1":
try:
from src.tasks.ocr_tasks import preprocess_document
try:
# Task is often defined with bind=True -> first arg is `self`
preprocess_document(None, batch_id)
except TypeError:
# Some wrappers accept only (batch_id,)
preprocess_document(batch_id)
except Exception as exc: # pragma: no cover - best-effort
pytest.skip(f"Could not invoke preprocess task inline: {exc}")
# Poll batch status until processing/review complete or timeout
timeout = int(os.getenv("E2E_TIMEOUT_SECONDS", "60"))
deadline = time.time() + timeout
status = None
while time.time() < deadline:
r = client.get(f"/api/v1/batches/{batch_id}", headers=auth_header)
if r.status_code == 200:
data = r.json().get("batch") or {}
status = data.get("status")
if status in ("review_complete", "submitted", "rejected"):
break
time.sleep(2)
assert status is not None, "Timed out waiting for batch to become available"
assert status in ("review_complete", "submitted"), f"Unexpected final status: {status}"