feat: add ArtifactUtils utility class and corresponding tests (#303)#350
feat: add ArtifactUtils utility class and corresponding tests (#303)#350fjuma merged 4 commits intoa2aproject:mainfrom
Conversation
…onding unit tests
Summary of ChangesHello @leehuiseok, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a new Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a helpful ArtifactUtils class for creating Artifact instances. The implementation is clean and the tests are comprehensive. I have a few suggestions to improve consistency and maintainability:
- Use
nullinstead of an empty string for optional descriptions to better represent their absence. - Update the corresponding tests to assert for
null. - Refactor test data creation to consistently use
Map.of()for conciseness. - Remove a couple of redundant tests to streamline the test suite.
Overall, this is a solid addition.
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newArtifact(List<Part<?>> parts, String name) { | ||
| return newArtifact(parts, name, ""); |
There was a problem hiding this comment.
It's better to use null instead of an empty string ("") for an optional parameter that is not provided. This indicates the absence of a value more clearly and works well with Jackson's NON_ABSENT inclusion strategy on the Artifact record, preventing the serialization of an empty description field.
| return newArtifact(parts, name, ""); | |
| return newArtifact(parts, name, null); |
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newTextArtifact(String name, String text) { | ||
| return newTextArtifact(name, text, ""); |
There was a problem hiding this comment.
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newDataArtifact(String name, Map<String, Object> data) { | ||
| return newDataArtifact(name, data, ""); |
There was a problem hiding this comment.
| Artifact artifact = ArtifactUtils.newArtifact(parts, name); | ||
|
|
||
| // Then | ||
| assertEquals("", artifact.description()); |
There was a problem hiding this comment.
Following the suggestion to use null for absent descriptions instead of an empty string, this assertion should be updated to check for null. You will need to add import static org.junit.jupiter.api.Assertions.assertNull;.
| assertEquals("", artifact.description()); | |
| assertNull(artifact.description()); |
| Map<String, Object> sampleData = new HashMap<>(); | ||
| sampleData.put("key", "value"); | ||
| sampleData.put("number", 123); |
There was a problem hiding this comment.
For creating small, immutable maps for test data, Map.of() is more concise and generally preferred over instantiating a HashMap and populating it. This also improves consistency with other tests in this file that use Map.of().
| Map<String, Object> sampleData = new HashMap<>(); | |
| sampleData.put("key", "value"); | |
| sampleData.put("number", 123); | |
| Map<String, Object> sampleData = Map.of("key", "value", "number", 123); |
| Map<String, Object> sampleData = new HashMap<>(); | ||
| sampleData.put("content", "test_data"); | ||
| sampleData.put("is_valid", true); |
There was a problem hiding this comment.
For creating small, immutable maps for test data, Map.of() is more concise and generally preferred over instantiating a HashMap and populating it.
| Map<String, Object> sampleData = new HashMap<>(); | |
| sampleData.put("content", "test_data"); | |
| sampleData.put("is_valid", true); | |
| Map<String, Object> sampleData = Map.of("content", "test_data", "is_valid", true); |
| Map<String, Object> sampleData = new HashMap<>(); | ||
| sampleData.put("info", "some details"); |
There was a problem hiding this comment.
For creating small, immutable maps for test data, Map.of() is more concise and generally preferred over instantiating a HashMap and populating it.
| Map<String, Object> sampleData = new HashMap<>(); | |
| sampleData.put("info", "some details"); | |
| Map<String, Object> sampleData = Map.of("info", "some details"); |
| @Test | ||
| void testNewTextArtifactWithEmptyDescription() { | ||
| // Given | ||
| String text = "Test content"; | ||
| String name = "Test_Artifact"; | ||
|
|
||
| // When | ||
| Artifact artifact = ArtifactUtils.newTextArtifact(name, text); | ||
|
|
||
| // Then | ||
| assertEquals("", artifact.description()); | ||
| } | ||
|
|
||
| @Test | ||
| void testNewDataArtifactWithEmptyDescription() { | ||
| // Given | ||
| Map<String, Object> data = Map.of("test", "value"); | ||
| String name = "Test_Data_Artifact"; | ||
|
|
||
| // When | ||
| Artifact artifact = ArtifactUtils.newDataArtifact(name, data); | ||
|
|
||
| // Then | ||
| assertEquals("", artifact.description()); | ||
| } |
There was a problem hiding this comment.
The tests testNewTextArtifactWithEmptyDescription and testNewDataArtifactWithEmptyDescription are redundant. The logic for handling an empty (or null) description is centralized in ArtifactUtils.newArtifact(...), which is already tested by testNewArtifactEmptyDescriptionIfNotProvided. Since the other factory methods delegate to this one, these additional tests don't add new coverage and can be removed to keep the test suite concise.
|
@leehuiseok may you address Gemini's comments ? |
… simplify test data initialization
|
@ehsavoie |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces the ArtifactUtils utility class with corresponding unit tests to simplify the creation of Artifact instances. The utility class provides static helper methods for creating artifacts with different content types, ensuring consistent ID generation and description handling. The unit tests cover UUID generation, assignment of name, description, and parts, and correct creation of text-based and data-based artifacts. I have provided comments to address potential issues related to null description handling and test coverage.
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newArtifact(List<Part<?>> parts, String name) { | ||
| return newArtifact(parts, name, null); |
There was a problem hiding this comment.
The current implementation passes null as the description when it's not provided. It might be better to pass an empty string ("") instead to avoid potential null pointer exceptions when the description is accessed elsewhere. This provides a default value and ensures consistency.
Consider updating the newArtifact method to handle null descriptions by defaulting to an empty string.
public static Artifact newArtifact(List<Part<?>> parts, String name) {
return newArtifact(parts, name, ""); // Provide an empty string as default description
}There was a problem hiding this comment.
null avoid serializing it to json
There was a problem hiding this comment.
I aligned with your suggestion to keep description as null by default so that it’s omitted from JSON (@JsonInclude(NON_NULL)). Tests now assert null accordingly.
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newTextArtifact(String name, String text) { | ||
| return newTextArtifact(name, text, null); |
There was a problem hiding this comment.
The current implementation passes null as the description when it's not provided. It might be better to pass an empty string ("") instead to avoid potential null pointer exceptions when the description is accessed elsewhere. This provides a default value and ensures consistency.
Consider updating the newTextArtifact method to handle null descriptions by defaulting to an empty string.
public static Artifact newTextArtifact(String name, String text) {
return newTextArtifact(name, text, ""); // Provide an empty string as default description
}There was a problem hiding this comment.
null avoid serializing the description in json
There was a problem hiding this comment.
I aligned with your suggestion to keep description as null by default so that it’s omitted from JSON (@JsonInclude(NON_NULL)). Tests now assert null accordingly.
ehsavoie
left a comment
There was a problem hiding this comment.
Maybe add methods with a Metadata parameter
server-common/src/test/java/io/a2a/server/util/ArtifactUtilsTest.java
Outdated
Show resolved
Hide resolved
server-common/src/test/java/io/a2a/server/util/ArtifactUtilsTest.java
Outdated
Show resolved
Hide resolved
| * @param name The human-readable name of the artifact. | ||
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newArtifact(List<Part<?>> parts, String name) { |
There was a problem hiding this comment.
Maybe switch the parameters order to match the other methods
| * @param description An optional description of the artifact. | ||
| * @return A new {@code Artifact} object with a generated artifact_id. | ||
| */ | ||
| public static Artifact newArtifact(List<Part<?>> parts, String name, String description) { |
There was a problem hiding this comment.
Maybe switch the parameters order to match the other methods
…unit tests for artifact creation
…ject#303) (a2aproject#350) ## feat: add `ArtifactUtils` utility class and corresponding unit tests ### Description This PR introduces the `ArtifactUtils` utility class, which provides a set of static helper methods for creating `Artifact` instances in a standardized and concise way. It simplifies the creation of artifacts with different content types (`TextPart`, `DataPart`, etc.) while ensuring consistent ID generation and description handling. ### Details - Added `ArtifactUtils` as a `final` utility class with a private constructor to prevent instantiation. - Implemented multiple overloaded factory methods for flexible artifact creation: - `newArtifact(List<Part<?>> parts, String name, String description)` - `newArtifact(List<Part<?>> parts, String name)` - `newTextArtifact(String name, String text, String description)` - `newTextArtifact(String name, String text)` - `newDataArtifact(String name, Map<String, Object> data, String description)` - `newDataArtifact(String name, Map<String, Object> data)` - Each artifact automatically receives a unique `artifactId` via `UUID.randomUUID()`. - Uses `List.of()` for concise creation of single-part artifacts (`TextPart`, `DataPart`). ### Tests Added comprehensive unit tests in `ArtifactUtilsTest` to verify: - UUID generation through mocking - Proper assignment of `name`, `description`, and `parts` - Correct creation of both text-based and data-based artifacts - Non-null and non-empty `artifactId` values ### Example Usage ```java Artifact textArtifact = ArtifactUtils.newTextArtifact("User Profile", "Basic user info"); Artifact dataArtifact = ArtifactUtils.newDataArtifact("Config", Map.of("version", "1.0")); ``` Fixes:a2aproject#303
feat: add
ArtifactUtilsutility class and corresponding unit testsDescription
This PR introduces the
ArtifactUtilsutility class, which provides a set of static helper methods for creatingArtifactinstances in a standardized and concise way.It simplifies the creation of artifacts with different content types (
TextPart,DataPart, etc.) while ensuring consistent ID generation and description handling.Details
ArtifactUtilsas afinalutility class with a private constructor to prevent instantiation.newArtifact(List<Part<?>> parts, String name, String description)newArtifact(List<Part<?>> parts, String name)newTextArtifact(String name, String text, String description)newTextArtifact(String name, String text)newDataArtifact(String name, Map<String, Object> data, String description)newDataArtifact(String name, Map<String, Object> data)artifactIdviaUUID.randomUUID().List.of()for concise creation of single-part artifacts (TextPart,DataPart).Tests
Added comprehensive unit tests in
ArtifactUtilsTestto verify:name,description, andpartsartifactIdvaluesExample Usage
Fixes:#303