import asyncio import unittest from types import SimpleNamespace from unittest.mock import AsyncMock, patch from app.services.ai_steward import AIStewardService from app.models import CognitiveConflict class AIStewardFailFastTest(unittest.IsolatedAsyncioTestCase): async def test_analyze_project_input_times_out_to_structured_fallback(self) -> None: service = AIStewardService(db=None) # type: ignore[arg-type] with patch.object(service.llm, "generate", AsyncMock(side_effect=asyncio.TimeoutError())): result = await service._analyze_project_input( "创建一个 3 周上线的 AI 客服项目,先出可运行 MVP。", tenant_id=1, ) self.assertEqual(result["primary_role"], "ai_engineer") self.assertEqual(result["timeline"], "3周") async def test_generate_task_chain_draft_times_out_to_default_tasks(self) -> None: service = AIStewardService(db=None) # type: ignore[arg-type] with patch.object(service.llm, "generate", AsyncMock(side_effect=asyncio.TimeoutError())): tasks = await service._generate_task_chain_draft( analysis={ "project_title": "AI 客服项目", "tech_stack": ["FastAPI", "React"], "timeline": "3周", "primary_role": "ai_engineer", }, tenant_id=1, ) self.assertGreaterEqual(len(tasks), 2) self.assertEqual(tasks[0]["title"], "技术方案设计") async def test_persist_project_creation_draft_writes_conflict_user_ids_as_list(self) -> None: added_rows = [] class FakeDB: def add(self, row): added_rows.append(row) async def flush(self): current = len(added_rows) for index, row in enumerate(added_rows, start=1): if getattr(row, "id", None) is None: row.id = index service = AIStewardService(db=FakeDB()) # type: ignore[arg-type] with patch( "app.services.ai_steward.persist_task", AsyncMock( return_value=SimpleNamespace( id=101, title="任务A", description="desc", estimated_hours=8.0, priority="high", status="todo", ) ), ): payload = await service._persist_project_creation_draft( normalized={ "project": { "name": "测试项目", "title": "测试项目", "description": "desc", "assigned_role": "ai_engineer", "domain_id": 1, }, "signal": { "content": "signal", "impact_score": 0.8, "priority": "high", "strategic_analysis": {}, }, "charter": { "title": "项目宪章", "content": {"success_criteria": ["ok"]}, }, "tasks": [SimpleNamespace(title="任务A", description="desc")], "task_audit": [], "risks": [ { "type": "schedule_delay", "description": "任务超时预警", "threshold_hours": 48.0, "severity": "medium", } ], "analysis": {}, }, input_text="创建测试项目", creator_id=2, tenant_id=1, ) risk_rows = [row for row in added_rows if isinstance(row, CognitiveConflict)] self.assertEqual(len(risk_rows), 1) self.assertEqual(risk_rows[0].involved_user_ids, []) self.assertEqual(payload["risks"][0]["description"], "任务超时预警")