Files
cleveragents-core/robot/helper_actor_remove_cli.py
T
HAL9000 8384f53e28 test(cli): cover actor remove format regression (#6491)
Add Robot regression coverage for `actor remove --format json`, document the flag in the CLI synopsis, and record the fix in the changelog.\n\nISSUES CLOSED: #6491
2026-05-06 01:07:15 +00:00

121 lines
3.6 KiB
Python

"""Helper script for Robot tests covering ``actor remove --format`` output."""
from __future__ import annotations
import json
import sys
from typing import Any
from unittest.mock import MagicMock, patch
from typer.testing import CliRunner
from cleveragents.cli.commands.actor import app as actor_app
from cleveragents.domain.models.core.actor import Actor
def _make_actor(
*,
name: str = "local/robot-remove-actor",
provider: str = "openai",
model: str = "gpt-4",
config: dict[str, Any] | None = None,
graph_descriptor: dict[str, Any] | None = None,
unsafe: bool = False,
is_default: bool = False,
is_built_in: bool = False,
) -> Actor:
"""Create a minimal :class:`Actor` instance for CLI testing."""
blob = config or {}
return Actor(
id=1,
name=name,
provider=provider,
model=model,
config_blob=blob,
config_hash=Actor.compute_hash(blob),
graph_descriptor=graph_descriptor,
unsafe=unsafe,
is_default=is_default,
is_built_in=is_built_in,
)
def _invoke_actor_remove(actor: Actor, *, impact: tuple[int, int, int]) -> str:
"""Invoke ``actor remove`` with Typer's :class:`CliRunner` and return stdout."""
runner = CliRunner()
with (
patch("cleveragents.cli.commands.actor._get_services") as mock_services,
patch("cleveragents.cli.commands.actor._compute_actor_impact") as mock_impact,
):
registry = MagicMock()
service = MagicMock()
registry.get_actor.return_value = actor
mock_services.return_value = (service, registry)
mock_impact.return_value = impact
result = runner.invoke(
actor_app,
["remove", actor.name, "--format", "json"],
)
assert result.exit_code == 0, (
"actor remove --format json failed"
f" (exit_code={result.exit_code}):\n{result.output}"
)
return result.output
def test_remove_format_json() -> None:
"""Ensure ``actor remove --format json`` emits a spec-compliant envelope."""
actor = _make_actor()
impact = (2, 1, 3)
output = _invoke_actor_remove(actor, impact=impact)
payload = json.loads(output.strip())
assert payload["command"] == f"agents actor remove {actor.name}", payload
assert payload["status"] == "ok", payload
assert payload["exit_code"] == 0, payload
data = payload["data"]
removed = data.get("actor_removed", {})
assert removed.get("name") == actor.name, removed
assert removed.get("provider") == actor.provider, removed
assert removed.get("model") == actor.model, removed
impact_section = data.get("impact", {})
assert impact_section.get("sessions") == impact[0], impact_section
assert impact_section.get("active_plans") == impact[1], impact_section
assert impact_section.get("actions_referencing") == impact[2], impact_section
cleanup = data.get("cleanup", {})
assert cleanup.get("config") == "kept on disk", cleanup
assert cleanup.get("contexts") == "0 orphaned", cleanup
messages = payload.get("messages", [])
assert messages, payload
assert messages[0].get("level") == "ok", messages
assert "Actor removed" in messages[0].get("text", ""), messages
print("actor-remove-json-format-ok")
def main() -> None:
command = sys.argv[1] if len(sys.argv) > 1 else "remove-json"
dispatch: dict[str, Any] = {
"remove-json": test_remove_format_json,
}
handler = dispatch.get(command)
if handler is None:
print(f"Unknown command: {command}", file=sys.stderr)
sys.exit(1)
handler()
if __name__ == "__main__":
main()