oclaw/tests/test_report_first_and_ne_exec_async.py
oliver 4827278a9c Enforce report-first short intents and async large execManagedNe batches.
Block CLI/inventory until ume_alarm_xlsx_report (or aggregate) succeeds, and return job_id for big NE batches via get_ne_exec_job.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 22:17:16 +08:00

110 lines
3.4 KiB
Python

from __future__ import annotations
import time
from pathlib import Path
from runtime.chat.ops_report_first_guard import (
maybe_block_cli_before_report,
report_first_block_payload,
)
from svc.jobs.ne_exec_jobs import (
count_exec_ne_targets,
get_ne_exec_job,
should_run_exec_managed_ne_async,
start_ne_exec_job,
strip_async_flag,
)
def test_report_first_blocks_cli_before_report() -> None:
blocked = maybe_block_cli_before_report(
tool_name="mcp__netx__execManagedNe",
intent="fiber_cut",
store=None,
session_id="",
turn_uuid="",
lang="en",
local_report_ok=False,
)
assert blocked is not None
assert blocked["error_code"] == "report_first_required"
assert blocked["next_tool"] == "ume_alarm_xlsx_report"
def test_report_first_allows_after_local_ok() -> None:
assert (
maybe_block_cli_before_report(
tool_name="mcp__netx__listCliTargets",
intent="offline",
store=None,
session_id="s",
turn_uuid="t",
local_report_ok=True,
)
is None
)
def test_report_first_ignores_non_report_intents() -> None:
assert (
maybe_block_cli_before_report(
tool_name="mcp__netx__execManagedNe",
intent="continue",
store=None,
session_id="",
turn_uuid="",
local_report_ok=False,
)
is None
)
def test_report_first_payload_zh() -> None:
out = report_first_block_payload(intent="fiber_cut", lang="zh")
assert "ume_alarm_xlsx_report" in out["hint"]
assert out["example"].get("mode") == "fiber_cut"
def test_should_async_by_ne_count(monkeypatch) -> None:
monkeypatch.setenv("AIA_EXEC_MANAGED_NE_ASYNC_MIN_NES", "4")
assert not should_run_exec_managed_ne_async({"ume_ne_ids": ["a", "b", "c"], "commands": ["show"]})
assert should_run_exec_managed_ne_async({"ume_ne_ids": ["a", "b", "c", "d"], "commands": ["show"]})
assert should_run_exec_managed_ne_async({"async": True, "ume_ne_id": "x", "commands": ["show"]})
assert not should_run_exec_managed_ne_async(
{"async": False, "ume_ne_ids": ["a", "b", "c", "d", "e"], "commands": ["show"]}
)
def test_count_and_strip_async() -> None:
assert count_exec_ne_targets({"targets": [{"ume_ne_id": "1", "commands": ["a"]}, {"ne_id": "2", "commands": ["b"]}]}) == 2
assert "async" not in strip_async_flag({"async": True, "commands": ["x"]})
def test_ne_exec_job_roundtrip(tmp_path: Path, monkeypatch) -> None:
monkeypatch.setenv("AIA_NE_EXEC_JOB_DIR", str(tmp_path))
def _runner() -> dict:
time.sleep(0.05)
return {"ok": True, "data": {"results": [1]}}
ack = start_ne_exec_job(
tool_name="mcp__netx__execManagedNe",
arguments={"ume_ne_ids": ["a", "b", "c", "d"], "commands": ["show version"]},
runner=_runner,
session_id="sess",
)
assert ack["ok"] is True
assert ack["async"] is True
jid = ack["job_id"]
deadline = time.time() + 2.0
status = ""
while time.time() < deadline:
polled = get_ne_exec_job(jid)
status = str(polled.get("status") or "")
if status in {"succeeded", "failed", "timeout"}:
break
time.sleep(0.05)
assert status == "succeeded"
done = get_ne_exec_job(jid)
assert done["terminal"] is True
assert done["result"]["ok"] is True