From c17c6c0404a05ff66904108ddf91c2d25c40c91b Mon Sep 17 00:00:00 2001 From: Oleksandr Klymenko Date: Tue, 30 Sep 2025 00:35:00 +0200 Subject: [PATCH] test: add test coverage for SyncMcpToolCallback.Builder Co-authored-by: Oleksandr Klymenko Signed-off-by: Oleksandr Klymenko --- .../mcp/SyncMcpToolCallbackBuilderTest.java | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/mcp/common/src/test/java/org/springframework/ai/mcp/SyncMcpToolCallbackBuilderTest.java b/mcp/common/src/test/java/org/springframework/ai/mcp/SyncMcpToolCallbackBuilderTest.java index 5f5d4a68c09..5915470352b 100644 --- a/mcp/common/src/test/java/org/springframework/ai/mcp/SyncMcpToolCallbackBuilderTest.java +++ b/mcp/common/src/test/java/org/springframework/ai/mcp/SyncMcpToolCallbackBuilderTest.java @@ -123,4 +123,95 @@ void builderShouldSupportMethodChaining() { assertThat(callback.getToolDefinition().name()).isEqualTo("chained_tool_name"); } + @Test + void builderShouldNormalizeToolNameWithSpecialCharacters() { + McpSyncClient mcpClient = Mockito.mock(McpSyncClient.class); + McpSchema.Implementation clientInfo = new McpSchema.Implementation("test-client", "1.0.0"); + when(mcpClient.getClientInfo()).thenReturn(clientInfo); + + Tool tool = Mockito.mock(Tool.class); + when(tool.name()).thenReturn("test-tool-with-dashes"); + when(tool.description()).thenReturn("Test description"); + + SyncMcpToolCallback callback = SyncMcpToolCallback.builder().mcpClient(mcpClient).tool(tool).build(); + + assertThat(callback.getOriginalToolName()).isEqualTo("test-tool-with-dashes"); + assertThat(callback.getToolDefinition().name()).isEqualTo("test_tool_with_dashes"); + } + + @Test + void builderShouldUseCustomPrefixedNameWithoutNormalization() { + McpSyncClient mcpClient = Mockito.mock(McpSyncClient.class); + + Tool tool = Mockito.mock(Tool.class); + when(tool.name()).thenReturn("original-name"); + when(tool.description()).thenReturn("Test description"); + + String customName = "custom-name-with-dashes"; + + SyncMcpToolCallback callback = SyncMcpToolCallback.builder() + .mcpClient(mcpClient) + .tool(tool) + .prefixedToolName(customName) + .build(); + + assertThat(callback.getOriginalToolName()).isEqualTo("original-name"); + assertThat(callback.getToolDefinition().name()).isEqualTo(customName); + } + + @Test + void builderShouldHandlePrefixedToolNameAsNull() { + McpSyncClient mcpClient = Mockito.mock(McpSyncClient.class); + McpSchema.Implementation clientInfo = new McpSchema.Implementation("test-client", "1.0.0"); + when(mcpClient.getClientInfo()).thenReturn(clientInfo); + + Tool tool = Mockito.mock(Tool.class); + when(tool.name()).thenReturn("test-tool"); + when(tool.description()).thenReturn("Description"); + + SyncMcpToolCallback callback = SyncMcpToolCallback.builder() + .mcpClient(mcpClient) + .tool(tool) + .prefixedToolName(null) + .build(); + + // When null, it should use the default normalized name + assertThat(callback).isNotNull(); + assertThat(callback.getToolDefinition().name()).isEqualTo("test_tool"); + } + + @Test + void builderShouldCreateNewInstancesForEachBuild() { + McpSyncClient mcpClient = Mockito.mock(McpSyncClient.class); + McpSchema.Implementation clientInfo = new McpSchema.Implementation("test-client", "1.0.0"); + when(mcpClient.getClientInfo()).thenReturn(clientInfo); + + Tool tool = Mockito.mock(Tool.class); + when(tool.name()).thenReturn("test-tool"); + when(tool.description()).thenReturn("Test description"); + + SyncMcpToolCallback.Builder builder = SyncMcpToolCallback.builder().mcpClient(mcpClient).tool(tool); + + SyncMcpToolCallback callback1 = builder.build(); + SyncMcpToolCallback callback2 = builder.build(); + + assertThat(callback1).isNotSameAs(callback2); + assertThat(callback1.getOriginalToolName()).isEqualTo(callback2.getOriginalToolName()); + } + + @Test + void builderShouldThrowExceptionWhenToolContextConverterIsNull() { + McpSyncClient mcpClient = Mockito.mock(McpSyncClient.class); + Tool tool = Mockito.mock(Tool.class); + when(tool.name()).thenReturn("test-tool"); + when(tool.description()).thenReturn("Test description"); + + assertThatThrownBy(() -> SyncMcpToolCallback.builder() + .mcpClient(mcpClient) + .tool(tool) + .toolContextToMcpMetaConverter(null) + .build()).isInstanceOf(IllegalArgumentException.class) + .hasMessage("ToolContextToMcpMetaConverter must not be null"); + } + }