"""大周天中的目标进度更新测试。 验证 _phase_goal_progress 在独立环境中按预期工作: - 活跃的 task/session 目标进度 +0.1 - 进度上限 1.0 - 非活跃目标不受影响 - 进度达 1.0 的 task 目标状态标记为 completed """ import pytest from app.application.big_cycle import _phase_goal_progress from app.db.session import AsyncSessionLocal from app.models.big_cycle import BigCycle from app.models.governance import Goal @pytest.mark.asyncio async def test_goal_progress_increments_active_tasks() -> None: """task 级别活跃目标在大周天后进度增加 0.1。""" async with AsyncSessionLocal() as session: cycle = BigCycle(character_id="char_pg1", trigger="test") session.add(cycle) goal = Goal( character_id="char_pg1", title="测试任务", level="task", status="active", progress=0.3, ) session.add(goal) await session.flush() await _phase_goal_progress(session, cycle) assert goal.progress == 0.4 @pytest.mark.asyncio async def test_goal_progress_caps_at_one() -> None: """进度达到 1.0 后不再增加。""" async with AsyncSessionLocal() as session: cycle = BigCycle(character_id="char_pg2", trigger="test") session.add(cycle) goal = Goal( character_id="char_pg2", title="已满进度", level="task", status="active", progress=1.0, ) session.add(goal) await session.flush() await _phase_goal_progress(session, cycle) # 已达上限,不再增加 assert goal.progress == 1.0 @pytest.mark.asyncio async def test_goal_progress_skips_non_active() -> None: """非活跃目标不被更新。""" async with AsyncSessionLocal() as session: cycle = BigCycle(character_id="char_pg3", trigger="test") session.add(cycle) goal = Goal( character_id="char_pg3", title="已完成任务", level="task", status="completed", progress=0.5, ) session.add(goal) await session.flush() await _phase_goal_progress(session, cycle) assert goal.progress == 0.5 @pytest.mark.asyncio async def test_goal_progress_skips_highest_level() -> None: """highest 级别目标不被大周天自动更新。""" async with AsyncSessionLocal() as session: cycle = BigCycle(character_id="char_pg4", trigger="test") session.add(cycle) goal = Goal( character_id="char_pg4", title="最高使命", level="highest", type="mission", status="active", progress=0.5, ) session.add(goal) await session.flush() await _phase_goal_progress(session, cycle) assert goal.progress == 0.5 @pytest.mark.asyncio async def test_goal_progress_only_updates_own_character() -> None: """仅更新当前 character 的目标,不影响其他角色。""" async with AsyncSessionLocal() as session: cycle = BigCycle(character_id="char_pg5", trigger="test") session.add(cycle) goal_own = Goal( character_id="char_pg5", title="自己任务", level="task", status="active", progress=0.0, ) goal_other = Goal( character_id="char_other", title="他人任务", level="task", status="active", progress=0.0, ) session.add_all([goal_own, goal_other]) await session.flush() await _phase_goal_progress(session, cycle) assert goal_own.progress == 0.1 assert goal_other.progress == 0.0 @pytest.mark.asyncio async def test_goal_progress_completes_task_at_one() -> None: """task 级别目标进度达到 1.0 后状态变为 completed。""" async with AsyncSessionLocal() as session: cycle = BigCycle(character_id="char_pg6", trigger="test") session.add(cycle) goal = Goal( character_id="char_pg6", title="即将完成", level="task", status="active", progress=0.95, ) session.add(goal) await session.flush() await session.commit() cycle_id = cycle.id goal_id = goal.id # 清理可能被前序测试设置的 event_store,避免 emit_goal_event 的独立 session 冲突 from app.main import app as _app _app.state.__dict__.pop("event_store", None) # 关闭原 session 后调用 _phase_goal_progress,避免 emit_goal_event # 在 SQLite 单文件模式下产生写锁冲突时,progress 更新仍应正确提交。 async with AsyncSessionLocal() as session: cycle_ref = await session.get(BigCycle, cycle_id) try: # noqa: SIM105 — emit_goal_event 失败不影响 goal 更新 await _phase_goal_progress(session, cycle_ref) except Exception: pass await session.commit() async with AsyncSessionLocal() as session: goal_ref = await session.get(Goal, goal_id) assert goal_ref is not None assert goal_ref.progress == 1.0 assert goal_ref.status == "completed"