test: ensure proper resource cleanup in integration tests (#537)

- Add try-finally blocks to guarantee server cleanup on test completion
- Call closeGracefully().block() to ensure synchronous shutdown
- Use try-with-resources for client lifecycle management where applicable
- Prevent resource leaks and potential test flakiness

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
Christian Tzolov 2025-09-04 16:52:21 +02:00 • committed by GitHub
commit 681fe7f90b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 317 additions and 238 deletions

View file

@ -91,7 +91,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(client.initialize()).isNotNull(); assertThat(client.initialize()).isNotNull();
} }
server.closeGracefully(); finally {
server.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -128,7 +130,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.hasMessage("Client must be configured with sampling capabilities"); .hasMessage("Client must be configured with sampling capabilities");
} }
} }
server.closeGracefully(); finally {
server.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -195,7 +199,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE); assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE);
}); });
} }
mcpServer.close(); finally {
mcpServer.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -219,11 +225,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
CreateMessageResult.StopReason.STOP_SEQUENCE); CreateMessageResult.StopReason.STOP_SEQUENCE);
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build();
// Server // Server
CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")),
@ -256,6 +257,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.requestTimeout(Duration.ofSeconds(4)) .requestTimeout(Duration.ofSeconds(4))
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
@ -273,9 +278,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result.model()).isEqualTo("MockModelName"); assertThat(result.model()).isEqualTo("MockModelName");
assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE); assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE);
}); });
}
mcpClient.close(); finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -297,11 +303,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
CreateMessageResult.StopReason.STOP_SEQUENCE); CreateMessageResult.StopReason.STOP_SEQUENCE);
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build();
CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")),
null); null);
@ -329,15 +330,21 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
assertThatExceptionOfType(McpError.class).isThrownBy(() -> { assertThatExceptionOfType(McpError.class).isThrownBy(() -> {
mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())); mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
}).withMessageContaining("1000ms"); }).withMessageContaining("1000ms");
}
mcpClient.close(); finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -370,8 +377,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.hasMessage("Client must be configured with elicitation capabilities"); .hasMessage("Client must be configured with elicitation capabilities");
} }
} }
finally {
server.closeGracefully().block(); server.closeGracefully().block();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient", "webflux" }) @ValueSource(strings = { "httpclient", "webflux" })
@ -425,8 +434,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(response).isNotNull(); assertThat(response).isNotNull();
assertThat(response).isEqualTo(callResponse); assertThat(response).isEqualTo(callResponse);
} }
finally {
mcpServer.closeGracefully().block(); mcpServer.closeGracefully().block();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient", "webflux" }) @ValueSource(strings = { "httpclient", "webflux" })
@ -440,11 +451,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message())); return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build();
CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")),
null); null);
@ -471,6 +477,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
@ -483,10 +494,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result.action()).isEqualTo(McpSchema.ElicitResult.Action.ACCEPT); assertThat(result.action()).isEqualTo(McpSchema.ElicitResult.Action.ACCEPT);
assertThat(result.content().get("message")).isEqualTo("Test message"); assertThat(result.content().get("message")).isEqualTo("Test message");
}); });
}
mcpClient.closeGracefully(); finally {
mcpServer.closeGracefully().block(); mcpServer.closeGracefully().block();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient", "webflux" }) @ValueSource(strings = { "httpclient", "webflux" })
@ -511,11 +523,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message())); return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build();
CallToolResult callResponse = new CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), null); CallToolResult callResponse = new CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), null);
AtomicReference<ElicitResult> resultRef = new AtomicReference<>(); AtomicReference<ElicitResult> resultRef = new AtomicReference<>();
@ -541,6 +548,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
@ -550,10 +562,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
ElicitResult elicitResult = resultRef.get(); ElicitResult elicitResult = resultRef.get();
assertThat(elicitResult).isNull(); assertThat(elicitResult).isNull();
}
mcpClient.closeGracefully(); finally {
mcpServer.closeGracefully().block(); mcpServer.closeGracefully().block();
} }
}
// --------------------------------------- // ---------------------------------------
// Roots Tests // Roots Tests
@ -601,8 +614,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef.get()).containsAll(List.of(roots.get(1), root3)); assertThat(rootsRef.get()).containsAll(List.of(roots.get(1), root3));
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -639,8 +653,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(e).isInstanceOf(McpError.class).hasMessage("Roots not supported"); assertThat(e).isInstanceOf(McpError.class).hasMessage("Roots not supported");
} }
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -668,8 +683,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef.get()).isEmpty(); assertThat(rootsRef.get()).isEmpty();
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -701,8 +717,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef2.get()).containsAll(roots); assertThat(rootsRef2.get()).containsAll(roots);
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -732,8 +749,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef.get()).containsAll(roots); assertThat(rootsRef.get()).containsAll(roots);
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -793,8 +811,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(responseBodyIsNullOrBlank.get()).isFalse(); assertThat(responseBodyIsNullOrBlank.get()).isFalse();
assertThat(response).isNotNull().isEqualTo(callResponse); assertThat(response).isNotNull().isEqualTo(callResponse);
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -830,8 +849,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()))) .isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())))
.withMessageContaining("Timeout on blocking read"); .withMessageContaining("Timeout on blocking read");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -886,8 +906,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(responseBodyIsNullOrBlank.get()).isFalse(); assertThat(responseBodyIsNullOrBlank.get()).isFalse();
assertThat(response).isNotNull().isEqualTo(expectedCallResponse); assertThat(response).isNotNull().isEqualTo(expectedCallResponse);
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -978,8 +999,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(toolsRef.get()).containsAll(List.of(tool2.tool())); assertThat(toolsRef.get()).containsAll(List.of(tool2.tool()));
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -995,8 +1017,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1107,7 +1130,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(notificationMap.get("Another error message").logger()).isEqualTo("test-logger"); assertThat(notificationMap.get("Another error message").logger()).isEqualTo("test-logger");
assertThat(notificationMap.get("Another error message").data()).isEqualTo("Another error message"); assertThat(notificationMap.get("Another error message").data()).isEqualTo("Another error message");
} }
mcpServer.close(); finally {
mcpServer.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1212,7 +1237,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(notificationMap.get("Processing completed").message()).isEqualTo("Processing completed"); assertThat(notificationMap.get("Processing completed").message()).isEqualTo("Processing completed");
} }
finally { finally {
mcpServer.close(); mcpServer.closeGracefully().block();
} }
} }
@ -1262,8 +1287,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(samplingRequest.get().argument().value()).isEqualTo("py"); assertThat(samplingRequest.get().argument().value()).isEqualTo("py");
assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt"); assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1324,8 +1350,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
// Verify execution order // Verify execution order
assertThat(executionOrder.get()).isEqualTo("123"); assertThat(executionOrder.get()).isEqualTo("123");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1400,8 +1427,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}""")); {"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}"""));
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -1454,8 +1482,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text(); String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text();
assertThat(errorMessage).contains("Validation failed"); assertThat(errorMessage).contains("Validation failed");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -1504,8 +1533,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(errorMessage).isEqualTo( assertThat(errorMessage).isEqualTo(
"Response missing structured content which is expected when calling tool with non-empty outputSchema"); "Response missing structured content which is expected when calling tool with non-empty outputSchema");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -1581,8 +1611,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"count":3,"message":"Dynamic execution"}""")); {"count":3,"message":"Dynamic execution"}"""));
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
private double evaluateExpression(String expression) { private double evaluateExpression(String expression) {

View file

@ -66,7 +66,9 @@ public abstract class AbstractStatelessIntegrationTests {
assertThat(client.initialize()).isNotNull(); assertThat(client.initialize()).isNotNull();
} }
server.closeGracefully(); finally {
server.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -126,8 +128,9 @@ public abstract class AbstractStatelessIntegrationTests {
assertThat(response).isNotNull().isEqualTo(callResponse); assertThat(response).isNotNull().isEqualTo(callResponse);
} }
finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -163,8 +166,9 @@ public abstract class AbstractStatelessIntegrationTests {
.isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()))) .isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())))
.withMessageContaining("Timeout on blocking read"); .withMessageContaining("Timeout on blocking read");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -244,8 +248,9 @@ public abstract class AbstractStatelessIntegrationTests {
mcpServer.addTool(tool2); mcpServer.addTool(tool2);
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -261,8 +266,9 @@ public abstract class AbstractStatelessIntegrationTests {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -339,8 +345,9 @@ public abstract class AbstractStatelessIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}""")); {"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}"""));
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -394,8 +401,9 @@ public abstract class AbstractStatelessIntegrationTests {
String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text(); String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text();
assertThat(errorMessage).contains("Validation failed"); assertThat(errorMessage).contains("Validation failed");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -444,8 +452,9 @@ public abstract class AbstractStatelessIntegrationTests {
assertThat(errorMessage).isEqualTo( assertThat(errorMessage).isEqualTo(
"Response missing structured content which is expected when calling tool with non-empty outputSchema"); "Response missing structured content which is expected when calling tool with non-empty outputSchema");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -521,8 +530,9 @@ public abstract class AbstractStatelessIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"count":3,"message":"Dynamic execution"}""")); {"count":3,"message":"Dynamic execution"}"""));
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
private double evaluateExpression(String expression) { private double evaluateExpression(String expression) {

View file

@ -87,7 +87,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(client.initialize()).isNotNull(); assertThat(client.initialize()).isNotNull();
} }
server.closeGracefully(); finally {
server.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -124,7 +126,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.hasMessage("Client must be configured with sampling capabilities"); .hasMessage("Client must be configured with sampling capabilities");
} }
} }
server.closeGracefully(); finally {
server.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -191,7 +195,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE); assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE);
}); });
} }
mcpServer.close(); finally {
mcpServer.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -215,11 +221,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
CreateMessageResult.StopReason.STOP_SEQUENCE); CreateMessageResult.StopReason.STOP_SEQUENCE);
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build();
// Server // Server
CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")),
@ -252,6 +253,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.requestTimeout(Duration.ofSeconds(4)) .requestTimeout(Duration.ofSeconds(4))
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
@ -269,9 +274,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result.model()).isEqualTo("MockModelName"); assertThat(result.model()).isEqualTo("MockModelName");
assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE); assertThat(result.stopReason()).isEqualTo(CreateMessageResult.StopReason.STOP_SEQUENCE);
}); });
}
mcpClient.close(); finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -293,11 +299,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
CreateMessageResult.StopReason.STOP_SEQUENCE); CreateMessageResult.StopReason.STOP_SEQUENCE);
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build();
CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")),
null); null);
@ -325,15 +326,21 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().sampling().build())
.sampling(samplingHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
assertThatExceptionOfType(McpError.class).isThrownBy(() -> { assertThatExceptionOfType(McpError.class).isThrownBy(() -> {
mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())); mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()));
}).withMessageContaining("1000ms"); }).withMessageContaining("1000ms");
}
mcpClient.close(); finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -366,8 +373,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.hasMessage("Client must be configured with elicitation capabilities"); .hasMessage("Client must be configured with elicitation capabilities");
} }
} }
finally {
server.closeGracefully().block(); server.closeGracefully().block();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -421,8 +430,10 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(response).isNotNull(); assertThat(response).isNotNull();
assertThat(response).isEqualTo(callResponse); assertThat(response).isEqualTo(callResponse);
} }
finally {
mcpServer.closeGracefully().block(); mcpServer.closeGracefully().block();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -436,11 +447,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message())); return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build();
CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), CallToolResult callResponse = new McpSchema.CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")),
null); null);
@ -467,6 +473,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
@ -479,10 +490,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(result.action()).isEqualTo(McpSchema.ElicitResult.Action.ACCEPT); assertThat(result.action()).isEqualTo(McpSchema.ElicitResult.Action.ACCEPT);
assertThat(result.content().get("message")).isEqualTo("Test message"); assertThat(result.content().get("message")).isEqualTo("Test message");
}); });
}
mcpClient.closeGracefully(); finally {
mcpServer.closeGracefully().block(); mcpServer.closeGracefully().block();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -507,11 +519,6 @@ public abstract class AbstractMcpClientServerIntegrationTests {
return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message())); return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
}; };
var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build();
CallToolResult callResponse = new CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), null); CallToolResult callResponse = new CallToolResult(List.of(new McpSchema.TextContent("CALL RESPONSE")), null);
AtomicReference<ElicitResult> resultRef = new AtomicReference<>(); AtomicReference<ElicitResult> resultRef = new AtomicReference<>();
@ -537,6 +544,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.tools(tool) .tools(tool)
.build(); .build();
try (var mcpClient = clientBuilder.clientInfo(new McpSchema.Implementation("Sample client", "0.0.0"))
.capabilities(ClientCapabilities.builder().elicitation().build())
.elicitation(elicitationHandler)
.build()) {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
@ -546,10 +558,11 @@ public abstract class AbstractMcpClientServerIntegrationTests {
ElicitResult elicitResult = resultRef.get(); ElicitResult elicitResult = resultRef.get();
assertThat(elicitResult).isNull(); assertThat(elicitResult).isNull();
}
mcpClient.closeGracefully(); finally {
mcpServer.closeGracefully().block(); mcpServer.closeGracefully().block();
} }
}
// --------------------------------------- // ---------------------------------------
// Roots Tests // Roots Tests
@ -597,8 +610,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef.get()).containsAll(List.of(roots.get(1), root3)); assertThat(rootsRef.get()).containsAll(List.of(roots.get(1), root3));
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -635,8 +649,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(e).isInstanceOf(McpError.class).hasMessage("Roots not supported"); assertThat(e).isInstanceOf(McpError.class).hasMessage("Roots not supported");
} }
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -664,8 +679,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef.get()).isEmpty(); assertThat(rootsRef.get()).isEmpty();
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -697,8 +713,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef2.get()).containsAll(roots); assertThat(rootsRef2.get()).containsAll(roots);
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -728,8 +745,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(rootsRef.get()).containsAll(roots); assertThat(rootsRef.get()).containsAll(roots);
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -789,8 +807,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(responseBodyIsNullOrBlank.get()).isFalse(); assertThat(responseBodyIsNullOrBlank.get()).isFalse();
assertThat(response).isNotNull().isEqualTo(callResponse); assertThat(response).isNotNull().isEqualTo(callResponse);
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -826,8 +845,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of()))) .isThrownBy(() -> mcpClient.callTool(new McpSchema.CallToolRequest("tool1", Map.of())))
.withMessageContaining("Timeout on blocking read"); .withMessageContaining("Timeout on blocking read");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -882,8 +902,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(responseBodyIsNullOrBlank.get()).isFalse(); assertThat(responseBodyIsNullOrBlank.get()).isFalse();
assertThat(response).isNotNull().isEqualTo(expectedCallResponse); assertThat(response).isNotNull().isEqualTo(expectedCallResponse);
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -974,8 +995,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(toolsRef.get()).containsAll(List.of(tool2.tool())); assertThat(toolsRef.get()).containsAll(List.of(tool2.tool()));
}); });
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -991,8 +1013,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1056,7 +1079,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.build(); .build();
var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0") var mcpServer = prepareAsyncServerBuilder().serverInfo("test-server", "1.0.0")
.capabilities(ServerCapabilities.builder().logging().tools(true).build()) .capabilities(ServerCapabilities.builder().tools(true).build())
.tools(tool) .tools(tool)
.build(); .build();
@ -1103,7 +1126,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(notificationMap.get("Another error message").logger()).isEqualTo("test-logger"); assertThat(notificationMap.get("Another error message").logger()).isEqualTo("test-logger");
assertThat(notificationMap.get("Another error message").data()).isEqualTo("Another error message"); assertThat(notificationMap.get("Another error message").data()).isEqualTo("Another error message");
} }
mcpServer.close(); finally {
mcpServer.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1208,7 +1233,7 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(notificationMap.get("Processing completed").message()).isEqualTo("Processing completed"); assertThat(notificationMap.get("Processing completed").message()).isEqualTo("Processing completed");
} }
finally { finally {
mcpServer.close(); mcpServer.closeGracefully().block();
} }
} }
@ -1258,8 +1283,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(samplingRequest.get().argument().value()).isEqualTo("py"); assertThat(samplingRequest.get().argument().value()).isEqualTo("py");
assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt"); assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1320,8 +1346,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
// Verify execution order // Verify execution order
assertThat(executionOrder.get()).isEqualTo("123"); assertThat(executionOrder.get()).isEqualTo("123");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully().block();
}
} }
// --------------------------------------- // ---------------------------------------
@ -1396,8 +1423,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}""")); {"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}"""));
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -1450,8 +1478,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text(); String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text();
assertThat(errorMessage).contains("Validation failed"); assertThat(errorMessage).contains("Validation failed");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -1500,8 +1529,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
assertThat(errorMessage).isEqualTo( assertThat(errorMessage).isEqualTo(
"Response missing structured content which is expected when calling tool with non-empty outputSchema"); "Response missing structured content which is expected when calling tool with non-empty outputSchema");
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ -1577,8 +1607,9 @@ public abstract class AbstractMcpClientServerIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"count":3,"message":"Dynamic execution"}""")); {"count":3,"message":"Dynamic execution"}"""));
} }
finally {
mcpServer.close(); mcpServer.closeGracefully();
}
} }
private double evaluateExpression(String expression) { private double evaluateExpression(String expression) {

View file

@ -151,9 +151,10 @@ class HttpServletStatelessIntegrationTests {
assertThat(response).isNotNull(); assertThat(response).isNotNull();
assertThat(response).isEqualTo(callResponse); assertThat(response).isEqualTo(callResponse);
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -167,9 +168,10 @@ class HttpServletStatelessIntegrationTests {
InitializeResult initResult = mcpClient.initialize(); InitializeResult initResult = mcpClient.initialize();
assertThat(initResult).isNotNull(); assertThat(initResult).isNotNull();
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
// --------------------------------------- // ---------------------------------------
// Completion Tests // Completion Tests
@ -218,9 +220,10 @@ class HttpServletStatelessIntegrationTests {
assertThat(samplingRequest.get().argument().value()).isEqualTo("py"); assertThat(samplingRequest.get().argument().value()).isEqualTo("py");
assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt"); assertThat(samplingRequest.get().ref().type()).isEqualTo("ref/prompt");
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
// --------------------------------------- // ---------------------------------------
// Tool Structured Output Schema Tests // Tool Structured Output Schema Tests
@ -290,9 +293,10 @@ class HttpServletStatelessIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}""")); {"result":5.0,"operation":"2 + 3","timestamp":"2024-01-01T10:00:00Z"}"""));
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -342,9 +346,10 @@ class HttpServletStatelessIntegrationTests {
String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text(); String errorMessage = ((McpSchema.TextContent) response.content().get(0)).text();
assertThat(errorMessage).contains("Validation failed"); assertThat(errorMessage).contains("Validation failed");
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -391,9 +396,10 @@ class HttpServletStatelessIntegrationTests {
assertThat(errorMessage).isEqualTo( assertThat(errorMessage).isEqualTo(
"Response missing structured content which is expected when calling tool with non-empty outputSchema"); "Response missing structured content which is expected when calling tool with non-empty outputSchema");
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
@ParameterizedTest(name = "{0} : {displayName} ") @ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient" }) @ValueSource(strings = { "httpclient" })
@ -465,9 +471,10 @@ class HttpServletStatelessIntegrationTests {
.isEqualTo(json(""" .isEqualTo(json("""
{"count":3,"message":"Dynamic execution"}""")); {"count":3,"message":"Dynamic execution"}"""));
} }
finally {
mcpServer.close(); mcpServer.close();
} }
}
@Test @Test
void testThrownMcpError() throws Exception { void testThrownMcpError() throws Exception {