All checks were successful
CI / test (push) Successful in 3m47s
openclaw agent has no cron state; a bare 'agenteval-intelligent-worker' message made the worker skill decide then 'wait for the next tick', deadlocking (task assigned, session never created). The trigger message now demands '立即完成当前任务,不要等待下一节拍' and, when all sessions are done, delegates to agenteval-intelligent-analyst. Verified end-to-end on t480: 1h-window eval went executing -> session (2 real turns) -> close -> report -> completed, fully agent-driven, no external IM channel.
111 lines
3.8 KiB
Python
111 lines
3.8 KiB
Python
"""Lifespan scan-loop test (v1.1.0 defect fix).
|
|
|
|
`scan_and_enqueue_tasks` previously had no scheduler — the OpenClaw Worker
|
|
wakes every minute but could never pull a task. The lifespan now starts an
|
|
asyncio background task that scans executing evals every 60s. This test
|
|
verifies that on application startup the scan is actually invoked.
|
|
"""
|
|
from unittest.mock import MagicMock
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
def test_lifespan_starts_scan_loop(monkeypatch):
|
|
"""Lifespan startup must invoke the intelligent-eval scan loop once."""
|
|
import agenteval.intelligent_eval.task_queue as tq
|
|
import agenteval.web.app as app_mod
|
|
|
|
calls: list[int] = []
|
|
real_scan = tq.scan_and_enqueue_tasks
|
|
|
|
def fake_scan(session):
|
|
calls.append(1)
|
|
return real_scan(session)
|
|
|
|
# The scan loop calls get_session() to open a DB session; replace it with a
|
|
# no-op mock so the test does not touch the real SQLite file.
|
|
monkeypatch.setattr(app_mod, "get_session", lambda: MagicMock())
|
|
monkeypatch.setattr(tq, "scan_and_enqueue_tasks", fake_scan)
|
|
|
|
with TestClient(app_mod.app) as client:
|
|
assert client.get("/api/health").status_code == 200
|
|
|
|
# The background task runs immediately (before its first 60s sleep).
|
|
assert calls, "scan_and_enqueue_tasks should have been invoked on startup"
|
|
|
|
|
|
def test_trigger_worker_skips_when_no_pending(monkeypatch):
|
|
"""No pending task → no docker exec invocation."""
|
|
import asyncio
|
|
import subprocess
|
|
from unittest.mock import MagicMock
|
|
|
|
import agenteval.web.app as app_mod
|
|
|
|
calls: list = []
|
|
monkeypatch.setattr(app_mod, "_has_pending_task", lambda: False)
|
|
|
|
def fake_run(cmd, **kwargs):
|
|
calls.append(cmd)
|
|
return MagicMock(returncode=0, stderr="")
|
|
|
|
monkeypatch.setattr(subprocess, "run", fake_run)
|
|
|
|
assert asyncio.run(app_mod._trigger_intelligent_worker()) is False
|
|
assert not calls, "should not invoke docker exec when queue is empty"
|
|
|
|
|
|
def test_trigger_worker_calls_docker_exec(monkeypatch):
|
|
"""Pending task present → invoke `docker exec openclaw-eval openclaw agent`."""
|
|
import asyncio
|
|
import subprocess
|
|
from unittest.mock import MagicMock
|
|
|
|
import agenteval.web.app as app_mod
|
|
|
|
calls: list = []
|
|
monkeypatch.setattr(app_mod, "_has_pending_task", lambda: True)
|
|
|
|
def fake_run(cmd, **kwargs):
|
|
calls.append(cmd)
|
|
return MagicMock(returncode=0, stderr="")
|
|
|
|
monkeypatch.setattr(subprocess, "run", fake_run)
|
|
|
|
assert asyncio.run(app_mod._trigger_intelligent_worker()) is True
|
|
assert calls, "docker exec should be invoked"
|
|
joined = " ".join(calls[0])
|
|
assert "docker" in joined and "openclaw" in joined
|
|
assert "agenteval-intelligent-worker" in joined
|
|
assert "--agent" in joined and "main" in joined
|
|
|
|
|
|
def test_trigger_worker_msg_has_execute_semantics(monkeypatch):
|
|
"""The trigger message must instruct immediate execution (no cron state).
|
|
|
|
`openclaw agent` has no cron state; a bare skill name makes the worker
|
|
skill "decide then wait for the next tick", deadlocking. The message must
|
|
say "立即完成当前任务 / 不要等待下一节拍".
|
|
"""
|
|
import asyncio
|
|
import subprocess
|
|
from unittest.mock import MagicMock
|
|
|
|
import agenteval.web.app as app_mod
|
|
|
|
calls: list = []
|
|
monkeypatch.setattr(app_mod, "_has_pending_task", lambda: True)
|
|
|
|
def fake_run(cmd, **kwargs):
|
|
calls.append(cmd)
|
|
return MagicMock(returncode=0, stderr="")
|
|
|
|
monkeypatch.setattr(subprocess, "run", fake_run)
|
|
|
|
asyncio.run(app_mod._trigger_intelligent_worker())
|
|
joined = " ".join(calls[0])
|
|
assert "不要等待下一节拍" in joined
|
|
assert "立即完成当前任务" in joined
|
|
assert "agenteval-intelligent-worker" in joined
|
|
assert "agenteval-intelligent-analyst" in joined
|