multi-agent-system / tests /integration /test_prd_flow.py
firepenguindisopanda
Refactor test documentation and improve consistency in comments
e382248
Raw
History Blame Contribute Delete
5.74 kB
"""
Integration tests for the PRD generation flow.
Tests the full lifecycle: start → chat → doc → status → sections.
Uses real NVIDIA LLM API calls.
**Why a fixture rather than test ordering.** These tests previously passed the
session id between themselves via `pytest.session_id`, falling back to an unused
random UUID when it was absent. A failed `/prd/start` therefore left the
remaining tests asserting against a session that had never existed - and they
passed, because the endpoints answer 200 for unknown sessions. The session is now
created by a module-scoped fixture, so a failure there ERRORs every dependent
test instead of quietly weakening it.
"""
import pytest
from tests.integration.conftest import _require_env, require_ok
@pytest.fixture(scope="module")
def prd_session(live_client) -> dict:
"""Start one PRD session shared by every test in this module."""
_require_env("NVIDIA_API_KEY")
response = live_client.post(
"/prd/start",
json={
"description": (
"A task management app for remote teams with real-time collaboration, "
"Kanban boards, and time tracking."
),
"user_id": 1,
},
)
require_ok(response, "POST /prd/start")
return response.json()
class TestPRDFlow:
"""Test the complete PRD generation lifecycle with live LLM."""
def test_prd_start_session(self, prd_session):
"""POST /prd/start creates a new PRD session with real LLM evaluation."""
assert prd_session["session_id"]
assert len(prd_session["message"]) > 10, (
f"expected a real LLM reply, got {prd_session['message']!r}"
)
def test_prd_chat_response(self, live_client, prd_session):
"""POST /prd/chat gets a real LLM response."""
_require_env("NVIDIA_API_KEY")
response = live_client.post(
"/prd/chat",
json={
"session_id": prd_session["session_id"],
"message": (
"The app should support multiple projects, assign tasks to team "
"members, and send email notifications for deadlines."
),
},
)
require_ok(response, "POST /prd/chat")
data = response.json()
assert "phase" in data
assert "needs_more" in data
assert len(data["agent_response"]) > 20, (
f"expected real LLM content, got {data['agent_response']!r}"
)
def test_prd_status(self, live_client, prd_session):
"""GET /prd/status/{session_id} returns session status."""
session_id = prd_session["session_id"]
response = live_client.get(f"/prd/status/{session_id}")
require_ok(response, f"GET /prd/status/{session_id}")
data = response.json()
assert data["phase"] != "not_found", (
"the session created by this module is not recognised by /prd/status"
)
assert "requirements_status" in data
assert "follow_up_count" in data
def test_prd_doc_retrieval(self, live_client, prd_session):
"""GET /prd/doc/{session_id} retrieves the PRD document."""
session_id = prd_session["session_id"]
response = live_client.get(f"/prd/doc/{session_id}")
require_ok(response, f"GET /prd/doc/{session_id}")
data = response.json()
assert data["session_id"] == session_id
assert "requirements_status" in data
def test_prd_sections(self, live_client, prd_session):
"""GET /prd/sections/{session_id} returns structured PRD sections."""
session_id = prd_session["session_id"]
response = live_client.get(f"/prd/sections/{session_id}")
require_ok(response, f"GET /prd/sections/{session_id}")
data = response.json()
assert data["session_id"] == session_id
assert "full_text" in data
assert "key_features" in data
def test_prd_missing_session(self, live_client):
"""GET /prd/status/{missing_id} handles missing session gracefully."""
response = live_client.get("/prd/status/00000000-0000-0000-0000-000000000000")
assert response.status_code == 200, response.text
data = response.json()
assert data["phase"] == "not_found"
class TestPRDDownload:
"""Test PRD download endpoints."""
def test_download_markdown(self, live_client, prd_session):
"""GET /prd/download/{session_id}?format=markdown returns markdown.
The endpoint 404s until `generated_prd` is populated, and this module's
conversation may not have reached generation. Rather than accept
`status_code in (200, 404)` - which passes whatever happens - the
expectation is derived from `/prd/sections`, whose `full_text` is empty
exactly when the PRD has not been generated. Both branches are checked.
"""
session_id = prd_session["session_id"]
sections = live_client.get(f"/prd/sections/{session_id}")
require_ok(sections, f"GET /prd/sections/{session_id}")
prd_generated = bool(sections.json()["full_text"])
response = live_client.get(
f"/prd/download/{session_id}",
params={"format": "markdown"},
)
if prd_generated:
assert response.status_code == 200, response.text
assert response.json()["markdown"], "download returned an empty PRD"
else:
assert response.status_code == 404, (
f"PRD was not generated, so download must 404; got "
f"{response.status_code}: {response.text[:300]}"
)
assert response.json()["error"] == "PRD not found or not generated"