From 46a5a663b8f4257765d23753265f96540062c685 Mon Sep 17 00:00:00 2001 From: Oleksandr Klymenko Date: Wed, 17 Sep 2025 16:57:54 +0200 Subject: [PATCH] Add comprehensive edge case and boundary testing for Google GenAI components Co-authored-by: Oleksandr Klymenko Signed-off-by: Oleksandr Klymenko --- .../genai/CreateGeminiRequestTests.java | 78 +++++++++++++++++++ .../genai/GoogleGenAiChatOptionsTest.java | 14 ++++ .../schema/JsonSchemaConverterTests.java | 20 +++++ 3 files changed, 112 insertions(+) diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/CreateGeminiRequestTests.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/CreateGeminiRequestTests.java index 89b08bd4e43..4f7abbaceec 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/CreateGeminiRequestTests.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/CreateGeminiRequestTests.java @@ -340,4 +340,82 @@ public void createRequestWithThinkingBudgetOverride() { assertThat(request.config().thinkingConfig().get().thinkingBudget().get()).isEqualTo(25000); } + @Test + public void createRequestWithNullThinkingBudget() { + var client = GoogleGenAiChatModel.builder() + .genAiClient(this.genAiClient) + .defaultOptions(GoogleGenAiChatOptions.builder().model("DEFAULT_MODEL").thinkingBudget(null).build()) + .build(); + + GeminiRequest request = client + .createGeminiRequest(client.buildRequestPrompt(new Prompt("Test message content"))); + + assertThat(request.contents()).hasSize(1); + assertThat(request.modelName()).isEqualTo("DEFAULT_MODEL"); + + // Verify thinkingConfig is not present when thinkingBudget is null + assertThat(request.config().thinkingConfig()).isEmpty(); + } + + @Test + public void createRequestWithZeroThinkingBudget() { + var client = GoogleGenAiChatModel.builder() + .genAiClient(this.genAiClient) + .defaultOptions(GoogleGenAiChatOptions.builder().model("DEFAULT_MODEL").thinkingBudget(0).build()) + .build(); + + GeminiRequest request = client + .createGeminiRequest(client.buildRequestPrompt(new Prompt("Test message content"))); + + assertThat(request.config().thinkingConfig()).isPresent(); + assertThat(request.config().thinkingConfig().get().thinkingBudget()).isPresent(); + assertThat(request.config().thinkingConfig().get().thinkingBudget().get()).isEqualTo(0); + } + + @Test + public void createRequestWithNoMessages() { + var client = GoogleGenAiChatModel.builder() + .genAiClient(this.genAiClient) + .defaultOptions(GoogleGenAiChatOptions.builder().model("DEFAULT_MODEL").build()) + .build(); + + GeminiRequest request = client.createGeminiRequest(client.buildRequestPrompt(new Prompt(List.of()))); + + assertThat(request.contents()).isEmpty(); + } + + @Test + public void createRequestWithOnlySystemMessage() { + var systemMessage = new SystemMessage("System Message Only"); + + var client = GoogleGenAiChatModel.builder() + .genAiClient(this.genAiClient) + .defaultOptions(GoogleGenAiChatOptions.builder().model("DEFAULT_MODEL").build()) + .build(); + + GeminiRequest request = client + .createGeminiRequest(client.buildRequestPrompt(new Prompt(List.of(systemMessage)))); + + assertThat(request.config().systemInstruction()).isPresent(); + assertThat(request.contents()).isEmpty(); + } + + @Test + public void createRequestWithLabels() { + var client = GoogleGenAiChatModel.builder() + .genAiClient(this.genAiClient) + .defaultOptions(GoogleGenAiChatOptions.builder() + .model("DEFAULT_MODEL") + .labels(java.util.Map.of("org", "my-org", "env", "test")) + .build()) + .build(); + + GeminiRequest request = client + .createGeminiRequest(client.buildRequestPrompt(new Prompt("Test message content"))); + + assertThat(request.config().labels()).isPresent(); + assertThat(request.config().labels().get()).containsEntry("org", "my-org"); + assertThat(request.config().labels().get()).containsEntry("env", "test"); + } + } diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatOptionsTest.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatOptionsTest.java index 3521213bfb5..c3f78a2ab02 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatOptionsTest.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/GoogleGenAiChatOptionsTest.java @@ -153,4 +153,18 @@ public void testToStringWithLabels() { assertThat(toString).contains("test-model"); } + @Test + public void testThinkingBudgetWithZeroValue() { + GoogleGenAiChatOptions options = GoogleGenAiChatOptions.builder().thinkingBudget(0).build(); + + assertThat(options.getThinkingBudget()).isEqualTo(0); + } + + @Test + public void testLabelsWithEmptyMap() { + GoogleGenAiChatOptions options = GoogleGenAiChatOptions.builder().labels(Map.of()).build(); + + assertThat(options.getLabels()).isEmpty(); + } + } diff --git a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/schema/JsonSchemaConverterTests.java b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/schema/JsonSchemaConverterTests.java index a32e776f859..7764da7f7fd 100644 --- a/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/schema/JsonSchemaConverterTests.java +++ b/models/spring-ai-google-genai/src/test/java/org/springframework/ai/google/genai/schema/JsonSchemaConverterTests.java @@ -54,6 +54,26 @@ void convertToOpenApiSchemaShouldThrowOnNullInput() { .hasMessage("JSON Schema node must not be null"); } + @Test + void fromJsonShouldHandleEmptyObject() { + String json = "{}"; + ObjectNode result = JsonSchemaConverter.fromJson(json); + + assertThat(result).isNotNull(); + assertThat(result.size()).isEqualTo(0); + } + + @Test + void fromJsonShouldHandleEmptyString() { + assertThatThrownBy(() -> JsonSchemaConverter.fromJson("")).isInstanceOf(RuntimeException.class) + .hasMessageContaining("Failed to parse JSON"); + } + + @Test + void fromJsonShouldHandleNullInput() { + assertThatThrownBy(() -> JsonSchemaConverter.fromJson(null)).isInstanceOf(RuntimeException.class); + } + @Nested class SchemaConversionTests {