Files
cleveragents-core/robot/helper_a2a_facade_wiring.py
freemo ec0b7631d0 refactor(a2a): rename ACP module and symbols to A2A standard
Renamed src/cleveragents/acp/ to src/cleveragents/a2a/ and all 13
Acp* classes to A2a* per ADR-047 (A2A Standard Adoption). Updated
all imports, structlog event names (acp.* → a2a.*), field names
(acp_version → a2a_version), and test references across the entire
codebase. This is a cosmetic rename only — no behavioral changes.

ISSUES CLOSED: #688
2026-03-12 14:38:57 +00:00

264 lines
8.1 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(operation="session.create"))
if resp.status == "ok" and resp.data["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(
operation="session.close",
params={"session_id": "INTEG-SESSION-001"},
)
)
if resp.status == "ok" and resp.data["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(
operation="plan.create",
params={"action_name": "local/test"},
)
)
if resp.status == "ok" and resp.data["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(
operation="plan.status",
params={"plan_id": "INTEG-PLAN-001"},
)
)
if resp.status == "ok" and resp.data["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(operation="registry.list_tools"))
tools = resp.data.get("tools", [])
if resp.status == "ok" 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(operation="registry.list_resources"))
resources = resp.data.get("resources", [])
if resp.status == "ok" 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(operation="context.get"))
if resp.status == "ok" and resp.data.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(operation="event.subscribe"))
sub_id = resp.data.get("subscription_id", "")
if resp.status == "ok" 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."""
cases: list[tuple[Exception, str]] = [
(ResourceNotFoundError(resource_type="x", resource_id="1"), "NOT_FOUND"),
(ValidationError("bad"), "VALIDATION_ERROR"),
(PlanError("fail"), "PLAN_ERROR"),
(BusinessRuleViolation("invalid"), "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()