22
33import json
44
5+ from collections .abc import AsyncGenerator
56from unittest .mock import AsyncMock , MagicMock , patch
67from uuid import uuid4
78
3132)
3233from a2a .utils .errors import JSON_RPC_ERROR_CODE_MAP
3334from google .protobuf import json_format
34- from httpx_sse import EventSource , SSEError
35+
36+
37+ async def async_iterable_from_list (
38+ items : list [str ],
39+ ) -> AsyncGenerator [str , None ]:
40+ """Helper to create an async iterable from a list."""
41+ for item in items :
42+ yield item
3543
3644
3745@pytest .fixture
@@ -439,17 +447,17 @@ async def test_send_message_streaming_sse_error(
439447 transport : JsonRpcTransport ,
440448 ):
441449 request = create_send_message_request ()
442- mock_event_source = AsyncMock ()
443- mock_event_source .response .raise_for_status = MagicMock ()
444- mock_event_source .response .headers = {
445- 'content-type' : 'text/event-stream'
446- }
447- mock_event_source .aiter_sse = MagicMock (
448- side_effect = SSEError ('Simulated SSE error' )
449- )
450- mock_aconnect_sse .return_value .__aenter__ .return_value = (
451- mock_event_source
450+ mock_response = AsyncMock (spec = httpx .Response )
451+ mock_response .raise_for_status = MagicMock ()
452+ mock_response .headers = {'content-type' : 'text/event-stream' }
453+ mock_response .aiter_lines .return_value = async_iterable_from_list (
454+ [
455+ 'event: error' ,
456+ 'data: Simulated SSE error' ,
457+ '' ,
458+ ]
452459 )
460+ mock_aconnect_sse .return_value .__aenter__ .return_value = mock_response
453461
454462 with pytest .raises (A2AClientError ):
455463 async for _ in transport .send_message_streaming (request ):
@@ -463,19 +471,13 @@ async def test_send_message_streaming_request_error(
463471 transport : JsonRpcTransport ,
464472 ):
465473 request = create_send_message_request ()
466- mock_event_source = AsyncMock ()
467- mock_event_source .response .raise_for_status = MagicMock ()
468- mock_event_source .response .headers = {
469- 'content-type' : 'text/event-stream'
470- }
471- mock_event_source .aiter_sse = MagicMock (
472- side_effect = httpx .RequestError (
473- 'Simulated request error' , request = MagicMock ()
474- )
475- )
476- mock_aconnect_sse .return_value .__aenter__ .return_value = (
477- mock_event_source
474+ mock_response = AsyncMock (spec = httpx .Response )
475+ mock_response .raise_for_status = MagicMock ()
476+ mock_response .headers = {'content-type' : 'text/event-stream' }
477+ mock_response .aiter_lines .side_effect = httpx .RequestError (
478+ 'Simulated request error' , request = MagicMock ()
478479 )
480+ mock_aconnect_sse .return_value .__aenter__ .return_value = mock_response
479481
480482 with pytest .raises (A2AClientError ):
481483 async for _ in transport .send_message_streaming (request ):
@@ -489,17 +491,13 @@ async def test_send_message_streaming_timeout(
489491 transport : JsonRpcTransport ,
490492 ):
491493 request = create_send_message_request ()
492- mock_event_source = AsyncMock ()
493- mock_event_source .response .raise_for_status = MagicMock ()
494- mock_event_source .response .headers = {
495- 'content-type' : 'text/event-stream'
496- }
497- mock_event_source .aiter_sse = MagicMock (
498- side_effect = httpx .TimeoutException ('Timeout' )
499- )
500- mock_aconnect_sse .return_value .__aenter__ .return_value = (
501- mock_event_source
494+ mock_response = AsyncMock (spec = httpx .Response )
495+ mock_response .raise_for_status = MagicMock ()
496+ mock_response .headers = {'content-type' : 'text/event-stream' }
497+ mock_response .aiter_lines .side_effect = httpx .TimeoutException (
498+ 'Timeout'
502499 )
500+ mock_aconnect_sse .return_value .__aenter__ .return_value = mock_response
503501
504502 with pytest .raises (A2AClientError , match = 'timed out' ):
505503 async for _ in transport .send_message_streaming (request ):
@@ -574,24 +572,16 @@ async def test_send_message_streaming_server_error_propagates(
574572 )
575573 request = create_send_message_request (text = 'Error stream' )
576574
577- mock_event_source = AsyncMock (spec = EventSource )
578- mock_response = MagicMock (spec = httpx .Response )
575+ mock_response = AsyncMock (spec = httpx .Response )
579576 mock_response .status_code = 403
577+ mock_response .headers = {'content-type' : 'text/event-stream' }
580578 mock_response .raise_for_status .side_effect = httpx .HTTPStatusError (
581579 'Forbidden' ,
582580 request = httpx .Request ('POST' , 'http://test.url' ),
583581 response = mock_response ,
584582 )
585- mock_event_source .response = mock_response
586-
587- async def empty_aiter ():
588- if False :
589- yield
590-
591- mock_event_source .aiter_sse = MagicMock (return_value = empty_aiter ())
592- mock_aconnect_sse .return_value .__aenter__ .return_value = (
593- mock_event_source
594- )
583+ mock_response .aiter_lines .return_value = async_iterable_from_list ([])
584+ mock_aconnect_sse .return_value .__aenter__ .return_value = mock_response
595585
596586 with pytest .raises (A2AClientError ) as exc_info :
597587 async for _ in client .send_message_streaming (request = request ):
0 commit comments