oclaw/tests/test_chat_jobs_api.py
oliver 0cf6aafa30 Add background jobs with Chat UI so long agent scripts can run for hours safely.
start_job/get_job/sleep replace blocked run_command for multi-hour work; Chat shows a live count badge and allows manual kill, with a reaper reclaiming timed-out or stale processes.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-23 01:02:57 +08:00

57 lines
1.9 KiB
Python

from __future__ import annotations
from fastapi import FastAPI
from fastapi.testclient import TestClient
from interfaces.admin.chat_api import include_chat_routes
from svc.jobs.background_jobs import BackgroundJobStore
def test_chat_jobs_api_list_cancel_purge(tmp_path, monkeypatch) -> None:
store = BackgroundJobStore(root_dir=tmp_path / "jobs")
monkeypatch.setattr("svc.jobs.background_jobs.get_job_store", lambda root_dir=None: store)
# Also patch the import site used inside route handlers
import svc.jobs.background_jobs as bj
monkeypatch.setattr(bj, "get_job_store", lambda root_dir=None: store)
class _FakeSqlite:
pass
def _resolve_auth(_store, _auth):
return {"tenant_id": "t1", "user_id": "u1", "username": "u1"}
monkeypatch.setattr("interfaces.admin.chat_api.get_assistant_store", lambda: _FakeSqlite())
app = FastAPI()
from fastapi import APIRouter
router = APIRouter()
include_chat_routes(router, resolve_auth=_resolve_auth)
app.include_router(router)
client = TestClient(app)
started = store.start(command="echo hi", cwd=str(tmp_path), timeout_s=5, name="ui-job")
assert started.get("ok") is True
job_id = started["job_id"]
r = client.get("/admin/api/chat/jobs", headers={"Authorization": "Bearer x"})
assert r.status_code == 200
body = r.json()
assert body.get("ok") is True
assert any(j.get("job_id") == job_id for j in body.get("jobs") or [])
# wait finish then purge
import time
deadline = time.time() + 8
while time.time() < deadline:
g = store.get(job_id)
if g.get("done"):
break
time.sleep(0.05)
assert store.get(job_id).get("done") is True
d = client.delete(f"/admin/api/chat/jobs/{job_id}", headers={"Authorization": "Bearer x"})
assert d.status_code == 200
assert d.json().get("purged") is True