Skip to content

Commit 2e1c4ef

Browse files
committed
Gemini authored: write tests for new ClientFactory.connect method
1 parent 0e50e7e commit 2e1c4ef

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

tests/client/test_client_factory.py

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Tests for the ClientFactory."""
22

3+
from unittest.mock import AsyncMock, MagicMock, patch
4+
35
import httpx
46
import pytest
57

@@ -103,3 +105,153 @@ def test_client_factory_no_compatible_transport(base_agent_card: AgentCard):
103105
factory = ClientFactory(config)
104106
with pytest.raises(ValueError, match='no compatible transports found'):
105107
factory.create(base_agent_card)
108+
109+
110+
@pytest.mark.asyncio
111+
async def test_client_factory_connect_with_agent_card(base_agent_card: AgentCard):
112+
"""Verify that connect works correctly when provided with an AgentCard."""
113+
client = await ClientFactory.connect(base_agent_card)
114+
assert isinstance(client._transport, JsonRpcTransport)
115+
assert client._transport.url == 'http://primary-url.com'
116+
117+
118+
@pytest.mark.asyncio
119+
async def test_client_factory_connect_with_url(base_agent_card: AgentCard):
120+
"""Verify that connect works correctly when provided with a URL."""
121+
with patch('a2a.client.client_factory.A2ACardResolver') as mock_resolver:
122+
mock_resolver.return_value.get_agent_card = AsyncMock(
123+
return_value=base_agent_card
124+
)
125+
126+
agent_url = 'http://example.com'
127+
client = await ClientFactory.connect(agent_url)
128+
129+
mock_resolver.assert_called_once()
130+
assert mock_resolver.call_args[0][1] == agent_url
131+
mock_resolver.return_value.get_agent_card.assert_awaited_once()
132+
133+
assert isinstance(client._transport, JsonRpcTransport)
134+
assert client._transport.url == 'http://primary-url.com'
135+
136+
137+
@pytest.mark.asyncio
138+
async def test_client_factory_connect_with_url_and_client_config(
139+
base_agent_card: AgentCard,
140+
):
141+
"""Verify connect with a URL and a pre-configured httpx client."""
142+
with patch('a2a.client.client_factory.A2ACardResolver') as mock_resolver:
143+
mock_resolver.return_value.get_agent_card = AsyncMock(
144+
return_value=base_agent_card
145+
)
146+
147+
agent_url = 'http://example.com'
148+
mock_httpx_client = httpx.AsyncClient()
149+
config = ClientConfig(httpx_client=mock_httpx_client)
150+
151+
client = await ClientFactory.connect(agent_url, client_config=config)
152+
153+
mock_resolver.assert_called_once_with(mock_httpx_client, agent_url)
154+
mock_resolver.return_value.get_agent_card.assert_awaited_once()
155+
156+
assert isinstance(client._transport, JsonRpcTransport)
157+
assert client._transport.url == 'http://primary-url.com'
158+
159+
160+
@pytest.mark.asyncio
161+
async def test_client_factory_connect_with_resolver_args(
162+
base_agent_card: AgentCard,
163+
):
164+
"""Verify connect passes resolver arguments correctly."""
165+
with patch('a2a.client.client_factory.A2ACardResolver') as mock_resolver:
166+
mock_resolver.return_value.get_agent_card = AsyncMock(
167+
return_value=base_agent_card
168+
)
169+
170+
agent_url = 'http://example.com'
171+
relative_path = '/card'
172+
http_kwargs = {'headers': {'X-Test': 'true'}}
173+
174+
# The resolver args are only passed if an httpx_client is provided in config
175+
config = ClientConfig(httpx_client=httpx.AsyncClient())
176+
177+
await ClientFactory.connect(
178+
agent_url,
179+
client_config=config,
180+
relative_card_path=relative_path,
181+
resolver_http_kwargs=http_kwargs,
182+
)
183+
184+
mock_resolver.return_value.get_agent_card.assert_awaited_once_with(
185+
relative_card_path=relative_path,
186+
http_kwargs=http_kwargs,
187+
)
188+
189+
190+
@pytest.mark.asyncio
191+
async def test_client_factory_connect_resolver_args_ignored_without_client(
192+
base_agent_card: AgentCard,
193+
):
194+
"""Verify resolver args are ignored if no httpx_client is provided."""
195+
with patch('a2a.client.client_factory.A2ACardResolver') as mock_resolver:
196+
mock_resolver.return_value.get_agent_card = AsyncMock(
197+
return_value=base_agent_card
198+
)
199+
200+
agent_url = 'http://example.com'
201+
relative_path = '/card'
202+
http_kwargs = {'headers': {'X-Test': 'true'}}
203+
204+
await ClientFactory.connect(
205+
agent_url,
206+
relative_card_path=relative_path,
207+
resolver_http_kwargs=http_kwargs,
208+
)
209+
210+
mock_resolver.return_value.get_agent_card.assert_awaited_once_with()
211+
212+
213+
@pytest.mark.asyncio
214+
async def test_client_factory_connect_with_extra_transports(
215+
base_agent_card: AgentCard,
216+
):
217+
"""Verify that connect can register and use extra transports."""
218+
219+
class CustomTransport:
220+
pass
221+
222+
def custom_transport_producer(*args, **kwargs):
223+
return CustomTransport()
224+
225+
base_agent_card.preferred_transport = 'custom'
226+
base_agent_card.url = 'custom://foo'
227+
228+
config = ClientConfig(supported_transports=['custom'])
229+
230+
client = await ClientFactory.connect(
231+
base_agent_card,
232+
client_config=config,
233+
extra_transports={'custom': custom_transport_producer},
234+
)
235+
236+
assert isinstance(client._transport, CustomTransport)
237+
238+
239+
@pytest.mark.asyncio
240+
async def test_client_factory_connect_with_consumers_and_interceptors(
241+
base_agent_card: AgentCard,
242+
):
243+
"""Verify consumers and interceptors are passed through correctly."""
244+
consumer1 = MagicMock()
245+
interceptor1 = MagicMock()
246+
247+
with patch('a2a.client.client_factory.BaseClient') as mock_base_client:
248+
await ClientFactory.connect(
249+
base_agent_card,
250+
consumers=[consumer1],
251+
interceptors=[interceptor1],
252+
)
253+
254+
mock_base_client.assert_called_once()
255+
call_args = mock_base_client.call_args[0]
256+
assert call_args[3] == [consumer1]
257+
assert call_args[4] == [interceptor1]

0 commit comments

Comments
 (0)