Skip to content

Commit f7cf1bf

Browse files
committed
fix: Move JSONRPC-specific tests back to AbstractA2AServerTest so that other server implementations that also support JSONRPC can make use of these tests. These tests will be skipped when testing other transports
1 parent cf3e3f0 commit f7cf1bf

File tree

2 files changed

+277
-277
lines changed

2 files changed

+277
-277
lines changed
Lines changed: 0 additions & 277 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,9 @@
11
package io.a2a.server.apps.quarkus;
22

3-
import static io.restassured.RestAssured.given;
4-
import static org.junit.jupiter.api.Assertions.assertEquals;
5-
import static org.junit.jupiter.api.Assertions.assertNull;
6-
import static org.junit.jupiter.api.Assertions.fail;
7-
import static org.wildfly.common.Assert.assertNotNull;
8-
import jakarta.ws.rs.core.MediaType;
9-
10-
import java.net.URI;
11-
import java.net.http.HttpClient;
12-
import java.net.http.HttpRequest;
13-
import java.net.http.HttpResponse;
14-
import java.util.concurrent.CompletableFuture;
15-
import java.util.concurrent.CountDownLatch;
16-
import java.util.concurrent.TimeUnit;
17-
import java.util.concurrent.atomic.AtomicReference;
18-
import java.util.stream.Stream;
19-
20-
import com.fasterxml.jackson.core.JsonProcessingException;
21-
223
import io.a2a.server.apps.common.AbstractA2AServerTest;
23-
import io.a2a.spec.A2AClientException;
24-
import io.a2a.spec.InvalidParamsError;
25-
import io.a2a.spec.InvalidRequestError;
26-
import io.a2a.spec.JSONParseError;
27-
import io.a2a.spec.JSONRPCErrorResponse;
28-
import io.a2a.spec.Message;
29-
import io.a2a.spec.MessageSendParams;
30-
import io.a2a.spec.MethodNotFoundError;
31-
import io.a2a.spec.Part;
32-
import io.a2a.spec.SendStreamingMessageRequest;
33-
import io.a2a.spec.SendStreamingMessageResponse;
34-
import io.a2a.spec.StreamingJSONRPCRequest;
35-
import io.a2a.spec.Task;
36-
import io.a2a.spec.TaskQueryParams;
37-
import io.a2a.spec.TaskState;
38-
import io.a2a.spec.TextPart;
394
import io.a2a.spec.TransportProtocol;
40-
import io.a2a.util.Utils;
415
import io.quarkus.test.junit.QuarkusTest;
426

43-
import org.junit.jupiter.api.Assertions;
44-
import org.junit.jupiter.api.Test;
45-
467
@QuarkusTest
478
public class QuarkusA2AJSONRPCTest extends AbstractA2AServerTest {
489

@@ -59,242 +20,4 @@ protected String getTransportProtocol() {
5920
protected String getTransportUrl() {
6021
return "http://localhost:8081";
6122
}
62-
63-
@Test
64-
public void testMalformedJSONRPCRequest() {
65-
// missing closing bracket
66-
String malformedRequest = "{\"jsonrpc\": \"2.0\", \"method\": \"message/send\", \"params\": {\"foo\": \"bar\"}";
67-
JSONRPCErrorResponse response = given()
68-
.contentType(MediaType.APPLICATION_JSON)
69-
.body(malformedRequest)
70-
.when()
71-
.post("/")
72-
.then()
73-
.statusCode(200)
74-
.extract()
75-
.as(JSONRPCErrorResponse.class);
76-
assertNotNull(response.getError());
77-
assertEquals(new JSONParseError().getCode(), response.getError().getCode());
78-
}
79-
80-
@Test
81-
public void testInvalidParamsJSONRPCRequest() {
82-
String invalidParamsRequest = """
83-
{"jsonrpc": "2.0", "method": "message/send", "params": "not_a_dict", "id": "1"}
84-
""";
85-
testInvalidParams(invalidParamsRequest);
86-
87-
invalidParamsRequest = """
88-
{"jsonrpc": "2.0", "method": "message/send", "params": {"message": {"parts": "invalid"}}, "id": "1"}
89-
""";
90-
testInvalidParams(invalidParamsRequest);
91-
}
92-
93-
private void testInvalidParams(String invalidParamsRequest) {
94-
JSONRPCErrorResponse response = given()
95-
.contentType(MediaType.APPLICATION_JSON)
96-
.body(invalidParamsRequest)
97-
.when()
98-
.post("/")
99-
.then()
100-
.statusCode(200)
101-
.extract()
102-
.as(JSONRPCErrorResponse.class);
103-
assertNotNull(response.getError());
104-
assertEquals(new InvalidParamsError().getCode(), response.getError().getCode());
105-
assertEquals("1", response.getId());
106-
}
107-
108-
@Test
109-
public void testInvalidJSONRPCRequestMissingJsonrpc() {
110-
String invalidRequest = """
111-
{
112-
"method": "message/send",
113-
"params": {}
114-
}
115-
""";
116-
JSONRPCErrorResponse response = given()
117-
.contentType(MediaType.APPLICATION_JSON)
118-
.body(invalidRequest)
119-
.when()
120-
.post("/")
121-
.then()
122-
.statusCode(200)
123-
.extract()
124-
.as(JSONRPCErrorResponse.class);
125-
assertNotNull(response.getError());
126-
assertEquals(new InvalidRequestError().getCode(), response.getError().getCode());
127-
}
128-
129-
@Test
130-
public void testInvalidJSONRPCRequestMissingMethod() {
131-
String invalidRequest = """
132-
{"jsonrpc": "2.0", "params": {}}
133-
""";
134-
JSONRPCErrorResponse response = given()
135-
.contentType(MediaType.APPLICATION_JSON)
136-
.body(invalidRequest)
137-
.when()
138-
.post("/")
139-
.then()
140-
.statusCode(200)
141-
.extract()
142-
.as(JSONRPCErrorResponse.class);
143-
assertNotNull(response.getError());
144-
assertEquals(new InvalidRequestError().getCode(), response.getError().getCode());
145-
}
146-
147-
@Test
148-
public void testInvalidJSONRPCRequestInvalidId() {
149-
String invalidRequest = """
150-
{"jsonrpc": "2.0", "method": "message/send", "params": {}, "id": {"bad": "type"}}
151-
""";
152-
JSONRPCErrorResponse response = given()
153-
.contentType(MediaType.APPLICATION_JSON)
154-
.body(invalidRequest)
155-
.when()
156-
.post("/")
157-
.then()
158-
.statusCode(200)
159-
.extract()
160-
.as(JSONRPCErrorResponse.class);
161-
assertNotNull(response.getError());
162-
assertEquals(new InvalidRequestError().getCode(), response.getError().getCode());
163-
}
164-
165-
@Test
166-
public void testInvalidJSONRPCRequestNonExistentMethod() {
167-
String invalidRequest = """
168-
{"jsonrpc": "2.0", "method" : "nonexistent/method", "params": {}}
169-
""";
170-
JSONRPCErrorResponse response = given()
171-
.contentType(MediaType.APPLICATION_JSON)
172-
.body(invalidRequest)
173-
.when()
174-
.post("/")
175-
.then()
176-
.statusCode(200)
177-
.extract()
178-
.as(JSONRPCErrorResponse.class);
179-
assertNotNull(response.getError());
180-
assertEquals(new MethodNotFoundError().getCode(), response.getError().getCode());
181-
}
182-
183-
@Test
184-
public void testNonStreamingMethodWithAcceptHeader() throws Exception {
185-
testGetTask(MediaType.APPLICATION_JSON);
186-
}
187-
188-
private void testGetTask(String mediaType) throws Exception {
189-
saveTaskInTaskStore(MINIMAL_TASK);
190-
try {
191-
Task response = getClient().getTask(new TaskQueryParams(MINIMAL_TASK.getId()), null);
192-
assertEquals("task-123", response.getId());
193-
assertEquals("session-xyz", response.getContextId());
194-
assertEquals(TaskState.SUBMITTED, response.getStatus().state());
195-
} catch (A2AClientException e) {
196-
fail("Unexpected exception during getTask: " + e.getMessage(), e);
197-
} finally {
198-
deleteTaskInTaskStore(MINIMAL_TASK.getId());
199-
}
200-
}
201-
202-
@Test
203-
public void testStreamingMethodWithAcceptHeader() throws Exception {
204-
testSendStreamingMessage(MediaType.SERVER_SENT_EVENTS);
205-
}
206-
207-
@Test
208-
public void testSendMessageStreamNewMessageSuccess() throws Exception {
209-
testSendStreamingMessage(null);
210-
}
211-
212-
private void testSendStreamingMessage(String mediaType) throws Exception {
213-
Message message = new Message.Builder(MESSAGE)
214-
.taskId(MINIMAL_TASK.getId())
215-
.contextId(MINIMAL_TASK.getContextId())
216-
.build();
217-
SendStreamingMessageRequest request = new SendStreamingMessageRequest(
218-
"1", new MessageSendParams(message, null, null));
219-
220-
CompletableFuture<HttpResponse<Stream<String>>> responseFuture = initialiseStreamingRequest(request, mediaType);
221-
222-
CountDownLatch latch = new CountDownLatch(1);
223-
AtomicReference<Throwable> errorRef = new AtomicReference<>();
224-
225-
responseFuture.thenAccept(response -> {
226-
if (response.statusCode() != 200) {
227-
//errorRef.set(new IllegalStateException("Status code was " + response.statusCode()));
228-
throw new IllegalStateException("Status code was " + response.statusCode());
229-
}
230-
response.body().forEach(line -> {
231-
try {
232-
SendStreamingMessageResponse jsonResponse = extractJsonResponseFromSseLine(line);
233-
if (jsonResponse != null) {
234-
assertNull(jsonResponse.getError());
235-
Message messageResponse = (Message) jsonResponse.getResult();
236-
assertEquals(MESSAGE.getMessageId(), messageResponse.getMessageId());
237-
assertEquals(MESSAGE.getRole(), messageResponse.getRole());
238-
Part<?> part = messageResponse.getParts().get(0);
239-
assertEquals(Part.Kind.TEXT, part.getKind());
240-
assertEquals("test message", ((TextPart) part).getText());
241-
latch.countDown();
242-
}
243-
} catch (JsonProcessingException e) {
244-
throw new RuntimeException(e);
245-
}
246-
});
247-
}).exceptionally(t -> {
248-
if (!isStreamClosedError(t)) {
249-
errorRef.set(t);
250-
}
251-
latch.countDown();
252-
return null;
253-
});
254-
255-
256-
boolean dataRead = latch.await(20, TimeUnit.SECONDS);
257-
Assertions.assertTrue(dataRead);
258-
Assertions.assertNull(errorRef.get());
259-
260-
}
261-
262-
private CompletableFuture<HttpResponse<Stream<String>>> initialiseStreamingRequest(
263-
StreamingJSONRPCRequest<?> request, String mediaType) throws Exception {
264-
265-
// Create the client
266-
HttpClient client = HttpClient.newBuilder()
267-
.version(HttpClient.Version.HTTP_2)
268-
.build();
269-
270-
// Create the request
271-
HttpRequest.Builder builder = HttpRequest.newBuilder()
272-
.uri(URI.create("http://localhost:" + serverPort + "/"))
273-
.POST(HttpRequest.BodyPublishers.ofString(Utils.OBJECT_MAPPER.writeValueAsString(request)))
274-
.header("Content-Type", APPLICATION_JSON);
275-
if (mediaType != null) {
276-
builder.header("Accept", mediaType);
277-
}
278-
HttpRequest httpRequest = builder.build();
279-
280-
281-
// Send request async and return the CompletableFuture
282-
return client.sendAsync(httpRequest, HttpResponse.BodyHandlers.ofLines());
283-
}
284-
285-
private SendStreamingMessageResponse extractJsonResponseFromSseLine(String line) throws JsonProcessingException {
286-
line = extractSseData(line);
287-
if (line != null) {
288-
return Utils.OBJECT_MAPPER.readValue(line, SendStreamingMessageResponse.class);
289-
}
290-
return null;
291-
}
292-
293-
private static String extractSseData(String line) {
294-
if (line.startsWith("data:")) {
295-
line = line.substring(5).trim();
296-
return line;
297-
}
298-
return null;
299-
}
30023
}

0 commit comments

Comments
 (0)