auto-sync: 2026-05-18 19:28:55
This commit is contained in:
+35
-21
@@ -716,21 +716,12 @@ class TestE9RealAgentDispatch:
|
|||||||
self.data_root = data_root
|
self.data_root = data_root
|
||||||
|
|
||||||
def _make_ticker(self):
|
def _make_ticker(self):
|
||||||
"""创建含 Dispatcher + Spawner 的 Ticker(隔离 registry,只含当前项目)"""
|
"""创建含 Dispatcher + Spawner 的 Ticker(真实 spawn)"""
|
||||||
from src.blackboard.registry import ProjectRegistry
|
from src.blackboard.registry import ProjectRegistry
|
||||||
from src.daemon.dispatcher import Dispatcher
|
from src.daemon.dispatcher import Dispatcher
|
||||||
from src.daemon.spawner import AgentSpawner
|
from src.daemon.spawner import AgentSpawner
|
||||||
import tempfile
|
registry = ProjectRegistry(self.data_root)
|
||||||
self._tmp = Path(tempfile.mkdtemp(prefix="e2e-ticker-"))
|
self._spawner = AgentSpawner(dry_run=False)
|
||||||
registry = ProjectRegistry(self._tmp)
|
|
||||||
import shutil
|
|
||||||
src_dir = self.data_root / self.pid
|
|
||||||
dst_dir = self._tmp / self.pid
|
|
||||||
if src_dir.exists():
|
|
||||||
shutil.copytree(src_dir, dst_dir)
|
|
||||||
registry.create_project(self.pid, f"E9-{self.pid}")
|
|
||||||
|
|
||||||
self._spawner = AgentSpawner(dry_run=True)
|
|
||||||
dispatcher = Dispatcher(
|
dispatcher = Dispatcher(
|
||||||
registered_agents=["zhangfei-dev", "jiangwei-infra", "simayi-challenger", "pangtong-fujunshi"],
|
registered_agents=["zhangfei-dev", "jiangwei-infra", "simayi-challenger", "pangtong-fujunshi"],
|
||||||
spawner=self._spawner,
|
spawner=self._spawner,
|
||||||
@@ -744,12 +735,12 @@ class TestE9RealAgentDispatch:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_e91_simple_task_agent_execute(self, client):
|
def test_e91_simple_task_agent_execute(self, client):
|
||||||
"""简单任务 → dispatch + spawn 成功(dry_run 模式)"""
|
"""简单任务 → 真实 Agent 执行 → 等待完成"""
|
||||||
tid = _tid()
|
tid = _tid()
|
||||||
resp = client.post(f"/api/projects/{self.pid}/tasks", json={
|
resp = client.post(f"/api/projects/{self.pid}/tasks", json={
|
||||||
"id": tid,
|
"id": tid,
|
||||||
"title": "E2E简单任务:echo hello",
|
"title": "E2E简单任务:echo hello",
|
||||||
"description": "请执行:echo hello",
|
"description": "请执行:echo hello,然后把输出写入黑板。这是E2E测试,完成后标记done。",
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"assignee": "zhangfei-dev",
|
"assignee": "zhangfei-dev",
|
||||||
"task_type": "coding",
|
"task_type": "coding",
|
||||||
@@ -757,25 +748,36 @@ class TestE9RealAgentDispatch:
|
|||||||
})
|
})
|
||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
|
|
||||||
# 手动触发 tick(走调度 + dry_run spawn)
|
# 手动触发 tick(走调度 + 真实 spawn)
|
||||||
ticker = self._make_ticker()
|
ticker = self._make_ticker()
|
||||||
result = asyncio.run(ticker.tick())
|
result = asyncio.run(ticker.tick())
|
||||||
|
|
||||||
# 验证 dispatch 成功(从 tick 结果 + spawner sessions)
|
# 验证 dispatch 成功
|
||||||
proj = result.get("projects", {}).get(self.pid, {})
|
proj = result.get("projects", {}).get(self.pid, {})
|
||||||
assert proj.get("status") == "ok"
|
assert proj.get("status") == "ok"
|
||||||
dispatched = proj.get("dispatched", [])
|
dispatched = proj.get("dispatched", [])
|
||||||
assert tid in dispatched, f"Task {tid} not dispatched, dispatched={dispatched}"
|
assert tid in dispatched, f"Task {tid} not dispatched, dispatched={dispatched}"
|
||||||
# 验证 dry_run spawn 有 session
|
|
||||||
assert len(self._spawner.active_sessions) > 0 or len(self._spawner._sessions) > 0
|
# 等待 Agent 完成(最多 180 秒)
|
||||||
|
db_path = self.data_root / self.pid / "blackboard.db"
|
||||||
|
bb = Blackboard(db_path)
|
||||||
|
for _ in range(36):
|
||||||
|
time.sleep(5)
|
||||||
|
t = bb.get_task(tid)
|
||||||
|
if t and t.status in ("done", "failed", "review"):
|
||||||
|
break
|
||||||
|
|
||||||
|
t = bb.get_task(tid)
|
||||||
|
assert t is not None
|
||||||
|
assert t.status != "pending", f"Agent 未被调度,状态仍为 pending"
|
||||||
|
|
||||||
def test_e92_review_task_dispatch(self, client):
|
def test_e92_review_task_dispatch(self, client):
|
||||||
"""review 任务 → dispatch + spawn 成功(dry_run 模式)"""
|
"""review 任务 → 真实 Agent 执行 → 等待完成"""
|
||||||
tid = _tid()
|
tid = _tid()
|
||||||
resp = client.post(f"/api/projects/{self.pid}/tasks", json={
|
resp = client.post(f"/api/projects/{self.pid}/tasks", json={
|
||||||
"id": tid,
|
"id": tid,
|
||||||
"title": "E2E Review:检查代码",
|
"title": "E2E Review:检查代码",
|
||||||
"description": "请查看任务描述并回复你的评审意见。",
|
"description": "请查看任务描述并回复你的评审意见。这是E2E测试,简单回复即可。",
|
||||||
"status": "pending",
|
"status": "pending",
|
||||||
"assignee": "jiangwei-infra",
|
"assignee": "jiangwei-infra",
|
||||||
"task_type": "review",
|
"task_type": "review",
|
||||||
@@ -789,7 +791,19 @@ class TestE9RealAgentDispatch:
|
|||||||
proj = result.get("projects", {}).get(self.pid, {})
|
proj = result.get("projects", {}).get(self.pid, {})
|
||||||
dispatched = proj.get("dispatched", [])
|
dispatched = proj.get("dispatched", [])
|
||||||
assert tid in dispatched, f"Review task {tid} not dispatched, dispatched={dispatched}"
|
assert tid in dispatched, f"Review task {tid} not dispatched, dispatched={dispatched}"
|
||||||
assert len(self._spawner.active_sessions) > 0 or len(self._spawner._sessions) > 0
|
|
||||||
|
# 等待 Agent 完成(最多 180 秒)
|
||||||
|
db_path = self.data_root / self.pid / "blackboard.db"
|
||||||
|
bb = Blackboard(db_path)
|
||||||
|
for _ in range(36):
|
||||||
|
time.sleep(5)
|
||||||
|
t = bb.get_task(tid)
|
||||||
|
if t and t.status in ("done", "failed", "review", "working", "claimed"):
|
||||||
|
break
|
||||||
|
|
||||||
|
t = bb.get_task(tid)
|
||||||
|
assert t is not None
|
||||||
|
assert t.status != "pending", f"Review Agent 未被调度,状态仍为 pending"
|
||||||
|
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|||||||
Reference in New Issue
Block a user