Files
cleveragents-core/robot/helper_tool_cli.py
T

211 lines
6.2 KiB
Python

"""Helper script for tool_cli.robot smoke tests.
Each subcommand is a self-contained check that prints a sentinel on success.
"""
from __future__ import annotations
import os
import sys
import tempfile
from pathlib import Path
from typing import Any
from unittest.mock import MagicMock, patch
# Ensure local source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
from typer.testing import CliRunner # noqa: E402
from cleveragents.cli.commands.tool import app as tool_app # noqa: E402
from cleveragents.cli.commands.validation import app as validation_app # noqa: E402
runner = CliRunner()
_TOOL_YAML = """\
name: local/smoke-tool
description: Smoke test tool
source: custom
code: |
def run(inputs):
return {"result": True}
"""
_VALIDATION_YAML = """\
name: local/smoke-val
description: Smoke test validation
source: custom
mode: required
code: |
def run(inputs):
return {"passed": True}
"""
def _mock_tool(
name: str = "local/smoke-tool",
tool_type: str = "tool",
) -> dict[str, Any]:
ns, sn = name.split("/", 1)
return {
"name": name,
"description": f"Smoke test {tool_type}",
"source": "custom",
"tool_type": tool_type,
"namespace": ns,
"short_name": sn,
"capability": {"read_only": False, "writes": False, "checkpointable": False},
"timeout": 300,
}
def _mock_attachment() -> dict[str, Any]:
return {
"attachment_id": "att-smoke-001",
"validation_name": "local/smoke-val",
"resource_id": "resource/r1",
"mode": "required",
"project_name": None,
"plan_id": None,
"created_at": "2026-01-01T00:00:00",
}
def _write_yaml(content: str) -> str:
fd, path = tempfile.mkstemp(suffix=".yaml")
with os.fdopen(fd, "w") as fh:
fh.write(content)
return path
# ---------------------------------------------------------------------------
# Subcommands
# ---------------------------------------------------------------------------
def tool_add_config() -> None:
"""Verify tool add --config works."""
path = _write_yaml(_TOOL_YAML)
try:
svc = MagicMock()
svc.register_tool.return_value = _mock_tool()
svc.get_tool.return_value = None
with patch(
"cleveragents.cli.commands.tool._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(tool_app, ["add", "--config", path])
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("tool-cli-add-config-ok")
finally:
Path(path).unlink(missing_ok=True)
def tool_list_all() -> None:
"""Verify tool list works."""
svc = MagicMock()
svc.list_tools.return_value = [_mock_tool()]
with patch(
"cleveragents.cli.commands.tool._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(tool_app, ["list"])
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("tool-cli-list-ok")
def tool_show_name() -> None:
"""Verify tool show accepts a namespaced name."""
svc = MagicMock()
svc.get_tool.return_value = _mock_tool()
with patch(
"cleveragents.cli.commands.tool._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(tool_app, ["show", "local/smoke-tool"])
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("tool-cli-show-ok")
def tool_remove_name() -> None:
"""Verify tool remove accepts a namespaced name."""
svc = MagicMock()
svc.get_tool.return_value = _mock_tool()
svc.remove_tool.return_value = True
with patch(
"cleveragents.cli.commands.tool._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(tool_app, ["remove", "local/smoke-tool", "--yes"])
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("tool-cli-remove-ok")
def validation_add_config() -> None:
"""Verify validation add --config works."""
path = _write_yaml(_VALIDATION_YAML)
try:
svc = MagicMock()
svc.register_tool.return_value = _mock_tool("local/smoke-val", "validation")
svc.get_tool.return_value = None
with patch(
"cleveragents.cli.commands.validation._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(validation_app, ["add", "--config", path])
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("validation-cli-add-ok")
finally:
Path(path).unlink(missing_ok=True)
def validation_attach() -> None:
"""Verify validation attach works."""
svc = MagicMock()
svc.attach_validation.return_value = _mock_attachment()
with patch(
"cleveragents.cli.commands.validation._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(
validation_app,
["attach", "resource/r1", "local/smoke-val"],
)
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("validation-cli-attach-ok")
def validation_detach() -> None:
"""Verify validation detach works."""
svc = MagicMock()
svc.detach_validation.return_value = True
with patch(
"cleveragents.cli.commands.validation._get_tool_registry_service",
return_value=svc,
):
result = runner.invoke(
validation_app,
["detach", "att-smoke-001", "--yes"],
)
assert result.exit_code == 0, f"exit={result.exit_code}: {result.output}"
print("validation-cli-detach-ok")
_COMMANDS = {
"tool-add-config": tool_add_config,
"tool-list": tool_list_all,
"tool-show": tool_show_name,
"tool-remove": tool_remove_name,
"validation-add-config": validation_add_config,
"validation-attach": validation_attach,
"validation-detach": validation_detach,
}
if __name__ == "__main__":
if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
print(f"Usage: {sys.argv[0]} <{'|'.join(_COMMANDS)}>")
sys.exit(1)
_COMMANDS[sys.argv[1]]()