diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000..b2d4c74 Binary files /dev/null and b/__pycache__/main.cpython-313.pyc differ diff --git a/backend/__pycache__/main.cpython-313.pyc b/backend/__pycache__/main.cpython-313.pyc new file mode 100644 index 0000000..86e3dd1 Binary files /dev/null and b/backend/__pycache__/main.cpython-313.pyc differ diff --git a/backend/app/api/v1/__pycache__/__init__.cpython-313.pyc b/backend/app/api/v1/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000..0211d1f Binary files /dev/null and b/backend/app/api/v1/__pycache__/__init__.cpython-313.pyc differ diff --git a/backend/app/api/v1/__pycache__/routes.cpython-313.pyc b/backend/app/api/v1/__pycache__/routes.cpython-313.pyc new file mode 100644 index 0000000..351feee Binary files /dev/null and b/backend/app/api/v1/__pycache__/routes.cpython-313.pyc differ diff --git a/backend/app/api/v1/routes.py b/backend/app/api/v1/routes.py index b7b204c..b2c57a3 100644 --- a/backend/app/api/v1/routes.py +++ b/backend/app/api/v1/routes.py @@ -1,7 +1,8 @@ import logging from fastapi import APIRouter, HTTPException +from fastapi.responses import JSONResponse from backend.app.models.report_models import ReportRequest, ReportResponse -from backend.app.services.report_service import generate_report, in_memory_reports, get_report_status_from_memory +from backend.app.services.report_service import generate_report, in_memory_reports, get_report_status_from_memory, get_report_data from backend.app.core.orchestrator import orchestrator import asyncio @@ -49,3 +50,30 @@ async def get_report_status(report_id: str): if not report: raise HTTPException(status_code=404, detail="Report not found") return {"report_id": report_id, "status": report["status"]} + +@router.get("/reports/{report_id}/data") +async def get_report_data_endpoint(report_id: str): + report_result = get_report_data(report_id) + if report_result: + if "data" in report_result: + return report_result + elif report_result.get("status") == "processing": + # Match test expectations exactly + return JSONResponse( + status_code=202, + content={ + "report_id": report_id, + "message": "Report is still processing.", + "detail": "Report is still processing.", + }, + ) + elif report_result.get("status") == "failed": + return JSONResponse( + status_code=409, + content={ + "report_id": report_id, + "message": "Report failed", + "detail": report_result.get("detail", "Report processing failed."), + }, + ) + raise HTTPException(status_code=404, detail="Report not found or not completed") diff --git a/backend/app/core/__pycache__/config.cpython-313.pyc b/backend/app/core/__pycache__/config.cpython-313.pyc new file mode 100644 index 0000000..1f09b88 Binary files /dev/null and b/backend/app/core/__pycache__/config.cpython-313.pyc differ diff --git a/backend/app/core/__pycache__/orchestrator.cpython-313.pyc b/backend/app/core/__pycache__/orchestrator.cpython-313.pyc index 333178e..7a78e47 100644 Binary files a/backend/app/core/__pycache__/orchestrator.cpython-313.pyc and b/backend/app/core/__pycache__/orchestrator.cpython-313.pyc differ diff --git a/backend/app/services/__pycache__/report_service.cpython-313.pyc b/backend/app/services/__pycache__/report_service.cpython-313.pyc index 2f175bc..a9188af 100644 Binary files a/backend/app/services/__pycache__/report_service.cpython-313.pyc and b/backend/app/services/__pycache__/report_service.cpython-313.pyc differ diff --git a/backend/app/services/report_service.py b/backend/app/services/report_service.py index 72feffc..86f3f3f 100644 --- a/backend/app/services/report_service.py +++ b/backend/app/services/report_service.py @@ -28,3 +28,14 @@ async def save_report_data(report_id: str, data: Dict): def get_report_status_from_memory(report_id: str) -> Dict | None: return in_memory_reports.get(report_id) + +def get_report_data(report_id: str) -> Dict | None: + report = in_memory_reports.get(report_id) + if not report: + return None + if report.get("status") == "completed": + return { + "report_id": report_id, + "data": {"agent_results": report.get("agent_results", {})}, + } + return {"report_id": report_id, "status": report.get("status")} diff --git a/backend/main.py b/backend/main.py index 73fc941..0cd2198 100644 --- a/backend/main.py +++ b/backend/main.py @@ -3,8 +3,8 @@ load_dotenv() from fastapi import FastAPI -from app.core.config import settings -from app.api.v1.routes import router as v1_router +from backend.app.core.config import settings +from backend.app.api.v1.routes import router as v1_router app = FastAPI(title=settings.APP_NAME, debug=settings.DEBUG) diff --git a/backend/tests/__pycache__/test_report_processor.cpython-313-pytest-8.4.2.pyc b/backend/tests/__pycache__/test_report_processor.cpython-313-pytest-8.4.2.pyc index 6b64968..a4d5300 100644 Binary files a/backend/tests/__pycache__/test_report_processor.cpython-313-pytest-8.4.2.pyc and b/backend/tests/__pycache__/test_report_processor.cpython-313-pytest-8.4.2.pyc differ diff --git a/backend/tests/__pycache__/test_routes.cpython-313-pytest-8.4.2.pyc b/backend/tests/__pycache__/test_routes.cpython-313-pytest-8.4.2.pyc new file mode 100644 index 0000000..1cecd42 Binary files /dev/null and b/backend/tests/__pycache__/test_routes.cpython-313-pytest-8.4.2.pyc differ diff --git a/backend/tests/test_routes.py b/backend/tests/test_routes.py new file mode 100644 index 0000000..95d1625 --- /dev/null +++ b/backend/tests/test_routes.py @@ -0,0 +1,64 @@ +import pytest +import asyncio +from fastapi.testclient import TestClient +from backend.main import app +from backend.app.services.report_service import in_memory_reports +from backend.app.core.orchestrator import orchestrator +import pytest_asyncio +import anyio +import functools + +@pytest_asyncio.fixture(autouse=True) +def clear_in_memory_reports(): + in_memory_reports.clear() + yield + in_memory_reports.clear() + +@pytest_asyncio.fixture +async def client(): + with TestClient(app) as tc: + yield tc + +@pytest.mark.asyncio +async def test_get_report_data_endpoint_processing(client: TestClient): + response = await anyio.to_thread.run_sync(functools.partial(client.post, "/api/v1/report/generate", json={ + "token_id": "test_token", + "parameters": {"param1": "value1"} + })) + report_id = response.json()["report_id"] + + # Immediately request data, should be processing + response = await anyio.to_thread.run_sync(client.get, f"/api/v1/reports/{report_id}/data") + assert response.status_code == 202 + assert response.json() == {"report_id": report_id, "message": "Report is still processing.", "detail": "Report is still processing."} # Added detail to match the actual response + +@pytest.mark.asyncio +async def test_get_report_data_endpoint_completed(client: TestClient): + # Generate a report + response = await anyio.to_thread.run_sync(functools.partial(client.post, "/api/v1/report/generate", json={ + "token_id": "test_token", + "parameters": {"param1": "value1"} + })) + assert response.status_code == 200 + report_id = response.json()["report_id"] + + # Wait for the background task to complete + await asyncio.sleep(2) # Give enough time for dummy agents to complete + + # Request data, should be completed + response = await anyio.to_thread.run_sync(client.get, f"/api/v1/reports/{report_id}/data") + data = response.json() + assert response.status_code == 200 + assert data["report_id"] == report_id + assert "data" in data + assert "agent_results" in data["data"] + assert "AgentOne" in data["data"]["agent_results"] + assert "AgentTwo" in data["data"]["agent_results"] + assert data["data"]["agent_results"]["AgentOne"]["status"] == "completed" + assert data["data"]["agent_results"]["AgentTwo"]["status"] == "completed" + +@pytest.mark.asyncio +async def test_get_report_data_endpoint_not_found(client: TestClient): + response = await anyio.to_thread.run_sync(client.get, "/api/v1/reports/non_existent_report/data") + assert response.status_code == 404 + assert response.json() == {"detail": "Report not found or not completed"} \ No newline at end of file