aps-agent/tests/golden/test_async_jobs.py

99 lines
3.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ============================================================
# 方向 F 黄金测试:轻量异步任务队列(矩阵 88 行剩余)
# 覆盖:提交/轮询/完成+结果、失败记录、取消(pending/running)、
# 取消终态返回 False、列表与统计
# ============================================================
from __future__ import annotations
import threading
import time
from server.agent_core.async_jobs import JobCancelled, JobQueue
def test_submit_poll_done_with_result():
"""提交 → 轮询 → done,result/progress/时间戳完整,poll 可重复读。"""
q = JobQueue()
job_id = q.submit(
"sensitivity.recompute",
lambda rec: {"robustness": 0.92},
params={"strategy": "COMPREHENSIVE"},
actor="planner",
)
record = q.wait(job_id, timeout=10)
assert record["status"] == "done"
assert record["result"] == {"robustness": 0.92}
assert record["progress"] == 100
assert record["params"]["strategy"] == "COMPREHENSIVE"
assert record["actor"] == "planner"
assert record["started_at"] and record["finished_at"]
again = q.poll(job_id)
assert again is not None
assert again["status"] == "done"
assert again["result"]["robustness"] == 0.92
def test_failed_job_records_error():
"""fn 抛异常 → failed,error 显式记录,result 为空。"""
q = JobQueue()
def boom(rec):
raise RuntimeError("求解器崩溃")
job_id = q.submit("montecarlo.recompute", boom)
record = q.wait(job_id, timeout=10)
assert record["status"] == "failed"
assert record["error"] == "求解器崩溃"
assert record["result"] is None
def test_cancel_running_job():
"""运行中任务可取消:置标记 → 终态 cancelled,结果丢弃。"""
q = JobQueue()
started = threading.Event()
def long_run(rec):
started.set()
while not rec.cancel_requested:
time.sleep(0.01)
raise JobCancelled()
job_id = q.submit("montecarlo.recompute", long_run)
assert started.wait(timeout=5), "任务未进入运行"
assert q.cancel(job_id) is True
record = q.wait(job_id, timeout=10)
assert record["status"] == "cancelled"
assert record["result"] is None
assert record["cancel_requested"] is True
def test_cancel_unknown_or_terminal_returns_false():
"""不存在或已终态任务取消返回 False。"""
q = JobQueue()
assert q.cancel("job-不存在") is False
job_id = q.submit("t", lambda rec: 1)
q.wait(job_id, timeout=10)
assert q.cancel(job_id) is False
assert q.poll(job_id)["status"] == "done"
def test_list_and_stats():
"""列表可按状态过滤,统计计数与终态一致。"""
q = JobQueue()
def boom(rec):
raise RuntimeError("x")
q.submit("a", lambda rec: 1)
q.submit("b", boom)
q.submit("c", lambda rec: 2)
for item in q.list():
q.wait(item["job_id"], timeout=10)
stats = q.stats()
assert stats["total"] == 3
assert stats["done"] == 2
assert stats["failed"] == 1
assert stats["pending"] == 0
failed = q.list(status="failed")
assert len(failed) == 1 and failed[0]["kind"] == "b"