8ea00f5185
CI / unit_tests (push) Has been cancelled
CI / benchmark-publish (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / typecheck (push) Has been cancelled
CI / security (push) Has been cancelled
CI / quality (push) Has been cancelled
CI / integration_tests (push) Has been cancelled
CI / e2e_tests (push) Has been cancelled
CI / coverage (push) Has been cancelled
CI / benchmark-regression (push) Has been cancelled
CI / build (push) Has been cancelled
CI / push-validation (push) Has been cancelled
CI / status-check (push) Has been cancelled
CI / docker (push) Has been cancelled
CI / helm (push) Has been cancelled
Co-authored-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me> Co-committed-by: Jeffrey Phillips Freeman <the@jeffreyfreeman.me>
269 lines
8.3 KiB
Python
269 lines
8.3 KiB
Python
"""Helper script for a2a_facade_wiring.robot integration tests.
|
|
|
|
Each subcommand exercises the wired A2A facade with lightweight mock
|
|
services and prints a sentinel on success.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock
|
|
|
|
# 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 cleveragents.a2a.errors import ( # noqa: E402
|
|
map_domain_error,
|
|
)
|
|
from cleveragents.a2a.events import A2aEventQueue # noqa: E402
|
|
from cleveragents.a2a.facade import A2aLocalFacade # noqa: E402
|
|
from cleveragents.a2a.models import A2aRequest # noqa: E402
|
|
from cleveragents.core.exceptions import ( # noqa: E402
|
|
BusinessRuleViolation,
|
|
PlanError,
|
|
ResourceNotFoundError,
|
|
ValidationError,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Mock helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class _MockSession:
|
|
def __init__(self) -> None:
|
|
self.session_id = "INTEG-SESSION-001"
|
|
|
|
|
|
class _MockPlanIdentity:
|
|
def __init__(self) -> None:
|
|
self.plan_id = "INTEG-PLAN-001"
|
|
|
|
|
|
class _MockPlan:
|
|
def __init__(self) -> None:
|
|
self.identity = _MockPlanIdentity()
|
|
self.phase = MagicMock()
|
|
self.phase.value = "strategize"
|
|
self.state = MagicMock()
|
|
self.state.value = "queued"
|
|
|
|
|
|
class _MockToolSpec:
|
|
def __init__(self, name: str, description: str) -> None:
|
|
self.name = name
|
|
self.description = description
|
|
|
|
|
|
class _MockResource:
|
|
def __init__(self) -> None:
|
|
self.resource_id = "RES-001"
|
|
self.name = "test-resource"
|
|
self.resource_type_name = "git-checkout"
|
|
|
|
|
|
def _mock_session_service() -> MagicMock:
|
|
svc = MagicMock()
|
|
svc.create.return_value = _MockSession()
|
|
svc.delete.return_value = None
|
|
return svc
|
|
|
|
|
|
def _mock_plan_lifecycle_service() -> MagicMock:
|
|
svc = MagicMock()
|
|
svc.use_action.return_value = _MockPlan()
|
|
svc.execute_plan.return_value = _MockPlan()
|
|
svc.get_plan.return_value = _MockPlan()
|
|
svc.apply_plan.return_value = _MockPlan()
|
|
return svc
|
|
|
|
|
|
def _mock_tool_registry() -> MagicMock:
|
|
reg = MagicMock()
|
|
reg.list_tools.return_value = [
|
|
_MockToolSpec("local/echo", "Echo tool"),
|
|
]
|
|
return reg
|
|
|
|
|
|
def _mock_resource_registry_service() -> MagicMock:
|
|
svc = MagicMock()
|
|
svc.list_resources.return_value = [_MockResource()]
|
|
return svc
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Subcommands
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def wired_session_create() -> None:
|
|
"""Dispatch session.create through a wired facade."""
|
|
facade = A2aLocalFacade(services={"session_service": _mock_session_service()})
|
|
resp = facade.dispatch(A2aRequest(method="session.create"))
|
|
if resp.result is not None and resp.result["session_id"] == "INTEG-SESSION-001":
|
|
print("a2a-wired-session-create-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_session_close() -> None:
|
|
"""Dispatch session.close through a wired facade."""
|
|
facade = A2aLocalFacade(services={"session_service": _mock_session_service()})
|
|
resp = facade.dispatch(
|
|
A2aRequest(
|
|
method="session.close",
|
|
params={"session_id": "INTEG-SESSION-001"},
|
|
)
|
|
)
|
|
if resp.result is not None and resp.result["status"] == "closed":
|
|
print("a2a-wired-session-close-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_plan_create() -> None:
|
|
"""Dispatch plan.create through a wired facade."""
|
|
facade = A2aLocalFacade(
|
|
services={"plan_lifecycle_service": _mock_plan_lifecycle_service()}
|
|
)
|
|
resp = facade.dispatch(
|
|
A2aRequest(
|
|
method="plan.create",
|
|
params={"action_name": "local/test"},
|
|
)
|
|
)
|
|
if resp.result is not None and resp.result["plan_id"] == "INTEG-PLAN-001":
|
|
print("a2a-wired-plan-create-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_plan_status() -> None:
|
|
"""Dispatch plan.status through a wired facade."""
|
|
facade = A2aLocalFacade(
|
|
services={"plan_lifecycle_service": _mock_plan_lifecycle_service()}
|
|
)
|
|
resp = facade.dispatch(
|
|
A2aRequest(
|
|
method="plan.status",
|
|
params={"plan_id": "INTEG-PLAN-001"},
|
|
)
|
|
)
|
|
if resp.result is not None and resp.result["phase"] == "strategize":
|
|
print("a2a-wired-plan-status-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_registry_tools() -> None:
|
|
"""Dispatch registry.list_tools through a wired facade."""
|
|
facade = A2aLocalFacade(services={"tool_registry": _mock_tool_registry()})
|
|
resp = facade.dispatch(A2aRequest(method="registry.list_tools"))
|
|
tools = resp.result.get("tools", []) if resp.result is not None else []
|
|
if resp.result is not None and len(tools) == 1:
|
|
print("a2a-wired-registry-tools-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_registry_resources() -> None:
|
|
"""Dispatch registry.list_resources through a wired facade."""
|
|
facade = A2aLocalFacade(
|
|
services={"resource_registry_service": _mock_resource_registry_service()}
|
|
)
|
|
resp = facade.dispatch(A2aRequest(method="registry.list_resources"))
|
|
resources = resp.result.get("resources", []) if resp.result is not None else []
|
|
if resp.result is not None and len(resources) == 1:
|
|
print("a2a-wired-registry-resources-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_context_stub() -> None:
|
|
"""Dispatch context.get and verify stub response."""
|
|
facade = A2aLocalFacade()
|
|
resp = facade.dispatch(A2aRequest(method="context.get"))
|
|
if resp.result is not None and resp.result.get("stub") is True:
|
|
print("a2a-wired-context-stub-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_event_subscribe() -> None:
|
|
"""Dispatch event.subscribe through a wired facade."""
|
|
queue = A2aEventQueue()
|
|
facade = A2aLocalFacade(services={"event_queue": queue})
|
|
resp = facade.dispatch(A2aRequest(method="event.subscribe"))
|
|
sub_id = resp.result.get("subscription_id", "") if resp.result is not None else ""
|
|
if resp.result is not None and sub_id:
|
|
print("a2a-wired-event-subscribe-ok")
|
|
else:
|
|
print(f"FAIL: {resp}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def wired_error_mapping() -> None:
|
|
"""Verify domain-to-A2A error code mapping."""
|
|
from cleveragents.a2a import errors as _a2a_errors
|
|
|
|
cases: list[tuple[Exception, int]] = [
|
|
(
|
|
ResourceNotFoundError(resource_type="x", resource_id="1"),
|
|
_a2a_errors.NOT_FOUND,
|
|
),
|
|
(ValidationError("bad"), _a2a_errors.VALIDATION_ERROR),
|
|
(PlanError("fail"), _a2a_errors.PLAN_ERROR),
|
|
(BusinessRuleViolation("invalid"), _a2a_errors.INVALID_STATE),
|
|
]
|
|
for exc, expected_code in cases:
|
|
code, _ = map_domain_error(exc)
|
|
if code != expected_code:
|
|
print(
|
|
f"FAIL: expected {expected_code} for {type(exc).__name__}, got {code}",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
print("a2a-wired-error-mapping-ok")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Dispatch
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_COMMANDS: dict[str, object] = {
|
|
"wired-session-create": wired_session_create,
|
|
"wired-session-close": wired_session_close,
|
|
"wired-plan-create": wired_plan_create,
|
|
"wired-plan-status": wired_plan_status,
|
|
"wired-registry-tools": wired_registry_tools,
|
|
"wired-registry-resources": wired_registry_resources,
|
|
"wired-context-stub": wired_context_stub,
|
|
"wired-event-subscribe": wired_event_subscribe,
|
|
"wired-error-mapping": wired_error_mapping,
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
if len(sys.argv) < 2 or sys.argv[1] not in _COMMANDS:
|
|
cmds = "|".join(_COMMANDS)
|
|
print(f"Usage: {sys.argv[0]} <{cmds}>", file=sys.stderr)
|
|
sys.exit(2)
|
|
fn = _COMMANDS[sys.argv[1]]
|
|
if callable(fn):
|
|
fn()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|