Files
cleveragents-core/robot/helper_tool_model.py
T
brent.edwards 3d2cd05f56
CI / lint (pull_request) Successful in 15s
CI / typecheck (pull_request) Successful in 28s
CI / quality (pull_request) Successful in 16s
CI / security (pull_request) Successful in 51s
CI / build (pull_request) Successful in 21s
CI / integration_tests (pull_request) Successful in 9m6s
CI / unit_tests (pull_request) Failing after 26m29s
CI / coverage (pull_request) Successful in 8m38s
CI / docker (pull_request) Has been skipped
test(tool): add robot tool model smoke tests
2026-02-17 21:14:46 +00:00

202 lines
6.1 KiB
Python

"""Robot Framework helper for Tool/Validation domain model smoke tests.
Provides a CLI-style interface for Robot to invoke model creation and
YAML config loading. Exit code 0 = success, 1 = failure.
Usage:
python robot/helper_tool_model.py create-tool
python robot/helper_tool_model.py create-validation
python robot/helper_tool_model.py load-tool-yaml <yaml_file>
python robot/helper_tool_model.py load-validation-yaml <yaml_file>
python robot/helper_tool_model.py validate-constraints
python robot/helper_tool_model.py validate-invalid-tool
"""
from __future__ import annotations
import sys
from pathlib import Path
from typing import Any
import yaml
# Ensure the src directory is on the import path.
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
from cleveragents.domain.models.core.tool import ( # noqa: E402
Tool,
ToolCapability,
ToolSource,
ToolType,
Validation,
ValidationMode,
)
def _cmd_create_tool() -> int:
"""Create a minimal Tool and verify fields."""
tool = Tool(
name="smoke/robot-tool",
description="Robot smoke test tool",
source=ToolSource.BUILTIN,
)
assert tool.name == "smoke/robot-tool"
assert tool.namespace == "smoke"
assert tool.short_name == "robot-tool"
assert tool.source == ToolSource.BUILTIN
assert tool.tool_type == ToolType.TOOL
assert tool.timeout == 300
print(f"tool-model-ok: {tool.name}")
return 0
def _cmd_create_validation() -> int:
"""Create a Validation and verify forced constraints."""
val = Validation(
name="smoke/robot-val",
description="Robot smoke validation",
source=ToolSource.BUILTIN,
)
assert val.tool_type == ToolType.VALIDATION
assert val.capability.read_only is True
assert val.capability.writes is False
assert val.capability.checkpointable is False
assert val.mode == ValidationMode.REQUIRED
print(f"validation-model-ok: {val.name}")
return 0
def _cmd_load_tool_yaml(yaml_path: str) -> int:
"""Load a Tool from a YAML config file and verify."""
path = Path(yaml_path)
if not path.exists():
print(f"tool-yaml-fail: file not found: {yaml_path}")
return 1
with path.open() as f:
config: dict[str, Any] = yaml.safe_load(f)
tool = Tool.from_config(config)
cli_dict = tool.as_cli_dict()
assert "name" in cli_dict
assert "source" in cli_dict
assert "capability" in cli_dict
print(f"tool-yaml-ok: {tool.name} source={tool.source.value}")
return 0
def _cmd_load_validation_yaml(yaml_path: str) -> int:
"""Load a Validation from a YAML config file and verify."""
path = Path(yaml_path)
if not path.exists():
print(f"validation-yaml-fail: file not found: {yaml_path}")
return 1
with path.open() as f:
config: dict[str, Any] = yaml.safe_load(f)
val = Validation.from_config(config)
assert val.tool_type == ToolType.VALIDATION
assert val.capability.read_only is True
assert val.capability.writes is False
cli_dict = val.as_cli_dict()
assert "mode" in cli_dict
print(f"validation-yaml-ok: {val.name} mode={val.mode.value}")
return 0
def _cmd_validate_constraints() -> int:
"""Verify that Validation forces read_only and blocks writes."""
val = Validation(
name="smoke/constraint-check",
description="Constraint test",
source=ToolSource.BUILTIN,
capability=ToolCapability(writes=True, checkpointable=True),
)
# Validation must force these even when given writable capability
assert val.capability.read_only is True, "Validation must force read_only=True"
assert val.capability.writes is False, "Validation must force writes=False"
assert val.capability.checkpointable is False, (
"Validation must force checkpointable=False"
)
print("validate-constraints-ok")
return 0
def _cmd_validate_invalid_tool() -> int:
"""Verify that invalid tool config is rejected."""
from pydantic import ValidationError
# Test: invalid name pattern
try:
Tool(
name="no-namespace",
description="Bad name",
source=ToolSource.BUILTIN,
)
print("validate-invalid-unexpected-success: bad name accepted")
return 1
except ValidationError:
pass
# Test: custom source without code
try:
Tool(
name="local/test",
description="Missing code",
source=ToolSource.CUSTOM,
)
print("validate-invalid-unexpected-success: missing code accepted")
return 1
except ValidationError:
pass
# Test: read_only with writes
try:
ToolCapability(read_only=True, writes=True)
print("validate-invalid-unexpected-success: read_only+writes accepted")
return 1
except ValidationError:
pass
print("validate-invalid-ok")
return 0
def main() -> int:
"""Entry point called by Robot Framework ``Run Process``."""
if len(sys.argv) < 2:
print(
"Usage: helper_tool_model.py "
"<create-tool|create-validation|load-tool-yaml|"
"load-validation-yaml|validate-constraints|validate-invalid-tool> "
"[args...]"
)
return 1
command = sys.argv[1]
if command == "create-tool":
return _cmd_create_tool()
if command == "create-validation":
return _cmd_create_validation()
if command == "load-tool-yaml":
if len(sys.argv) < 3:
print("Usage: helper_tool_model.py load-tool-yaml <file>")
return 1
return _cmd_load_tool_yaml(sys.argv[2])
if command == "load-validation-yaml":
if len(sys.argv) < 3:
print("Usage: helper_tool_model.py load-validation-yaml <file>")
return 1
return _cmd_load_validation_yaml(sys.argv[2])
if command == "validate-constraints":
return _cmd_validate_constraints()
if command == "validate-invalid-tool":
return _cmd_validate_invalid_tool()
print(f"Unknown command: {command}")
return 1
if __name__ == "__main__":
sys.exit(main())