Skip to content

Commit 5fb6a26

Browse files
committed
chore: Adding some testing on toProto conversion.
Checking that optional parameters not being set doesn't lead to a NullPointerException. Signed-off-by: Emmanuel Hugonnet <[email protected]>
1 parent 81b4a6b commit 5fb6a26

File tree

4 files changed

+295
-4
lines changed

4 files changed

+295
-4
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,5 @@ nb-configuration.xml
4343
/.quarkus/cli/plugins/
4444
# TLS Certificates
4545
.certs/
46+
nbproject/
47+

spec-grpc/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,21 @@
5353
<artifactId>javax.annotation-api</artifactId>
5454
<scope>provided</scope>
5555
</dependency>
56+
<dependency>
57+
<groupId>org.junit.jupiter</groupId>
58+
<artifactId>junit-jupiter-api</artifactId>
59+
<scope>test</scope>
60+
</dependency>
61+
<dependency>
62+
<groupId>org.junit.jupiter</groupId>
63+
<artifactId>junit-jupiter-params</artifactId>
64+
<scope>test</scope>
65+
</dependency>
66+
<dependency>
67+
<groupId>org.junit.jupiter</groupId>
68+
<artifactId>junit-jupiter-engine</artifactId>
69+
<scope>test</scope>
70+
</dependency>
5671
</dependencies>
5772

5873
<build>

spec-grpc/src/main/java/io/a2a/grpc/utils/ProtoUtils.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package io.a2a.grpc.utils;
22

3+
import static java.util.Objects.requireNonNullElse;
4+
35
import java.nio.charset.StandardCharsets;
46
import java.time.Instant;
57
import java.time.LocalDateTime;
@@ -143,8 +145,8 @@ public static io.a2a.grpc.Task task(Task task) {
143145
public static io.a2a.grpc.Message message(Message message) {
144146
io.a2a.grpc.Message.Builder builder = io.a2a.grpc.Message.newBuilder();
145147
builder.setMessageId(message.getMessageId());
146-
builder.setContextId(message.getContextId());
147-
builder.setTaskId(message.getTaskId());
148+
builder.setContextId(requireNonNullElse(message.getContextId(), ""));
149+
builder.setTaskId(requireNonNullElse(message.getTaskId(), ""));
148150
builder.setRole(role(message.getRole()));
149151
if (message.getParts() != null) {
150152
builder.addAllContent(message.getParts().stream().map(ToProto::part).collect(Collectors.toList()));
@@ -182,8 +184,8 @@ public static io.a2a.grpc.TaskArtifactUpdateEvent taskArtifactUpdateEvent(TaskAr
182184
builder.setTaskId(event.getTaskId());
183185
builder.setContextId(event.getContextId());
184186
builder.setArtifact(artifact(event.getArtifact()));
185-
builder.setAppend(event.isAppend() == null ? false : event.isAppend());
186-
builder.setLastChunk(event.isLastChunk() == null ? false : event.isLastChunk());
187+
builder.setAppend(requireNonNullElse(event.isAppend(), false));
188+
builder.setLastChunk(requireNonNullElse(event.isLastChunk(), false));
187189
if (event.getMetadata() != null) {
188190
builder.setMetadata(struct(event.getMetadata()));
189191
}
Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,272 @@
1+
package io.a2a.grpc.utils;
2+
3+
import static io.a2a.grpc.Role.ROLE_AGENT;
4+
import static io.a2a.grpc.Role.ROLE_USER;
5+
import static org.junit.jupiter.api.Assertions.assertEquals;
6+
import static org.junit.jupiter.api.Assertions.assertNotNull;
7+
8+
import io.a2a.grpc.SendMessageConfiguration;
9+
import io.a2a.spec.AgentCapabilities;
10+
import io.a2a.spec.AgentCard;
11+
import io.a2a.spec.AgentSkill;
12+
import io.a2a.spec.Artifact;
13+
import io.a2a.spec.HTTPAuthSecurityScheme;
14+
import io.a2a.spec.Message;
15+
import io.a2a.spec.MessageSendConfiguration;
16+
import io.a2a.spec.PushNotificationAuthenticationInfo;
17+
import io.a2a.spec.PushNotificationConfig;
18+
import io.a2a.spec.Task;
19+
import io.a2a.spec.TaskArtifactUpdateEvent;
20+
import io.a2a.spec.TaskPushNotificationConfig;
21+
import io.a2a.spec.TaskState;
22+
import io.a2a.spec.TaskStatus;
23+
import io.a2a.spec.TaskStatusUpdateEvent;
24+
import io.a2a.spec.TextPart;
25+
import java.util.Collections;
26+
import java.util.List;
27+
import java.util.Map;
28+
import org.junit.jupiter.api.Test;
29+
30+
public class ToProtoTest {
31+
32+
private static final Message SIMPLE_MESSAGE = new Message.Builder()
33+
.role(Message.Role.USER)
34+
.parts(Collections.singletonList(new TextPart("tell me a joke")))
35+
.contextId("context-1234")
36+
.messageId("message-1234")
37+
.build();
38+
39+
@Test
40+
public void convertAgentCard() {
41+
AgentCard agentCard = new AgentCard.Builder()
42+
.name("Hello World Agent")
43+
.description("Just a hello world agent")
44+
.url("http://localhost:9999")
45+
.version("1.0.0")
46+
.documentationUrl("http://example.com/docs")
47+
.capabilities(new AgentCapabilities.Builder()
48+
.streaming(true)
49+
.pushNotifications(true)
50+
.stateTransitionHistory(true)
51+
.build())
52+
.defaultInputModes(Collections.singletonList("text"))
53+
.defaultOutputModes(Collections.singletonList("text"))
54+
.skills(Collections.singletonList(new AgentSkill.Builder()
55+
.id("hello_world")
56+
.name("Returns hello world")
57+
.description("just returns hello world")
58+
.tags(Collections.singletonList("hello world"))
59+
.examples(List.of("hi", "hello world"))
60+
.build()))
61+
.protocolVersion("0.2.5")
62+
.build();
63+
io.a2a.grpc.AgentCard result = ProtoUtils.ToProto.agentCard(agentCard);
64+
assertEquals("Hello World Agent", result.getName());
65+
assertEquals("Just a hello world agent", result.getDescription());
66+
assertEquals("http://localhost:9999", result.getUrl());
67+
assertEquals("1.0.0", result.getVersion());
68+
assertEquals("http://example.com/docs", result.getDocumentationUrl());
69+
assertEquals(1, result.getDefaultInputModesCount());
70+
assertEquals("text", result.getDefaultInputModes(0));
71+
assertEquals(1, result.getDefaultOutputModesCount());
72+
assertEquals("text", result.getDefaultOutputModes(0));
73+
assertEquals("0.2.5", result.getProtocolVersion());
74+
agentCard = new AgentCard.Builder()
75+
.name("Hello World Agent")
76+
.description("Just a hello world agent")
77+
.url("http://localhost:9999")
78+
.version("1.0.0")
79+
.documentationUrl("http://example.com/docs")
80+
.capabilities(new AgentCapabilities.Builder()
81+
.streaming(true)
82+
.pushNotifications(true)
83+
.stateTransitionHistory(true)
84+
.build())
85+
.defaultInputModes(Collections.singletonList("text"))
86+
.defaultOutputModes(Collections.singletonList("text"))
87+
.skills(Collections.singletonList(new AgentSkill.Builder()
88+
.id("hello_world")
89+
.name("Returns hello world")
90+
.description("just returns hello world")
91+
.tags(Collections.singletonList("hello world"))
92+
.examples(List.of("hi", "hello world"))
93+
.build()))
94+
.preferredTransport("HTTP+JSON")
95+
// .iconUrl("http://example.com/icon.svg")
96+
.securitySchemes(Map.of("basic", new HTTPAuthSecurityScheme.Builder().scheme("basic").description("Basic Auth").build()))
97+
.security(List.of(Map.of("oauth", List.of("read"))))
98+
.protocolVersion("0.2.5")
99+
.build();
100+
result = ProtoUtils.ToProto.agentCard(agentCard);
101+
assertEquals("Hello World Agent", result.getName());
102+
assertEquals("Just a hello world agent", result.getDescription());
103+
assertEquals("http://localhost:9999", result.getUrl());
104+
assertEquals("1.0.0", result.getVersion());
105+
assertEquals("http://example.com/docs", result.getDocumentationUrl());
106+
assertEquals(1, result.getDefaultInputModesCount());
107+
assertEquals("text", result.getDefaultInputModes(0));
108+
assertEquals(1, result.getDefaultOutputModesCount());
109+
assertEquals("text", result.getDefaultOutputModes(0));
110+
assertEquals("0.2.5", result.getProtocolVersion());
111+
assertEquals("HTTP+JSON", result.getPreferredTransport());
112+
assertEquals(1, result.getSecurityCount());
113+
assertEquals(1, result.getSecurity(0).getSchemesMap().size());
114+
assertEquals(true, result.getSecurity(0).getSchemesMap().containsKey("oauth"));
115+
assertEquals(1, result.getSecurity(0).getSchemesMap().get("oauth").getListCount());
116+
assertEquals("read", result.getSecurity(0).getSchemesMap().get("oauth").getList(0));
117+
assertEquals(1, result.getSecuritySchemesMap().size());
118+
assertEquals(true, result.getSecuritySchemesMap().containsKey("basic"));
119+
assertEquals(result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getApiKeySecurityScheme());
120+
assertEquals(result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme().getDefaultInstanceForType(), result.getSecuritySchemesMap().get("basic").getOauth2SecurityScheme());
121+
assertEquals("basic", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getScheme());
122+
assertEquals("Basic Auth", result.getSecuritySchemesMap().get("basic").getHttpAuthSecurityScheme().getDescription());
123+
}
124+
125+
@Test
126+
public void convertTask() {
127+
Task task = new Task.Builder().id("cancel-task-123")
128+
.contextId("session-xyz")
129+
.status(new TaskStatus(TaskState.SUBMITTED))
130+
.build();
131+
io.a2a.grpc.Task result = ProtoUtils.ToProto.task(task);
132+
assertEquals("session-xyz", result.getContextId());
133+
assertEquals("cancel-task-123", result.getId());
134+
assertEquals(io.a2a.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState());
135+
assertEquals(0, result.getArtifactsCount());
136+
assertEquals(0, result.getHistoryCount());
137+
task = new Task.Builder().id("cancel-task-123")
138+
.contextId("session-xyz")
139+
.status(new TaskStatus(TaskState.SUBMITTED))
140+
.artifacts(List.of(new Artifact.Builder()
141+
.artifactId("11")
142+
.name("artefact")
143+
.parts(new TextPart("text"))
144+
.build()))
145+
.history(List.of(SIMPLE_MESSAGE))
146+
.metadata(Collections.emptyMap())
147+
.build();
148+
result = ProtoUtils.ToProto.task(task);
149+
assertEquals("session-xyz", result.getContextId());
150+
assertEquals("cancel-task-123", result.getId());
151+
assertEquals(io.a2a.grpc.TaskState.TASK_STATE_SUBMITTED, result.getStatus().getState());
152+
assertEquals(1, result.getArtifactsCount());
153+
assertEquals("11", result.getArtifacts(0).getArtifactId());
154+
assertEquals("artefact", result.getArtifacts(0).getName());
155+
assertEquals(1, result.getArtifacts(0).getPartsCount());
156+
assertEquals(true, result.getArtifacts(0).getParts(0).hasText());
157+
assertEquals(false, result.getArtifacts(0).getParts(0).hasFile());
158+
assertEquals(false, result.getArtifacts(0).getParts(0).hasData());
159+
assertEquals("text", result.getArtifacts(0).getParts(0).getText());
160+
assertEquals(1, result.getHistoryCount());
161+
assertEquals("context-1234", result.getHistory(0).getContextId());
162+
assertEquals("message-1234", result.getHistory(0).getMessageId());
163+
assertEquals(ROLE_USER, result.getHistory(0).getRole());
164+
assertEquals(1, result.getHistory(0).getContentCount());
165+
assertEquals("tell me a joke", result.getHistory(0).getContent(0).getText());
166+
assertEquals(io.a2a.grpc.FilePart.getDefaultInstance(), result.getHistory(0).getContent(0).getFile());
167+
assertEquals(io.a2a.grpc.DataPart.getDefaultInstance(), result.getHistory(0).getContent(0).getData());
168+
}
169+
170+
@Test
171+
public void convertMessage() {
172+
io.a2a.grpc.Message result = ProtoUtils.ToProto.message(SIMPLE_MESSAGE);
173+
assertEquals("context-1234", result.getContextId());
174+
assertEquals("message-1234", result.getMessageId());
175+
assertEquals(ROLE_USER, result.getRole());
176+
assertEquals(1, result.getContentCount());
177+
assertEquals("tell me a joke", result.getContent(0).getText());
178+
assertEquals(io.a2a.grpc.FilePart.getDefaultInstance(), result.getContent(0).getFile());
179+
assertEquals(io.a2a.grpc.DataPart.getDefaultInstance(), result.getContent(0).getData());
180+
Message message = new Message.Builder()
181+
.role(Message.Role.AGENT)
182+
.parts(Collections.singletonList(new TextPart("tell me a joke")))
183+
.messageId("message-1234")
184+
.build();
185+
result = ProtoUtils.ToProto.message(message);
186+
assertEquals("", result.getContextId());
187+
assertEquals("message-1234", result.getMessageId());
188+
assertEquals(ROLE_AGENT, result.getRole());
189+
assertEquals(1, result.getContentCount());
190+
assertEquals("tell me a joke", result.getContent(0).getText());
191+
assertEquals(io.a2a.grpc.FilePart.getDefaultInstance(), result.getContent(0).getFile());
192+
assertEquals(io.a2a.grpc.DataPart.getDefaultInstance(), result.getContent(0).getData());
193+
}
194+
195+
@Test
196+
public void convertTaskPushNotificationConfig() {
197+
TaskPushNotificationConfig taskPushConfig = new TaskPushNotificationConfig("push-task-123",
198+
new PushNotificationConfig.Builder()
199+
.url("http://example.com")
200+
.id("xyz")
201+
.build());
202+
io.a2a.grpc.TaskPushNotificationConfig result = ProtoUtils.ToProto.taskPushNotificationConfig(taskPushConfig);
203+
assertEquals("tasks/push-task-123/pushNotificationConfigs/xyz", result.getName());
204+
assertNotNull(result.getPushNotificationConfig());
205+
assertEquals("http://example.com", result.getPushNotificationConfig().getUrl());
206+
assertEquals("xyz", result.getPushNotificationConfig().getId());
207+
assertEquals(false, result.getPushNotificationConfig().hasAuthentication());
208+
taskPushConfig
209+
= new TaskPushNotificationConfig("push-task-123",
210+
new PushNotificationConfig.Builder()
211+
.token("AAAAAA")
212+
.authenticationInfo(new PushNotificationAuthenticationInfo(Collections.singletonList("jwt"), "credentials"))
213+
.url("http://example.com")
214+
.id("xyz")
215+
.build());
216+
result = ProtoUtils.ToProto.taskPushNotificationConfig(taskPushConfig);
217+
assertEquals("tasks/push-task-123/pushNotificationConfigs/xyz", result.getName());
218+
assertNotNull(result.getPushNotificationConfig());
219+
assertEquals("http://example.com", result.getPushNotificationConfig().getUrl());
220+
assertEquals("xyz", result.getPushNotificationConfig().getId());
221+
assertEquals("AAAAAA", result.getPushNotificationConfig().getToken());
222+
assertEquals(true, result.getPushNotificationConfig().hasAuthentication());
223+
assertEquals("credentials", result.getPushNotificationConfig().getAuthentication().getCredentials());
224+
assertEquals(1, result.getPushNotificationConfig().getAuthentication().getSchemesCount());
225+
assertEquals("jwt", result.getPushNotificationConfig().getAuthentication().getSchemes(0));
226+
}
227+
228+
@Test
229+
public void convertTaskArtifactUpdateEvent() {
230+
TaskArtifactUpdateEvent task = new TaskArtifactUpdateEvent.Builder()
231+
.taskId("task-123")
232+
.contextId("session-123")
233+
.artifact(new Artifact.Builder()
234+
.artifactId("11")
235+
.parts(new TextPart("text"))
236+
.build()).build();
237+
io.a2a.grpc.TaskArtifactUpdateEvent result = ProtoUtils.ToProto.taskArtifactUpdateEvent(task);
238+
assertEquals("task-123", result.getTaskId());
239+
assertEquals("session-123", result.getContextId());
240+
assertNotNull(result.getArtifact());
241+
assertEquals("11", result.getArtifact().getArtifactId());
242+
assertEquals(1, result.getArtifact().getPartsCount());
243+
assertEquals("text", result.getArtifact().getParts(0).getText());
244+
}
245+
246+
@Test
247+
public void convertTaskStatusUpdateEvent() {
248+
TaskStatusUpdateEvent tsue = new TaskStatusUpdateEvent.Builder()
249+
.taskId("1234")
250+
.contextId("xyz")
251+
.status(new TaskStatus(TaskState.COMPLETED))
252+
.isFinal(true)
253+
.build();
254+
io.a2a.grpc.TaskStatusUpdateEvent result = ProtoUtils.ToProto.taskStatusUpdateEvent(tsue);
255+
assertEquals("1234", result.getTaskId());
256+
assertEquals("xyz", result.getContextId());
257+
assertEquals(true, result.getFinal());
258+
assertEquals(io.a2a.grpc.TaskState.TASK_STATE_COMPLETED, result.getStatus().getState());
259+
}
260+
261+
@Test
262+
public void convertSendMessageConfiguration() {
263+
MessageSendConfiguration configuration = new MessageSendConfiguration.Builder()
264+
.acceptedOutputModes(List.of("text"))
265+
.blocking(false)
266+
.build();
267+
SendMessageConfiguration result = ProtoUtils.ToProto.messageSendConfiguration(configuration);
268+
assertEquals(false, result.getBlocking());
269+
assertEquals(1, result.getAcceptedOutputModesCount());
270+
assertEquals("text", result.getAcceptedOutputModesBytes(0).toStringUtf8());
271+
}
272+
}

0 commit comments

Comments
 (0)