"""Integration tests for the FastAPI + Temporal MVP.""" import asyncio import pytest async def wait_for_workflow_status(client, order_id: int, expected_status: str, attempts: int = 120): """Poll the workflow status endpoint until it reaches a target status.""" last_payload = None for _ in range(attempts): response = await client.get(f"/api/v1/workflows/{order_id}") if response.status_code == 200: last_payload = response.json() if last_payload["workflow_status"] == expected_status: return last_payload await asyncio.sleep(0.05) raise AssertionError(f"Workflow {order_id} never reached status {expected_status!r}: {last_payload}") async def wait_for_step_count(client, order_id: int, step_name: str, minimum_count: int, attempts: int = 120): """Poll until a workflow step has been recorded a minimum number of times.""" last_payload = None for _ in range(attempts): response = await client.get(f"/api/v1/workflows/{order_id}") if response.status_code == 200: last_payload = response.json() count = sum(1 for step in last_payload["steps"] if step["step_name"] == step_name) if count >= minimum_count: return last_payload await asyncio.sleep(0.05) raise AssertionError( f"Workflow {order_id} never recorded step {step_name!r} {minimum_count} times: {last_payload}" ) @pytest.mark.asyncio async def test_healthcheck(api_runtime): """The health endpoint should always respond successfully.""" client, _ = api_runtime response = await client.get("/healthz") assert response.status_code == 200 assert response.json() == {"status": "ok"} @pytest.mark.asyncio async def test_low_end_order_completes(api_runtime): """Low-end orders should run through the full automated pipeline.""" client, env = api_runtime response = await client.post( "/api/v1/orders", json={ "customer_level": "low", "service_mode": "auto_basic", "model_id": 101, "pose_id": 3, "garment_asset_id": 9001, "scene_ref_asset_id": 8001, }, ) assert response.status_code == 201 payload = response.json() assert payload["workflow_id"] == f"order-{payload['order_id']}" handle = env.client.get_workflow_handle(payload["workflow_id"]) result = await handle.result() assert result["status"] == "succeeded" order_response = await client.get(f"/api/v1/orders/{payload['order_id']}") assert order_response.status_code == 200 assert order_response.json()["status"] == "succeeded" assets_response = await client.get(f"/api/v1/orders/{payload['order_id']}/assets") assert assets_response.status_code == 200 assert any(asset["asset_type"] == "final" for asset in assets_response.json()) workflow_response = await client.get(f"/api/v1/workflows/{payload['order_id']}") assert workflow_response.status_code == 200 assert workflow_response.json()["workflow_status"] == "succeeded" @pytest.mark.asyncio async def test_mid_end_order_waits_review_then_approves(api_runtime): """Mid-end orders should pause for review and continue after approval.""" client, env = api_runtime response = await client.post( "/api/v1/orders", json={ "customer_level": "mid", "service_mode": "semi_pro", "model_id": 101, "pose_id": 3, "garment_asset_id": 9001, "scene_ref_asset_id": 8001, }, ) assert response.status_code == 201 payload = response.json() await wait_for_workflow_status(client, payload["order_id"], "waiting_review") pending_response = await client.get("/api/v1/reviews/pending") assert pending_response.status_code == 200 assert any(item["order_id"] == payload["order_id"] for item in pending_response.json()) review_response = await client.post( f"/api/v1/reviews/{payload['order_id']}/submit", json={"decision": "approve", "reviewer_id": 77, "comment": "通过"}, ) assert review_response.status_code == 200 handle = env.client.get_workflow_handle(payload["workflow_id"]) result = await handle.result() assert result["status"] == "succeeded" order_response = await client.get(f"/api/v1/orders/{payload['order_id']}") assert order_response.status_code == 200 assert order_response.json()["status"] == "succeeded" @pytest.mark.asyncio @pytest.mark.parametrize( ("decision", "expected_step"), [ ("rerun_scene", "scene"), ("rerun_face", "face"), ("rerun_fusion", "fusion"), ], ) async def test_mid_end_rerun_paths_return_to_review(api_runtime, decision: str, expected_step: str): """Each rerun decision should branch back to the correct step and pause again for review.""" client, env = api_runtime response = await client.post( "/api/v1/orders", json={ "customer_level": "mid", "service_mode": "semi_pro", "model_id": 101, "pose_id": 3, "garment_asset_id": 9001, "scene_ref_asset_id": 8001, }, ) assert response.status_code == 201 payload = response.json() await wait_for_workflow_status(client, payload["order_id"], "waiting_review") review_response = await client.post( f"/api/v1/reviews/{payload['order_id']}/submit", json={"decision": decision, "reviewer_id": 77, "comment": f"trigger {decision}"}, ) assert review_response.status_code == 200 workflow_payload = await wait_for_step_count(client, payload["order_id"], expected_step, 2) workflow_payload = await wait_for_step_count(client, payload["order_id"], "review", 2) assert workflow_payload["workflow_status"] == "waiting_review" approve_response = await client.post( f"/api/v1/reviews/{payload['order_id']}/submit", json={"decision": "approve", "reviewer_id": 77, "comment": "批准最终结果"}, ) assert approve_response.status_code == 200 handle = env.client.get_workflow_handle(payload["workflow_id"]) result = await handle.result() assert result["status"] == "succeeded"