Skip to content

Commit 269d35a

Browse files
misselvexukabir
authored andcommitted
test: improve TaskManager test coverage
1 parent 0238c29 commit 269d35a

File tree

1 file changed

+355
-0
lines changed

1 file changed

+355
-0
lines changed

server-common/src/test/java/io/a2a/server/tasks/TaskManagerTest.java

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertNotSame;
5+
import static org.junit.jupiter.api.Assertions.assertNotNull;
56
import static org.junit.jupiter.api.Assertions.assertNull;
67
import static org.junit.jupiter.api.Assertions.assertSame;
8+
import static org.junit.jupiter.api.Assertions.assertThrows;
9+
import static org.junit.jupiter.api.Assertions.assertTrue;
10+
import static org.junit.jupiter.api.Assertions.assertThrows;
11+
import static org.junit.jupiter.api.Assertions.assertTrue;
712

813
import java.util.Collections;
914
import java.util.HashMap;
15+
import java.util.List;
1016

1117
import io.a2a.spec.A2AServerException;
1218
import io.a2a.spec.Artifact;
@@ -175,4 +181,353 @@ public void testGetTaskNoTaskId() {
175181
Task retrieved = taskManagerWithoutId.getTask();
176182
assertNull(retrieved);
177183
}
184+
185+
// Additional tests for missing coverage scenarios
186+
187+
@Test
188+
public void testTaskArtifactUpdateEventAppendTrueWithExistingArtifact() throws A2AServerException {
189+
// Setup: Create a task with an existing artifact
190+
Task initialTask = minimalTask;
191+
Artifact existingArtifact = new Artifact.Builder()
192+
.artifactId("artifact-id")
193+
.name("artifact-1")
194+
.parts(Collections.singletonList(new TextPart("existing content")))
195+
.build();
196+
Task taskWithArtifact = new Task.Builder(initialTask)
197+
.artifacts(Collections.singletonList(existingArtifact))
198+
.build();
199+
taskStore.save(taskWithArtifact);
200+
201+
// Test: Append new parts to existing artifact
202+
Artifact newArtifact = new Artifact.Builder()
203+
.artifactId("artifact-id")
204+
.name("artifact-1")
205+
.parts(Collections.singletonList(new TextPart("new content")))
206+
.build();
207+
TaskArtifactUpdateEvent event = new TaskArtifactUpdateEvent.Builder()
208+
.taskId(minimalTask.getId())
209+
.contextId(minimalTask.getContextId())
210+
.artifact(newArtifact)
211+
.append(true)
212+
.build();
213+
214+
Task saved = taskManager.saveTaskEvent(event);
215+
Task updatedTask = taskManager.getTask();
216+
217+
assertEquals(1, updatedTask.getArtifacts().size());
218+
Artifact updatedArtifact = updatedTask.getArtifacts().get(0);
219+
assertEquals("artifact-id", updatedArtifact.artifactId());
220+
assertEquals(2, updatedArtifact.parts().size());
221+
assertEquals("existing content", ((TextPart) updatedArtifact.parts().get(0)).getText());
222+
assertEquals("new content", ((TextPart) updatedArtifact.parts().get(1)).getText());
223+
}
224+
225+
@Test
226+
public void testTaskArtifactUpdateEventAppendTrueWithoutExistingArtifact() throws A2AServerException {
227+
// Setup: Create a task without artifacts
228+
Task initialTask = minimalTask;
229+
taskStore.save(initialTask);
230+
231+
// Test: Try to append to non-existent artifact (should be ignored)
232+
Artifact newArtifact = new Artifact.Builder()
233+
.artifactId("artifact-id")
234+
.name("artifact-1")
235+
.parts(Collections.singletonList(new TextPart("new content")))
236+
.build();
237+
TaskArtifactUpdateEvent event = new TaskArtifactUpdateEvent.Builder()
238+
.taskId(minimalTask.getId())
239+
.contextId(minimalTask.getContextId())
240+
.artifact(newArtifact)
241+
.append(true)
242+
.build();
243+
244+
Task saved = taskManager.saveTaskEvent(event);
245+
Task updatedTask = taskManager.getTask();
246+
247+
// Should have no artifacts since append was ignored
248+
assertEquals(0, updatedTask.getArtifacts().size());
249+
}
250+
251+
@Test
252+
public void testTaskArtifactUpdateEventAppendFalseWithExistingArtifact() throws A2AServerException {
253+
// Setup: Create a task with an existing artifact
254+
Task initialTask = minimalTask;
255+
Artifact existingArtifact = new Artifact.Builder()
256+
.artifactId("artifact-id")
257+
.name("artifact-1")
258+
.parts(Collections.singletonList(new TextPart("existing content")))
259+
.build();
260+
Task taskWithArtifact = new Task.Builder(initialTask)
261+
.artifacts(Collections.singletonList(existingArtifact))
262+
.build();
263+
taskStore.save(taskWithArtifact);
264+
265+
// Test: Replace existing artifact (append=false)
266+
Artifact newArtifact = new Artifact.Builder()
267+
.artifactId("artifact-id")
268+
.name("artifact-1")
269+
.parts(Collections.singletonList(new TextPart("replacement content")))
270+
.build();
271+
TaskArtifactUpdateEvent event = new TaskArtifactUpdateEvent.Builder()
272+
.taskId(minimalTask.getId())
273+
.contextId(minimalTask.getContextId())
274+
.artifact(newArtifact)
275+
.append(false)
276+
.build();
277+
278+
Task saved = taskManager.saveTaskEvent(event);
279+
Task updatedTask = taskManager.getTask();
280+
281+
assertEquals(1, updatedTask.getArtifacts().size());
282+
Artifact updatedArtifact = updatedTask.getArtifacts().get(0);
283+
assertEquals("artifact-id", updatedArtifact.artifactId());
284+
assertEquals(1, updatedArtifact.parts().size());
285+
assertEquals("replacement content", ((TextPart) updatedArtifact.parts().get(0)).getText());
286+
}
287+
288+
@Test
289+
public void testTaskArtifactUpdateEventAppendNullWithExistingArtifact() throws A2AServerException {
290+
// Setup: Create a task with an existing artifact
291+
Task initialTask = minimalTask;
292+
Artifact existingArtifact = new Artifact.Builder()
293+
.artifactId("artifact-id")
294+
.name("artifact-1")
295+
.parts(Collections.singletonList(new TextPart("existing content")))
296+
.build();
297+
Task taskWithArtifact = new Task.Builder(initialTask)
298+
.artifacts(Collections.singletonList(existingArtifact))
299+
.build();
300+
taskStore.save(taskWithArtifact);
301+
302+
// Test: Replace existing artifact (append=null, defaults to false)
303+
Artifact newArtifact = new Artifact.Builder()
304+
.artifactId("artifact-id")
305+
.name("artifact-1")
306+
.parts(Collections.singletonList(new TextPart("replacement content")))
307+
.build();
308+
TaskArtifactUpdateEvent event = new TaskArtifactUpdateEvent.Builder()
309+
.taskId(minimalTask.getId())
310+
.contextId(minimalTask.getContextId())
311+
.artifact(newArtifact)
312+
.build(); // append is null
313+
314+
Task saved = taskManager.saveTaskEvent(event);
315+
Task updatedTask = taskManager.getTask();
316+
317+
assertEquals(1, updatedTask.getArtifacts().size());
318+
Artifact updatedArtifact = updatedTask.getArtifacts().get(0);
319+
assertEquals("artifact-id", updatedArtifact.artifactId());
320+
assertEquals(1, updatedArtifact.parts().size());
321+
assertEquals("replacement content", ((TextPart) updatedArtifact.parts().get(0)).getText());
322+
}
323+
324+
@Test
325+
public void testAddingTaskWithDifferentIdFails() {
326+
// Test that adding a task with a different id from the taskmanager's taskId fails
327+
TaskManager taskManagerWithId = new TaskManager("task-abc", "session-xyz", taskStore, null);
328+
329+
Task differentTask = new Task.Builder()
330+
.id("different-task-id")
331+
.contextId("session-xyz")
332+
.status(new TaskStatus(TaskState.SUBMITTED))
333+
.build();
334+
335+
assertThrows(A2AServerException.class, () -> {
336+
taskManagerWithId.saveTaskEvent(differentTask);
337+
});
338+
}
339+
340+
@Test
341+
public void testAddingTaskWithDifferentIdViaStatusUpdateFails() {
342+
// Test that adding a status update with different taskId fails
343+
TaskManager taskManagerWithId = new TaskManager("task-abc", "session-xyz", taskStore, null);
344+
345+
TaskStatusUpdateEvent event = new TaskStatusUpdateEvent.Builder()
346+
.taskId("different-task-id")
347+
.contextId("session-xyz")
348+
.status(new TaskStatus(TaskState.WORKING))
349+
.isFinal(false)
350+
.build();
351+
352+
assertThrows(A2AServerException.class, () -> {
353+
taskManagerWithId.saveTaskEvent(event);
354+
});
355+
}
356+
357+
@Test
358+
public void testAddingTaskWithDifferentIdViaArtifactUpdateFails() {
359+
// Test that adding an artifact update with different taskId fails
360+
TaskManager taskManagerWithId = new TaskManager("task-abc", "session-xyz", taskStore, null);
361+
362+
Artifact artifact = new Artifact.Builder()
363+
.artifactId("artifact-id")
364+
.name("artifact-1")
365+
.parts(Collections.singletonList(new TextPart("content")))
366+
.build();
367+
TaskArtifactUpdateEvent event = new TaskArtifactUpdateEvent.Builder()
368+
.taskId("different-task-id")
369+
.contextId("session-xyz")
370+
.artifact(artifact)
371+
.build();
372+
373+
assertThrows(A2AServerException.class, () -> {
374+
taskManagerWithId.saveTaskEvent(event);
375+
});
376+
}
377+
378+
@Test
379+
public void testTaskWithNoMessageUsesInitialMessage() throws A2AServerException {
380+
// Test that adding a task with no message, and there is a TaskManager.initialMessage,
381+
// the initialMessage gets used
382+
Message initialMessage = new Message.Builder()
383+
.role(Message.Role.USER)
384+
.parts(Collections.singletonList(new TextPart("initial message")))
385+
.messageId("initial-msg-id")
386+
.build();
387+
388+
TaskManager taskManagerWithInitialMessage = new TaskManager(null, null, taskStore, initialMessage);
389+
390+
// Use a status update event instead of a Task to trigger createTask
391+
TaskStatusUpdateEvent event = new TaskStatusUpdateEvent.Builder()
392+
.taskId("new-task-id")
393+
.contextId("some-context")
394+
.status(new TaskStatus(TaskState.SUBMITTED))
395+
.isFinal(false)
396+
.build();
397+
398+
Task saved = taskManagerWithInitialMessage.saveTaskEvent(event);
399+
Task retrieved = taskManagerWithInitialMessage.getTask();
400+
401+
// Check that the task has the initial message in its history
402+
assertNotNull(retrieved.getHistory());
403+
assertEquals(1, retrieved.getHistory().size());
404+
Message historyMessage = retrieved.getHistory().get(0);
405+
assertEquals(initialMessage.getMessageId(), historyMessage.getMessageId());
406+
assertEquals(initialMessage.getRole(), historyMessage.getRole());
407+
assertEquals("initial message", ((TextPart) historyMessage.getParts().get(0)).getText());
408+
}
409+
410+
@Test
411+
public void testTaskWithMessageDoesNotUseInitialMessage() throws A2AServerException {
412+
// Test that adding a task with a message does not use the initial message
413+
Message initialMessage = new Message.Builder()
414+
.role(Message.Role.USER)
415+
.parts(Collections.singletonList(new TextPart("initial message")))
416+
.messageId("initial-msg-id")
417+
.build();
418+
419+
TaskManager taskManagerWithInitialMessage = new TaskManager(null, null, taskStore, initialMessage);
420+
421+
Message taskMessage = new Message.Builder()
422+
.role(Message.Role.AGENT)
423+
.parts(Collections.singletonList(new TextPart("task message")))
424+
.messageId("task-msg-id")
425+
.build();
426+
427+
Task taskWithMessage = new Task.Builder()
428+
.id("new-task-id")
429+
.contextId("some-context")
430+
.status(new TaskStatus(TaskState.SUBMITTED, taskMessage, null))
431+
.build();
432+
433+
Task saved = taskManagerWithInitialMessage.saveTaskEvent(taskWithMessage);
434+
Task retrieved = taskManagerWithInitialMessage.getTask();
435+
436+
// Check that the task does not have the initial message in its history
437+
assertNull(retrieved.getHistory());
438+
}
439+
440+
@Test
441+
public void testMultipleArtifactsWithSameArtifactId() throws A2AServerException {
442+
// Test handling of multiple artifacts with the same artifactId
443+
Task initialTask = minimalTask;
444+
taskStore.save(initialTask);
445+
446+
// Add first artifact
447+
Artifact artifact1 = new Artifact.Builder()
448+
.artifactId("artifact-id")
449+
.name("artifact-1")
450+
.parts(Collections.singletonList(new TextPart("content 1")))
451+
.build();
452+
TaskArtifactUpdateEvent event1 = new TaskArtifactUpdateEvent.Builder()
453+
.taskId(minimalTask.getId())
454+
.contextId(minimalTask.getContextId())
455+
.artifact(artifact1)
456+
.build();
457+
taskManager.saveTaskEvent(event1);
458+
459+
// Add second artifact with same artifactId (should replace the first)
460+
Artifact artifact2 = new Artifact.Builder()
461+
.artifactId("artifact-id")
462+
.name("artifact-2")
463+
.parts(Collections.singletonList(new TextPart("content 2")))
464+
.build();
465+
TaskArtifactUpdateEvent event2 = new TaskArtifactUpdateEvent.Builder()
466+
.taskId(minimalTask.getId())
467+
.contextId(minimalTask.getContextId())
468+
.artifact(artifact2)
469+
.build();
470+
taskManager.saveTaskEvent(event2);
471+
472+
Task updatedTask = taskManager.getTask();
473+
assertEquals(1, updatedTask.getArtifacts().size());
474+
Artifact finalArtifact = updatedTask.getArtifacts().get(0);
475+
assertEquals("artifact-id", finalArtifact.artifactId());
476+
assertEquals("artifact-2", finalArtifact.name());
477+
assertEquals("content 2", ((TextPart) finalArtifact.parts().get(0)).getText());
478+
}
479+
480+
@Test
481+
public void testMultipleArtifactsWithDifferentArtifactIds() throws A2AServerException {
482+
// Test handling of multiple artifacts with different artifactIds
483+
Task initialTask = minimalTask;
484+
taskStore.save(initialTask);
485+
486+
// Add first artifact
487+
Artifact artifact1 = new Artifact.Builder()
488+
.artifactId("artifact-id-1")
489+
.name("artifact-1")
490+
.parts(Collections.singletonList(new TextPart("content 1")))
491+
.build();
492+
TaskArtifactUpdateEvent event1 = new TaskArtifactUpdateEvent.Builder()
493+
.taskId(minimalTask.getId())
494+
.contextId(minimalTask.getContextId())
495+
.artifact(artifact1)
496+
.build();
497+
taskManager.saveTaskEvent(event1);
498+
499+
// Add second artifact with different artifactId (should be added)
500+
Artifact artifact2 = new Artifact.Builder()
501+
.artifactId("artifact-id-2")
502+
.name("artifact-2")
503+
.parts(Collections.singletonList(new TextPart("content 2")))
504+
.build();
505+
TaskArtifactUpdateEvent event2 = new TaskArtifactUpdateEvent.Builder()
506+
.taskId(minimalTask.getId())
507+
.contextId(minimalTask.getContextId())
508+
.artifact(artifact2)
509+
.build();
510+
taskManager.saveTaskEvent(event2);
511+
512+
Task updatedTask = taskManager.getTask();
513+
assertEquals(2, updatedTask.getArtifacts().size());
514+
515+
// Verify both artifacts are present
516+
List<Artifact> artifacts = updatedTask.getArtifacts();
517+
boolean foundArtifact1 = false;
518+
boolean foundArtifact2 = false;
519+
520+
for (Artifact artifact : artifacts) {
521+
if ("artifact-id-1".equals(artifact.artifactId())) {
522+
foundArtifact1 = true;
523+
assertEquals("content 1", ((TextPart) artifact.parts().get(0)).getText());
524+
} else if ("artifact-id-2".equals(artifact.artifactId())) {
525+
foundArtifact2 = true;
526+
assertEquals("content 2", ((TextPart) artifact.parts().get(0)).getText());
527+
}
528+
}
529+
530+
assertTrue(foundArtifact1, "Artifact 1 should be present");
531+
assertTrue(foundArtifact2, "Artifact 2 should be present");
532+
}
178533
}

0 commit comments

Comments
 (0)