from unittest.mock import AsyncMock, MagicMock, patch from fastapi.testclient import TestClient from app.api.limiter import limiter from app.api.main import app from app.models.issue import IssueReport from app.models.report import EngineeringReport from app.models.repository import RepositoryMetadata from app.models.review import GeneratedTests, ReviewSuggestions limiter.enabled = False client = TestClient(app) VALID_URL = "https://github.com/owner/repo" def _mock_settings(api_key: str = "") -> MagicMock: s = MagicMock() s.api_key = api_key return s def _fake_report() -> EngineeringReport: return EngineeringReport( repository=RepositoryMetadata( url=VALID_URL, name="repo", local_path="/tmp/fake", language="Python", frameworks=[], architecture="", entry_points=[], summary="", ), issues=IssueReport(), review=ReviewSuggestions(summary="ok", overall_score=8.0), tests=GeneratedTests(), full_report="# Report", generated_at="2026-06-15T00:00:00Z", ) def test_analyze_async_returns_job_id_and_completes() -> None: mock_result = MagicMock() mock_result.state = "SUCCESS" mock_result.status = "SUCCESS" mock_result.ready.return_value = True mock_result.failed.return_value = False mock_result.result = _fake_report().model_dump() with ( patch("app.api.dependencies.get_settings", return_value=_mock_settings()), patch( "app.worker.tasks.run_full_analysis", new=AsyncMock(return_value=_fake_report()), ), patch("app.api.routes.AsyncResult", return_value=mock_result), ): submit = client.post("/api/v1/analyze/async", json={"github_url": VALID_URL}) assert submit.status_code == 202 job_id = submit.json()["job_id"] status = client.get(f"/api/v1/jobs/{job_id}") assert status.status_code == 200 data = status.json() assert data["status"] == "success" assert data["result"]["full_report"] == "# Report" def test_job_status_unknown_id_returns_pending() -> None: with patch("app.api.dependencies.get_settings", return_value=_mock_settings()): response = client.get("/api/v1/jobs/does-not-exist") assert response.status_code == 200 assert response.json()["status"] == "pending"