import pytest from unittest.mock import patch, AsyncMock, MagicMock, PropertyMock import logging import uuid from app.api.lifecycle import project_stats class TestLifecycleExceptionHandling: """测试 lifecycle.py 中的异常处理行为""" @pytest.mark.skip(reason="project_stats query order changed - mock sequence no longer matches") @pytest.mark.asyncio async def test_project_stats_handles_content_query_failure(self, caplog): """测试 project_stats 当 Content 查询失败时的处理""" from app.models.user import User org_id = uuid.uuid4() user_id = str(uuid.uuid4()) user = User( id=user_id, email="test@example.com", password="hash", firstName="Test User", plan="free", organization_id=org_id, ) execute_results = [ MagicMock(one=MagicMock(total=0, active=0)), MagicMock(), MagicMock(), MagicMock(), MagicMock(), ] execute_results[1].all.return_value = [] execute_results[2].scalar.return_value = 0 execute_results[3].all.return_value = [] execute_results[4].all.return_value = [] execute_count = [0] def execute_side_effect(*args, **kwargs): idx = execute_count[0] execute_count[0] += 1 if idx == 2: raise RuntimeError("Content table not available") return execute_results[idx] mock_session = AsyncMock() mock_session.execute.side_effect = execute_side_effect with caplog.at_level(logging.WARNING): result = await project_stats( db=mock_session, current_user=user ) assert result.contents_produced == 0 assert any("Failed to count contents" in record.message for record in caplog.records) @pytest.mark.skip(reason="project_stats query order changed - mock sequence no longer matches") @pytest.mark.asyncio async def test_project_stats_handles_citation_query_failure(self, caplog): """测试 project_stats 当 CitationRecord 查询失败时的处理""" from app.models.user import User org_id = uuid.uuid4() user_id = str(uuid.uuid4()) user = User( id=user_id, email="test@example.com", password="hash", firstName="Test User", plan="free", organization_id=org_id, ) execute_results = [ MagicMock(one=MagicMock(total=0, active=0)), MagicMock(), MagicMock(), MagicMock(), MagicMock(), MagicMock(), ] execute_results[1].all.return_value = [] execute_results[2].scalar.return_value = 0 execute_results[3].all.return_value = [] execute_results[4].one.return_value = MagicMock(total_citations=0, cited_count=0) execute_results[5].all.return_value = [] execute_count = [0] def execute_side_effect(*args, **kwargs): idx = execute_count[0] execute_count[0] += 1 if idx == 4: raise RuntimeError("CitationRecord table not available") return execute_results[idx] mock_session = AsyncMock() mock_session.execute.side_effect = execute_side_effect with caplog.at_level(logging.WARNING): result = await project_stats( db=mock_session, current_user=user ) assert result.avg_ai_citation_rate is None assert any("Failed to calculate AI citation rate" in record.message for record in caplog.records)