"""F9 Agent 调度器集成测试 — rollback/on_complete DB 交互""" import asyncio import json import pytest from pathlib import Path from src.blackboard.models import Task from src.blackboard.operations import Blackboard from src.daemon.dispatcher import Dispatcher pytestmark = pytest.mark.integration # --------------------------------------------------------------------------- # 司马懿评审补充:_rollback_current_agent + on_complete 统一(v2.8 #07.2) # --------------------------------------------------------------------------- class TestRollbackAndOnComplete: """司马懿评审遗漏 #3 + #4: crash 后 current_agent 回退 + on_complete 统一路径""" def test_rollback_current_agent_on_crash(self, tmp_path): """executor crash → _rollback_current_agent 回退 current_agent → assignee""" db_path = tmp_path / "blackboard.db" bb = Blackboard(db_path) bb.create_task(Task( id="t1", title="T", status="working", assigned_by="daemon", assignee="zhangfei-dev", )) conn = bb._conn() try: conn.execute("UPDATE tasks SET current_agent=? WHERE id=?", ("zhangfei-dev", "t1")) conn.commit() finally: conn.close() dispatcher = Dispatcher(registered_agents=["zhangfei-dev"]) dispatcher._rollback_current_agent(db_path, "t1", "zhangfei-dev") import sqlite3 conn2 = sqlite3.connect(str(db_path)) conn2.row_factory = sqlite3.Row row = conn2.execute("SELECT current_agent, assignee FROM tasks WHERE id=?", ("t1",)).fetchone() conn2.close() assert row["current_agent"] == row["assignee"] == "zhangfei-dev" def test_rollback_different_agent(self, tmp_path): """current_agent ≠ agent_id → 不回退(安全检查)""" db_path = tmp_path / "blackboard.db" bb = Blackboard(db_path) bb.create_task(Task( id="t1", title="T", status="working", assigned_by="daemon", assignee="zhangfei-dev", )) conn = bb._conn() try: conn.execute("UPDATE tasks SET current_agent=? WHERE id=?", ("simayi-challenger", "t1")) conn.commit() finally: conn.close() dispatcher = Dispatcher(registered_agents=["zhangfei-dev"]) dispatcher._rollback_current_agent(db_path, "t1", "wrong-agent") import sqlite3 conn2 = sqlite3.connect(str(db_path)) conn2.row_factory = sqlite3.Row row = conn2.execute("SELECT current_agent FROM tasks WHERE id=?", ("t1",)).fetchone() conn2.close() assert row["current_agent"] == "simayi-challenger" def test_on_complete_crash_rollback_executor(self, tmp_path): """executor crash → rollback current_agent + _task_auto_complete(标 review)""" db_path = tmp_path / "blackboard.db" bb = Blackboard(db_path) bb.create_task(Task( id="t1", title="T", status="working", assigned_by="daemon", assignee="zhangfei-dev", )) conn = bb._conn() try: conn.execute("UPDATE tasks SET current_agent=? WHERE id=?", ("zhangfei-dev", "t1")) conn.commit() finally: conn.close() dispatcher = Dispatcher(registered_agents=["zhangfei-dev"]) dispatcher._rollback_current_agent(db_path, "t1", "zhangfei-dev") import sqlite3 conn2 = sqlite3.connect(str(db_path)) conn2.row_factory = sqlite3.Row row = conn2.execute("SELECT current_agent FROM tasks WHERE id=?", ("t1",)).fetchone() conn2.close() assert row["current_agent"] == "zhangfei-dev" def test_on_complete_crash_rollback_review(self, tmp_path): """review crash → rollback current_agent + 保持 review 状态""" db_path = tmp_path / "blackboard.db" bb = Blackboard(db_path) bb.create_task(Task( id="t1", title="T", status="review", assigned_by="daemon", assignee="zhangfei-dev", )) conn = bb._conn() try: conn.execute("UPDATE tasks SET current_agent=? WHERE id=?", ("simayi-challenger", "t1")) conn.commit() finally: conn.close() dispatcher = Dispatcher(registered_agents=["simayi-challenger"]) dispatcher._rollback_current_agent(db_path, "t1", "simayi-challenger") import sqlite3 conn2 = sqlite3.connect(str(db_path)) conn2.row_factory = sqlite3.Row row = conn2.execute("SELECT current_agent, status FROM tasks WHERE id=?", ("t1",)).fetchone() conn2.close() assert row["current_agent"] == "zhangfei-dev" assert row["status"] == "review"