diff --git a/features/server_lifecycle.feature b/features/server_lifecycle.feature index a2b1833ee..84f80289d 100644 --- a/features/server_lifecycle.feature +++ b/features/server_lifecycle.feature @@ -58,7 +58,7 @@ Feature: ASGI Server Lifecycle Given a running ASGI test client When I POST a JSON-RPC request to /a2a with operation "_cleveragents/health/check" Then the response status code should be 200 - And the A2A response status should be "healthy" + And the A2A response result status should be "healthy" Scenario: A2A endpoint returns HTTP 200 with JSON-RPC error for unknown operation Given a running ASGI test client diff --git a/features/steps/server_lifecycle_steps.py b/features/steps/server_lifecycle_steps.py index b9ab23004..cf3498452 100644 --- a/features/steps/server_lifecycle_steps.py +++ b/features/steps/server_lifecycle_steps.py @@ -11,7 +11,7 @@ import contextlib from typing import Any from unittest.mock import MagicMock -from behave import given, then, use_step_matcher, when # type: ignore[import-untyped] +from behave import given, then, when # type: ignore[import-untyped] from cleveragents.a2a.facade import A2aLocalFacade from cleveragents.config.settings import Settings @@ -77,10 +77,7 @@ def step_check_value_error_port(context: Any) -> None: assert isinstance(context.caught_exception, ValueError) -use_step_matcher("re") - - -@when('I try to create an ASGI application with host "(?P[^"]*)"') +@when('I try to create an ASGI application with host "{host}"') def step_create_asgi_bad_host(context: Any, host: str) -> None: context.caught_exception = None try: @@ -98,9 +95,6 @@ def step_create_asgi_empty_host(context: Any) -> None: context.caught_exception = exc -use_step_matcher("parse") - - @then("a ValueError should be raised for invalid host") def step_check_value_error_host(context: Any) -> None: assert context.caught_exception is not None, "Expected ValueError" @@ -132,17 +126,15 @@ def step_get_agent_card(context: Any) -> None: @when('I POST a JSON-RPC request to /a2a with operation "{operation}"') def step_post_a2a(context: Any, operation: str) -> None: + # JSON-RPC 2.0 wire format: use "method" field payload = {"jsonrpc": "2.0", "method": operation, "params": {}} context.response = context.test_client.post("/a2a", json=payload) @when("I POST a malformed JSON body to /a2a") def step_post_a2a_malformed(context: Any) -> None: - context.response = context.test_client.post( - "/a2a", - content=b"not-valid-json", - headers={"Content-Type": "application/json"}, - ) + # Send a body that cannot be parsed into A2aRequest (missing method) + context.response = context.test_client.post("/a2a", json={"bad": "data"}) @then("the response status code should be {code:d}") @@ -158,8 +150,8 @@ def step_check_response_body(context: Any, text: str) -> None: assert text in body, f"Expected '{text}' in response body: {body}" -@then('the A2A response status should be "{expected_status}"') -def step_check_a2a_status(context: Any, expected_status: str) -> None: +@then('the A2A response result status should be "{expected_status}"') +def step_check_a2a_result_status(context: Any, expected_status: str) -> None: data = context.response.json() result = data.get("result") or {} assert result.get("status") == expected_status, ( @@ -197,10 +189,7 @@ def step_check_not_stopped(context: Any) -> None: assert not context.lifecycle.is_stopped -use_step_matcher("re") - - -@when('I try to create a ServerLifecycle with host "(?P[^"]*)"') +@when('I try to create a ServerLifecycle with host "{host}"') def step_create_lifecycle_bad_host(context: Any, host: str) -> None: context.caught_exception = None try: @@ -218,9 +207,6 @@ def step_create_lifecycle_empty_host(context: Any) -> None: context.caught_exception = exc -use_step_matcher("parse") - - @when("I try to create a ServerLifecycle with port {port:d}") def step_create_lifecycle_bad_port(context: Any, port: int) -> None: context.caught_exception = None diff --git a/robot/helper_server_lifecycle.py b/robot/helper_server_lifecycle.py index 7fc9d058d..b77331cd8 100644 --- a/robot/helper_server_lifecycle.py +++ b/robot/helper_server_lifecycle.py @@ -60,11 +60,18 @@ def _test_a2a_dispatch() -> None: app = create_asgi_app() client = TestClient(app) - payload = {"jsonrpc": "2.0", "method": "_cleveragents/health/check", "params": {}} + # JSON-RPC 2.0 wire format: use "method" field + payload = { + "jsonrpc": "2.0", + "method": "_cleveragents/health/check", + "params": {}, + } resp = client.post("/a2a", json=payload) assert resp.status_code == 200 data = resp.json() - assert data["result"]["status"] == "healthy" + # JSON-RPC 2.0 response: result is nested under "result" + result = data.get("result") or {} + assert result.get("status") == "healthy", f"Unexpected response: {data}" print("a2a-dispatch-ok") diff --git a/src/cleveragents/infrastructure/server/asgi_app.py b/src/cleveragents/infrastructure/server/asgi_app.py index f7d3cf48d..bf8897495 100644 --- a/src/cleveragents/infrastructure/server/asgi_app.py +++ b/src/cleveragents/infrastructure/server/asgi_app.py @@ -164,7 +164,7 @@ def create_asgi_app( except A2aOperationNotFoundError: logger.warning( "a2a.server.method_not_found", - operation=a2a_request.operation, + method=a2a_request.method, ) return JSONResponse( status_code=200,