"""Step definitions for a2a_cli_facade_integration.feature. Tests the integration between CLI commands and the A2A local facade, verifying that the facade bootstrap, dispatch helpers, and notification wrappers work correctly. """ from __future__ import annotations from typing import Any from unittest.mock import MagicMock, patch from behave import given, then, when try: from cleveragents.a2a.cli_bootstrap import get_facade, reset_facade from cleveragents.a2a.facade import A2aLocalFacade from cleveragents.a2a.models import A2aRequest except ImportError: pass # a2a module not available # --------------------------------------------------------------------------- # Given # --------------------------------------------------------------------------- @given("a facade created via the CLI bootstrap") def step_create_bootstrap_facade(context: Any) -> None: reset_facade() context.facade = get_facade() @given("a facade with a mock session service") def step_facade_with_mock_session(context: Any) -> None: mock_session_svc = MagicMock() mock_session_svc.create.return_value = MagicMock( session_id="test-session-001", actor_name="stub", ) context.facade = A2aLocalFacade(services={"session_service": mock_session_svc}) @given("a facade with a mock plan lifecycle service") def step_facade_with_mock_plan(context: Any) -> None: mock_plan_svc = MagicMock() mock_plan_svc.get_plan.return_value = MagicMock( identity=MagicMock(plan_id="test-plan-001"), phase=MagicMock(value="execute"), state=MagicMock(value="complete"), ) context.facade = A2aLocalFacade(services={"plan_lifecycle_service": mock_plan_svc}) @given("a facade that raises an error on dispatch") def step_facade_raises_error(context: Any) -> None: context.error_facade = MagicMock(spec=A2aLocalFacade) context.error_facade.dispatch.side_effect = RuntimeError("test error") # --------------------------------------------------------------------------- # When # --------------------------------------------------------------------------- @when("I dispatch a session.create operation via the CLI facade helper") def step_dispatch_session_create(context: Any) -> None: request = A2aRequest(method="session.create", params={"actor": "stub"}) context.response = context.facade.dispatch(request) @when("I dispatch a plan.create operation via the CLI facade helper") def step_dispatch_plan_create(context: Any) -> None: request = A2aRequest(method="plan.create", params={"action_name": "test"}) context.response = context.facade.dispatch(request) @when("I dispatch a plan.execute operation via the CLI facade helper") def step_dispatch_plan_execute(context: Any) -> None: request = A2aRequest(method="plan.execute", params={"plan_id": "test-plan-001"}) context.response = context.facade.dispatch(request) @when("I dispatch a plan.apply operation via the CLI facade helper") def step_dispatch_plan_apply(context: Any) -> None: request = A2aRequest(method="plan.apply", params={"plan_id": "test-plan-001"}) context.response = context.facade.dispatch(request) @when("I dispatch a plan.status operation via the CLI facade helper") def step_dispatch_plan_status(context: Any) -> None: request = A2aRequest(method="plan.status", params={"plan_id": "test-plan-001"}) context.response = context.facade.dispatch(request) @when("I dispatch a plan.diff operation via the CLI facade helper") def step_dispatch_plan_diff(context: Any) -> None: request = A2aRequest(method="plan.diff", params={"plan_id": "test-plan-001"}) context.response = context.facade.dispatch(request) @when('I call the plan notify_facade helper with operation "{operation}"') def step_call_notify_facade(context: Any, operation: str) -> None: # Patch the bootstrap module so _notify_facade gets the error facade with patch( "cleveragents.a2a.cli_bootstrap.get_facade", return_value=context.error_facade, ): from cleveragents.a2a.cli_bootstrap import reset_facade reset_facade() from cleveragents.cli.commands.plan import _notify_facade # This should not raise even though the facade errors context.notify_exception = None try: _notify_facade(operation, {"plan_id": "test"}) except Exception as e: context.notify_exception = e reset_facade() # --------------------------------------------------------------------------- # Then # --------------------------------------------------------------------------- @then("the facade should support all 42 operations") def step_check_42_operations(context: Any) -> None: ops = context.facade.list_operations() assert len(ops) == 42, f"Expected 42 operations, got {len(ops)}: {ops}" @then("the facade should be cached on subsequent calls") def step_check_facade_cached(context: Any) -> None: facade2 = get_facade() assert facade2 is context.facade, "Facade should be the same cached instance" reset_facade() @then("the facade should return an ok response") def step_check_ok_response(context: Any) -> None: assert context.response.error is None, ( f"Expected no error, got error: {context.response.error}" ) @then("no exception should propagate to the caller") def step_check_no_exception(context: Any) -> None: assert context.notify_exception is None, ( f"Expected no exception, got: {context.notify_exception}" )