Spaces:
Sleeping
Sleeping
| """Tests for server/routes.py — FastAPI chat API endpoints.""" | |
| from fastapi.testclient import TestClient | |
| from server.web import app | |
| client = TestClient(app) | |
| class TestChatEndpoint: | |
| def test_basic_chat(self): | |
| resp = client.post("/api/chat", json={ | |
| "message": "I need a bracket", | |
| "history": [], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert "responses" in data | |
| assert len(data["responses"]) > 0 | |
| def test_chat_with_mentions(self): | |
| resp = client.post("/api/chat", json={ | |
| "message": "What do you think?", | |
| "history": [], | |
| "mentions": ["cnc"], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| agent_ids = [r["agent_id"] for r in data["responses"]] | |
| assert "cnc" in agent_ids | |
| def test_chat_with_history(self): | |
| resp = client.post("/api/chat", json={ | |
| "message": "Make it wider", | |
| "history": [ | |
| {"role": "user", "content": "I need a bracket"}, | |
| {"role": "agent", "agent_id": "design", "content": "L-bracket suggestion."}, | |
| ], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert "responses" in data | |
| def test_chat_empty_message_rejected(self): | |
| resp = client.post("/api/chat", json={ | |
| "message": "", | |
| "history": [], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 422 | |
| def test_chat_returns_design_state(self): | |
| resp = client.post("/api/chat", json={ | |
| "message": "60mm wide aluminum bracket", | |
| "history": [], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert "design_state" in data | |
| def test_chat_at_mention_in_message(self): | |
| resp = client.post("/api/chat", json={ | |
| "message": "@engineering what thickness?", | |
| "history": [], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| agent_ids = [r["agent_id"] for r in data["responses"]] | |
| assert "engineering" in agent_ids | |
| class TestReportEndpoint: | |
| def test_basic_report(self): | |
| resp = client.post("/api/report", json={ | |
| "part_name": "test_bracket", | |
| "history": [ | |
| {"role": "agent", "agent_id": "design", "content": "L-bracket design."}, | |
| {"role": "agent", "agent_id": "engineering", "content": "3mm aluminum."}, | |
| {"role": "agent", "agent_id": "cnc", "content": "3-axis OK."}, | |
| ], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert "report" in data | |
| assert "test_bracket" in data["report"] | |
| assert "Design Decisions" in data["report"] | |
| assert "Engineering Specifications" in data["report"] | |
| assert "Manufacturing Notes" in data["report"] | |
| def test_empty_history(self): | |
| resp = client.post("/api/report", json={ | |
| "part_name": "empty_part", | |
| "history": [], | |
| "backend": "mock", | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert "report" in data | |
| class TestAgentsEndpoint: | |
| def test_list_agents(self): | |
| resp = client.get("/api/agents") | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert "agents" in data | |
| agent_ids = [a["id"] for a in data["agents"]] | |
| assert "design" in agent_ids | |
| assert "engineering" in agent_ids | |
| assert "cnc" in agent_ids | |
| assert "cad" in agent_ids | |
| def test_agent_has_metadata(self): | |
| resp = client.get("/api/agents") | |
| data = resp.json() | |
| agent = data["agents"][0] | |
| assert "id" in agent | |
| assert "name" in agent | |
| assert "role" in agent | |
| assert "color" in agent | |
| assert "avatar" in agent | |
| class TestPlanApproveEndpoint: | |
| def test_approve_sets_phase(self): | |
| resp = client.post("/api/plan/approve", json={ | |
| "plan": { | |
| "part_name": "bracket", | |
| "description": "test", | |
| "material": "aluminum 6061", | |
| "dimensions": {"width": 60}, | |
| "features": ["4x M6 holes"], | |
| "constraints": ["min wall 3mm"], | |
| "axis_recommendation": "3-axis", | |
| "machining_notes": [], | |
| "confidence_score": 9.0, | |
| }, | |
| "design_state": { | |
| "part_name": "bracket", | |
| "material": "steel", | |
| "dimensions": {"width": 50}, | |
| "phase": "planning", | |
| }, | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert data["design_state"]["phase"] == "approved" | |
| assert data["design_state"]["material"] == "aluminum 6061" | |
| assert data["design_state"]["dimensions"]["width"] == 60 | |
| def test_approve_merges_plan_into_state(self): | |
| resp = client.post("/api/plan/approve", json={ | |
| "plan": { | |
| "part_name": "gear", | |
| "description": "spur gear", | |
| "material": "brass", | |
| "dimensions": {"diameter": 40}, | |
| "features": [], | |
| "constraints": [], | |
| "axis_recommendation": "3-axis", | |
| "machining_notes": ["No undercuts"], | |
| "confidence_score": 8.0, | |
| }, | |
| "design_state": {"phase": "planning"}, | |
| }) | |
| data = resp.json() | |
| assert data["design_state"]["part_name"] == "gear" | |
| assert data["design_state"]["plan"]["material"] == "brass" | |
| def test_approve_preserves_notes(self): | |
| resp = client.post("/api/plan/approve", json={ | |
| "plan": { | |
| "part_name": "bracket", | |
| "description": "test", | |
| "material": "aluminum 6061", | |
| "dimensions": {"width": 60}, | |
| "features": [], | |
| "constraints": [], | |
| "axis_recommendation": "3-axis", | |
| "machining_notes": [], | |
| "confidence_score": 9.0, | |
| "notes": "Check material compatibility", | |
| }, | |
| "design_state": {"phase": "planning"}, | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert data["design_state"]["plan"]["notes"] == "Check material compatibility" | |
| class TestPlanRejectEndpoint: | |
| def test_reject_resets_phase(self): | |
| resp = client.post("/api/plan/reject", json={ | |
| "design_state": { | |
| "phase": "planning", | |
| "material": "aluminum", | |
| "plan": {"part_name": "x", "description": "", "material": "aluminum", | |
| "dimensions": {}, "features": [], "constraints": [], | |
| "axis_recommendation": "", "machining_notes": [], | |
| "confidence_score": 5.0}, | |
| }, | |
| }) | |
| assert resp.status_code == 200 | |
| data = resp.json() | |
| assert data["design_state"]["phase"] == "exploring" | |
| assert data["design_state"]["plan"] is None | |
| assert data["design_state"]["material"] == "aluminum" | |