1+ package io .github .vishalmysore .a2a .client ;
2+
3+ import io .github .vishalmysore .a2a .domain .*;
4+ import io .github .vishalmysore .common .AgentInfo ;
5+ import io .github .vishalmysore .common .CommonClientResponse ;
6+ import org .junit .jupiter .api .BeforeEach ;
7+ import org .junit .jupiter .api .Test ;
8+ import org .mockito .MockedStatic ;
9+ import org .springframework .http .HttpStatus ;
10+ import org .springframework .http .ResponseEntity ;
11+ import org .springframework .web .client .HttpClientErrorException ;
12+ import org .springframework .web .client .RestTemplate ;
13+
14+ import java .io .ByteArrayInputStream ;
15+ import java .io .IOException ;
16+ import java .net .HttpURLConnection ;
17+ import java .net .URL ;
18+ import java .util .UUID ;
19+
20+ import static org .junit .jupiter .api .Assertions .*;
21+ import static org .mockito .ArgumentMatchers .any ;
22+ import static org .mockito .ArgumentMatchers .eq ;
23+ import static org .mockito .Mockito .*;
24+
25+ class A2AAgentTest {
26+
27+ private A2AAgent a2aAgent ;
28+ private RestTemplate mockRestTemplate ;
29+ private HttpURLConnection mockConnection ;
30+
31+ @ BeforeEach
32+ void setUp () {
33+ a2aAgent = new A2AAgent ();
34+ mockRestTemplate = mock (RestTemplate .class );
35+ mockConnection = mock (HttpURLConnection .class );
36+ }
37+
38+ @ Test
39+ void testGetType () {
40+ assertEquals ("a2a" , a2aAgent .getType ());
41+ }
42+
43+ @ Test
44+ void testRemoteMethodCall () throws Exception {
45+ // Setup
46+ String query = "Test query" ;
47+ SendTaskResponse mockResponse = new SendTaskResponse ();
48+ Task task = new Task ();
49+ task .setId (UUID .randomUUID ().toString ());
50+ mockResponse .setResult (task );
51+
52+ // Use MockedStatic for RestTemplate
53+ try (MockedStatic <UUID > mockedUuid = mockStatic (UUID .class )) {
54+ UUID mockUuid = mock (UUID .class );
55+ when (mockUuid .toString ()).thenReturn ("test-uuid" );
56+ mockedUuid .when (UUID ::randomUUID ).thenReturn (mockUuid );
57+
58+ // Setup the URL
59+ a2aAgent .connect ("http://test-url/.well-known/agent.json" , null );
60+
61+ // Mock RestTemplate
62+ mockRestTemplate = mock (RestTemplate .class );
63+ when (mockRestTemplate .postForEntity (
64+ anyString (),
65+ any (),
66+ eq (SendTaskResponse .class )
67+ )).thenReturn (new ResponseEntity <>(mockResponse , HttpStatus .OK ));
68+
69+ // Use reflection to replace the RestTemplate with our mock
70+ // (can't directly set it since A2AAgent creates a new instance each call)
71+ try (MockedStatic <RestTemplate > mockedRestTemplate = mockStatic (RestTemplate .class )) {
72+ mockedRestTemplate .when (RestTemplate ::new ).thenReturn (mockRestTemplate );
73+
74+ // Execute
75+ CommonClientResponse response = a2aAgent .remoteMethodCall (query );
76+
77+ // Verify
78+ assertNotNull (response );
79+ assertEquals (mockResponse , response );
80+ }
81+ }
82+ }
83+
84+ @ Test
85+ void testRemoteMethodCallWithName () throws Exception {
86+ // Setup
87+ String query = "Test query" ;
88+ String methodName = "test-method" ;
89+ SendTaskResponse mockResponse = new SendTaskResponse ();
90+ Task task = new Task ();
91+ task .setId (UUID .randomUUID ().toString ());
92+ mockResponse .setResult (task );
93+
94+ // Use MockedStatic for RestTemplate
95+ try (MockedStatic <UUID > mockedUuid = mockStatic (UUID .class )) {
96+ UUID mockUuid = mock (UUID .class );
97+ when (mockUuid .toString ()).thenReturn ("test-uuid" );
98+ mockedUuid .when (UUID ::randomUUID ).thenReturn (mockUuid );
99+
100+ // Setup the URL
101+ a2aAgent .connect ("http://test-url/.well-known/agent.json" , null );
102+
103+ // Mock RestTemplate
104+ mockRestTemplate = mock (RestTemplate .class );
105+ when (mockRestTemplate .postForEntity (
106+ anyString (),
107+ any (),
108+ eq (SendTaskResponse .class )
109+ )).thenReturn (new ResponseEntity <>(mockResponse , HttpStatus .OK ));
110+
111+ // Use reflection to replace the RestTemplate with our mock
112+ try (MockedStatic <RestTemplate > mockedRestTemplate = mockStatic (RestTemplate .class )) {
113+ mockedRestTemplate .when (RestTemplate ::new ).thenReturn (mockRestTemplate );
114+
115+ // Execute
116+ CommonClientResponse response = a2aAgent .remoteMethodCall (methodName , query );
117+
118+ // Verify
119+ assertNotNull (response );
120+ assertEquals (mockResponse , response );
121+ }
122+ }
123+ }
124+
125+ @ Test
126+ void testConnectAndDisconnect () throws Exception {
127+ // Setup for connect
128+ String agentCardJson = "{\" name\" :\" Test Agent\" ,\" description\" :\" Test Description\" ,\" agent_type\" :\" a2a\" }" ;
129+
130+ // Mock URL and connection
131+ URL mockUrl = mock (URL .class );
132+ try (MockedStatic <URL > mockedUrl = mockStatic (URL .class )) {
133+ mockedUrl .when (() -> new URL (anyString ())).thenReturn (mockUrl );
134+ when (mockUrl .openConnection ()).thenReturn (mockConnection );
135+ when (mockConnection .getInputStream ()).thenReturn (new ByteArrayInputStream (agentCardJson .getBytes ()));
136+ when (mockConnection .getResponseCode ()).thenReturn (200 );
137+
138+ // Execute connect
139+ a2aAgent .connect ("http://test-url/.well-known/agent.json" , null );
140+
141+ // Verify connect
142+ assertTrue (a2aAgent .isConnected ());
143+ AgentCard agentCard = (AgentCard ) a2aAgent .getInfo ();
144+ assertEquals ("Test Agent" , agentCard .getName ());
145+ assertEquals ("Test Description" , agentCard .getDescription ());
146+
147+ // Execute disconnect
148+ a2aAgent .disconnect ();
149+
150+ // Verify disconnect
151+ assertFalse (a2aAgent .isConnected ());
152+ assertNull (a2aAgent .getInfo ());
153+ }
154+ }
155+
156+ @ Test
157+ void testConnectWithNonJsonUrl () throws Exception {
158+ // Setup for connect with URL not ending in .json
159+ String agentCardJson = "{\" name\" :\" Test Agent\" ,\" description\" :\" Test Description\" ,\" agent_type\" :\" a2a\" }" ;
160+
161+ // Mock URL and connection
162+ URL mockUrl = mock (URL .class );
163+ try (MockedStatic <URL > mockedUrl = mockStatic (URL .class )) {
164+ mockedUrl .when (() -> new URL (anyString ())).thenReturn (mockUrl );
165+ when (mockUrl .openConnection ()).thenReturn (mockConnection );
166+ when (mockConnection .getInputStream ()).thenReturn (new ByteArrayInputStream (agentCardJson .getBytes ()));
167+ when (mockConnection .getResponseCode ()).thenReturn (200 );
168+
169+ // Execute connect with URL ending with /
170+ a2aAgent .connect ("http://test-url/" , null );
171+
172+ // Verify connect
173+ assertTrue (a2aAgent .isConnected ());
174+
175+ // Execute connect with URL not ending with /
176+ a2aAgent .connect ("http://test-url" , null );
177+
178+ // Verify connect
179+ assertTrue (a2aAgent .isConnected ());
180+ }
181+ }
182+
183+ @ Test
184+ void testConnectFailureInvalidUrl () {
185+ // Test with invalid URL (not containing .well-known)
186+ assertThrows (IllegalArgumentException .class , () ->
187+ a2aAgent .connect ("http://test-url/invalid.json" , null )
188+ );
189+ }
190+
191+ @ Test
192+ void testConnectFailureHttp () throws Exception {
193+ // Setup for HTTP failure
194+ URL mockUrl = mock (URL .class );
195+ try (MockedStatic <URL > mockedUrl = mockStatic (URL .class )) {
196+ mockedUrl .when (() -> new URL (anyString ())).thenReturn (mockUrl );
197+ when (mockUrl .openConnection ()).thenReturn (mockConnection );
198+ when (mockConnection .getResponseCode ()).thenReturn (404 );
199+
200+ // Execute and verify
201+ assertThrows (RuntimeException .class , () ->
202+ a2aAgent .connect ("http://test-url/.well-known/agent.json" , null )
203+ );
204+ }
205+ }
206+
207+ @ Test
208+ void testConnectFailureIO () throws Exception {
209+ // Setup for IO Exception
210+ URL mockUrl = mock (URL .class );
211+ try (MockedStatic <URL > mockedUrl = mockStatic (URL .class )) {
212+ mockedUrl .when (() -> new URL (anyString ())).thenReturn (mockUrl );
213+ when (mockUrl .openConnection ()).thenThrow (new IOException ("Test IO Exception" ));
214+
215+ // Execute and verify
216+ assertThrows (RuntimeException .class , () ->
217+ a2aAgent .connect ("http://test-url/.well-known/agent.json" , null )
218+ );
219+ }
220+ }
221+
222+ @ Test
223+ void testGetterMethods () throws Exception {
224+ // Setup
225+ String agentCardJson = "{\" name\" :\" Test Agent\" ,\" description\" :\" Test Description\" ,\" agent_type\" :\" a2a\" }" ;
226+
227+ // Mock URL and connection
228+ URL mockUrl = mock (URL .class );
229+ try (MockedStatic <URL > mockedUrl = mockStatic (URL .class )) {
230+ mockedUrl .when (() -> new URL (anyString ())).thenReturn (mockUrl );
231+ when (mockUrl .openConnection ()).thenReturn (mockConnection );
232+ when (mockConnection .getInputStream ()).thenReturn (new ByteArrayInputStream (agentCardJson .getBytes ()));
233+ when (mockConnection .getResponseCode ()).thenReturn (200 );
234+
235+ // Connect
236+ a2aAgent .connect ("http://test-url/.well-known/agent.json" , null );
237+
238+ // Test getters
239+ assertEquals (mockUrl , a2aAgent .getServerUrl ());
240+ assertNotNull (a2aAgent .getMapper ());
241+ AgentInfo info = a2aAgent .getInfo ();
242+ assertNotNull (info );
243+ AgentCard agentCard = (AgentCard ) info ;
244+ assertEquals ("Test Agent" , agentCard .getName ());
245+ }
246+ }
247+ }
0 commit comments