Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added __pycache__/main.cpython-313.pyc
Binary file not shown.
Binary file added backend/__pycache__/main.cpython-313.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
30 changes: 29 additions & 1 deletion backend/app/api/v1/routes.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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")
Binary file added backend/app/core/__pycache__/config.cpython-313.pyc
Binary file not shown.
Binary file modified backend/app/core/__pycache__/orchestrator.cpython-313.pyc
Binary file not shown.
Binary file modified backend/app/services/__pycache__/report_service.cpython-313.pyc
Binary file not shown.
11 changes: 11 additions & 0 deletions backend/app/services/report_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")}
4 changes: 2 additions & 2 deletions backend/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Binary file not shown.
Binary file not shown.
64 changes: 64 additions & 0 deletions backend/tests/test_routes.py
Original file line number Diff line number Diff line change
@@ -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"}