11import json
2+
23from collections .abc import AsyncGenerator
34from typing import Any
45from unittest .mock import AsyncMock , MagicMock , patch
56
67import httpx
78import pytest
9+
810from httpx_sse import EventSource , ServerSentEvent
9- from pydantic import ValidationError as PydanticValidationError
10-
11- from a2a .client import (A2ACardResolver , A2AClient , A2AClientHTTPError ,
12- A2AClientJSONError , create_text_message_object )
13- from a2a .types import (A2ARequest , AgentCapabilities , AgentCard , AgentSkill ,
14- CancelTaskRequest , CancelTaskResponse ,
15- CancelTaskSuccessResponse , GetTaskRequest ,
16- GetTaskResponse , InvalidParamsError ,
17- JSONRPCErrorResponse , MessageSendParams , Role ,
18- SendMessageRequest , SendMessageResponse ,
19- SendMessageSuccessResponse , SendStreamingMessageRequest ,
20- SendStreamingMessageResponse , TaskIdParams ,
21- TaskNotCancelableError , TaskQueryParams )
11+
12+ from a2a .client import (
13+ A2ACardResolver ,
14+ A2AClient ,
15+ A2AClientHTTPError ,
16+ A2AClientJSONError ,
17+ create_text_message_object ,
18+ )
19+ from a2a .types import (
20+ A2ARequest ,
21+ AgentCapabilities ,
22+ AgentCard ,
23+ AgentSkill ,
24+ CancelTaskRequest ,
25+ CancelTaskResponse ,
26+ CancelTaskSuccessResponse ,
27+ GetTaskRequest ,
28+ GetTaskResponse ,
29+ InvalidParamsError ,
30+ JSONRPCErrorResponse ,
31+ MessageSendParams ,
32+ Role ,
33+ SendMessageRequest ,
34+ SendMessageResponse ,
35+ SendMessageSuccessResponse ,
36+ SendStreamingMessageRequest ,
37+ SendStreamingMessageResponse ,
38+ TaskIdParams ,
39+ TaskNotCancelableError ,
40+ TaskQueryParams ,
41+ )
42+
2243
2344AGENT_CARD = AgentCard (
2445 name = 'Hello World Agent' ,
@@ -100,7 +121,9 @@ class TestA2ACardResolver:
100121 BASE_URL = 'http://example.com'
101122 AGENT_CARD_PATH = '/.well-known/agent.json'
102123 FULL_AGENT_CARD_URL = f'{ BASE_URL } { AGENT_CARD_PATH } '
103- EXTENDED_AGENT_CARD_PATH = '/agent/authenticatedExtendedCard' # Default path
124+ EXTENDED_AGENT_CARD_PATH = (
125+ '/agent/authenticatedExtendedCard' # Default path
126+ )
104127
105128 @pytest .mark .asyncio
106129 async def test_init_strips_slashes (self , mock_httpx_client : AsyncMock ):
@@ -141,11 +164,12 @@ async def test_get_agent_card_success_public_only(
141164
142165 @pytest .mark .asyncio
143166 async def test_get_agent_card_success_with_specified_path_for_extended_card (
144- self , mock_httpx_client : AsyncMock ):
167+ self , mock_httpx_client : AsyncMock
168+ ):
145169 extended_card_response = AsyncMock (spec = httpx .Response )
146170 extended_card_response .status_code = 200
147- extended_card_response .json .return_value = AGENT_CARD_EXTENDED . model_dump (
148- mode = 'json'
171+ extended_card_response .json .return_value = (
172+ AGENT_CARD_EXTENDED . model_dump ( mode = 'json' )
149173 )
150174
151175 # Mock the single call for the extended card
@@ -156,20 +180,26 @@ async def test_get_agent_card_success_with_specified_path_for_extended_card(
156180 base_url = self .BASE_URL ,
157181 agent_card_path = self .AGENT_CARD_PATH ,
158182 )
159-
183+
160184 # Fetch the extended card by providing its relative path and example auth
161- auth_kwargs = {" headers" : {" Authorization" : " Bearer test token" }}
185+ auth_kwargs = {' headers' : {' Authorization' : ' Bearer test token' }}
162186 agent_card_result = await resolver .get_agent_card (
163187 relative_card_path = self .EXTENDED_AGENT_CARD_PATH ,
164- http_kwargs = auth_kwargs
188+ http_kwargs = auth_kwargs ,
165189 )
166190
167- expected_extended_url = f'{ self .BASE_URL } /{ self .EXTENDED_AGENT_CARD_PATH .lstrip ("/" )} '
168- mock_httpx_client .get .assert_called_once_with (expected_extended_url , ** auth_kwargs )
191+ expected_extended_url = (
192+ f'{ self .BASE_URL } /{ self .EXTENDED_AGENT_CARD_PATH .lstrip ("/" )} '
193+ )
194+ mock_httpx_client .get .assert_called_once_with (
195+ expected_extended_url , ** auth_kwargs
196+ )
169197 extended_card_response .raise_for_status .assert_called_once ()
170198
171199 assert isinstance (agent_card_result , AgentCard )
172- assert agent_card_result == AGENT_CARD_EXTENDED # Should return the extended card
200+ assert (
201+ agent_card_result == AGENT_CARD_EXTENDED
202+ ) # Should return the extended card
173203
174204 @pytest .mark .asyncio
175205 async def test_get_agent_card_validation_error (
@@ -178,19 +208,29 @@ async def test_get_agent_card_validation_error(
178208 mock_response = AsyncMock (spec = httpx .Response )
179209 mock_response .status_code = 200
180210 # Data that will cause a Pydantic ValidationError
181- mock_response .json .return_value = {"invalid_field" : "value" , "name" : "Test Agent" }
211+ mock_response .json .return_value = {
212+ 'invalid_field' : 'value' ,
213+ 'name' : 'Test Agent' ,
214+ }
182215 mock_httpx_client .get .return_value = mock_response
183216
184217 resolver = A2ACardResolver (
185218 httpx_client = mock_httpx_client , base_url = self .BASE_URL
186219 )
187220 # The call that is expected to raise an error should be within pytest.raises
188221 with pytest .raises (A2AClientJSONError ) as exc_info :
189- await resolver .get_agent_card () # Fetches from default path
190-
191- assert f'Failed to validate agent card structure from { self .FULL_AGENT_CARD_URL } ' in str (exc_info .value )
192- assert 'invalid_field' in str (exc_info .value ) # Check if Pydantic error details are present
193- assert mock_httpx_client .get .call_count == 1 # Should only be called once
222+ await resolver .get_agent_card () # Fetches from default path
223+
224+ assert (
225+ f'Failed to validate agent card structure from { self .FULL_AGENT_CARD_URL } '
226+ in str (exc_info .value )
227+ )
228+ assert 'invalid_field' in str (
229+ exc_info .value
230+ ) # Check if Pydantic error details are present
231+ assert (
232+ mock_httpx_client .get .call_count == 1
233+ ) # Should only be called once
194234
195235 @pytest .mark .asyncio
196236 async def test_get_agent_card_http_status_error (
@@ -217,7 +257,10 @@ async def test_get_agent_card_http_status_error(
217257 await resolver .get_agent_card ()
218258
219259 assert exc_info .value .status_code == 404
220- assert f'Failed to fetch agent card from { self .FULL_AGENT_CARD_URL } ' in str (exc_info .value )
260+ assert (
261+ f'Failed to fetch agent card from { self .FULL_AGENT_CARD_URL } '
262+ in str (exc_info .value )
263+ )
221264 assert 'Not Found' in str (exc_info .value )
222265 mock_httpx_client .get .assert_called_once_with (self .FULL_AGENT_CARD_URL )
223266
@@ -242,7 +285,10 @@ async def test_get_agent_card_json_decode_error(
242285 await resolver .get_agent_card ()
243286
244287 # Assertions using exc_info must be after the with block
245- assert f'Failed to parse JSON for agent card from { self .FULL_AGENT_CARD_URL } ' in str (exc_info .value )
288+ assert (
289+ f'Failed to parse JSON for agent card from { self .FULL_AGENT_CARD_URL } '
290+ in str (exc_info .value )
291+ )
246292 assert 'Expecting value' in str (exc_info .value )
247293 mock_httpx_client .get .assert_called_once_with (self .FULL_AGENT_CARD_URL )
248294
@@ -263,7 +309,10 @@ async def test_get_agent_card_request_error(
263309 await resolver .get_agent_card ()
264310
265311 assert exc_info .value .status_code == 503
266- assert f'Network communication error fetching agent card from { self .FULL_AGENT_CARD_URL } ' in str (exc_info .value )
312+ assert (
313+ f'Network communication error fetching agent card from { self .FULL_AGENT_CARD_URL } '
314+ in str (exc_info .value )
315+ )
267316 assert 'Network issue' in str (exc_info .value )
268317 mock_httpx_client .get .assert_called_once_with (self .FULL_AGENT_CARD_URL )
269318
0 commit comments