Skip to content

Commit cbfdb14

Browse files
authored
refactor: extract common integration test logic into abstract base classes (modelcontextprotocol#473)
refactor: extract common integration test logic into abstract base classes - Move duplicated test methods from WebFlux and WebMvc integration test classes to abstract base classes - WebFluxSseIntegrationTests, WebFluxStreamableIntegrationTests now extend AbstractMcpClientServerIntegrationTests - WebFluxStatelessIntegrationTests, WebMvcStatelessIntegrationTests now extend AbstractStatelessIntegrationTests - Each concrete test class now only implements transport-specific setup methods (prepareClients, prepareAsyncServerBuilder, prepareSyncServerBuilder) - Eliminates ~1300+ lines of duplicated test code across multiple files - Improves maintainability by centralizing test logic in reusable base classes - Updates WebMvcSseServerTransportProvider to use builder pattern - Adds new HttpServletSseIntegrationTests extending AbstractMcpClientServerIntegrationTests - Removes HttpServletSseServerTransportProviderIntegrationTests - Standardizes timeout configurations and client setup across all integration tests Signed-off-by: Christian Tzolov <[email protected]>
1 parent 1edd1b6 commit cbfdb14

File tree

11 files changed

+792
-4785
lines changed

11 files changed

+792
-4785
lines changed

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/WebFluxSseIntegrationTests.java

Lines changed: 31 additions & 1432 deletions
Large diffs are not rendered by default.

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/WebFluxStatelessIntegrationTests.java

Lines changed: 34 additions & 421 deletions
Large diffs are not rendered by default.

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/WebFluxStreamableIntegrationTests.java

Lines changed: 40 additions & 1444 deletions
Large diffs are not rendered by default.

mcp-spring/mcp-spring-webmvc/src/test/java/io/modelcontextprotocol/server/WebMvcSseIntegrationTests.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,11 @@ protected void prepareClients(int port, String mcpEndpoint) {
4242

4343
clientBuilders.put("httpclient",
4444
McpClient.sync(HttpClientSseClientTransport.builder("http://localhost:" + port).build())
45-
.initializationTimeout(Duration.ofHours(10))
4645
.requestTimeout(Duration.ofHours(10)));
4746

4847
clientBuilders.put("webflux", McpClient
49-
.sync(WebFluxSseClientTransport.builder(WebClient.builder().baseUrl("http://localhost:" + port)).build()));
48+
.sync(WebFluxSseClientTransport.builder(WebClient.builder().baseUrl("http://localhost:" + port)).build())
49+
.requestTimeout(Duration.ofHours(10)));
5050
}
5151

5252
@Configuration
@@ -55,7 +55,10 @@ static class TestConfig {
5555

5656
@Bean
5757
public WebMvcSseServerTransportProvider webMvcSseServerTransportProvider() {
58-
return new WebMvcSseServerTransportProvider(new ObjectMapper(), MESSAGE_ENDPOINT);
58+
return WebMvcSseServerTransportProvider.builder()
59+
.objectMapper(new ObjectMapper())
60+
.messageEndpoint(MESSAGE_ENDPOINT)
61+
.build();
5962
}
6063

6164
@Bean

mcp-spring/mcp-spring-webmvc/src/test/java/io/modelcontextprotocol/server/WebMvcStatelessIntegrationTests.java

Lines changed: 27 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
import org.apache.catalina.LifecycleState;
1212
import org.junit.jupiter.api.AfterEach;
1313
import org.junit.jupiter.api.BeforeEach;
14-
import org.junit.jupiter.params.ParameterizedTest;
15-
import org.junit.jupiter.params.provider.ValueSource;
1614
import org.springframework.context.annotation.Bean;
1715
import org.springframework.context.annotation.Configuration;
1816
import org.springframework.web.reactive.function.client.WebClient;
@@ -29,7 +27,6 @@
2927
import io.modelcontextprotocol.server.McpServer.StatelessAsyncSpecification;
3028
import io.modelcontextprotocol.server.McpServer.StatelessSyncSpecification;
3129
import io.modelcontextprotocol.server.transport.WebMvcStatelessServerTransport;
32-
import io.modelcontextprotocol.spec.McpSchema;
3330
import reactor.core.scheduler.Schedulers;
3431

3532
class WebMvcStatelessIntegrationTests extends AbstractStatelessIntegrationTests {
@@ -63,6 +60,32 @@ public RouterFunction<ServerResponse> routerFunction(WebMvcStatelessServerTransp
6360

6461
private TomcatTestUtil.TomcatServer tomcatServer;
6562

63+
@Override
64+
protected StatelessAsyncSpecification prepareAsyncServerBuilder() {
65+
return McpServer.async(this.mcpServerTransport);
66+
}
67+
68+
@Override
69+
protected StatelessSyncSpecification prepareSyncServerBuilder() {
70+
return McpServer.sync(this.mcpServerTransport);
71+
}
72+
73+
@Override
74+
protected void prepareClients(int port, String mcpEndpoint) {
75+
76+
clientBuilders.put("httpclient", McpClient
77+
.sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + port).endpoint(mcpEndpoint).build())
78+
.requestTimeout(Duration.ofHours(10)));
79+
80+
clientBuilders.put("webflux",
81+
McpClient
82+
.sync(WebClientStreamableHttpTransport
83+
.builder(WebClient.builder().baseUrl("http://localhost:" + port))
84+
.endpoint(mcpEndpoint)
85+
.build())
86+
.requestTimeout(Duration.ofHours(10)));
87+
}
88+
6689
@BeforeEach
6790
public void before() {
6891

@@ -76,33 +99,13 @@ public void before() {
7699
throw new RuntimeException("Failed to start Tomcat", e);
77100
}
78101

79-
clientBuilders
80-
.put("httpclient",
81-
McpClient.sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + PORT)
82-
.endpoint(MESSAGE_ENDPOINT)
83-
.build()).initializationTimeout(Duration.ofHours(10)).requestTimeout(Duration.ofHours(10)));
84-
85-
clientBuilders.put("webflux",
86-
McpClient.sync(WebClientStreamableHttpTransport
87-
.builder(WebClient.builder().baseUrl("http://localhost:" + PORT))
88-
.endpoint(MESSAGE_ENDPOINT)
89-
.build()));
102+
prepareClients(PORT, MESSAGE_ENDPOINT);
90103

91104
// Get the transport from Spring context
92105
this.mcpServerTransport = tomcatServer.appContext().getBean(WebMvcStatelessServerTransport.class);
93106

94107
}
95108

96-
@Override
97-
protected StatelessAsyncSpecification prepareAsyncServerBuilder() {
98-
return McpServer.async(this.mcpServerTransport);
99-
}
100-
101-
@Override
102-
protected StatelessSyncSpecification prepareSyncServerBuilder() {
103-
return McpServer.sync(this.mcpServerTransport);
104-
}
105-
106109
@AfterEach
107110
public void after() {
108111
reactor.netty.http.HttpResources.disposeLoopsAndConnections();
@@ -124,42 +127,4 @@ public void after() {
124127
}
125128
}
126129

127-
@ParameterizedTest(name = "{0} : {displayName} ")
128-
@ValueSource(strings = { "httpclient", "webflux" })
129-
void simple(String clientType) {
130-
131-
var clientBuilder = clientBuilders.get(clientType);
132-
133-
var server = McpServer.async(this.mcpServerTransport)
134-
.serverInfo("test-server", "1.0.0")
135-
.requestTimeout(Duration.ofSeconds(1000))
136-
.build();
137-
138-
try (
139-
// Create client without sampling capabilities
140-
var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
141-
.requestTimeout(Duration.ofSeconds(1000))
142-
.build()) {
143-
144-
assertThat(client.initialize()).isNotNull();
145-
146-
}
147-
server.closeGracefully();
148-
}
149-
150-
@Override
151-
protected void prepareClients(int port, String mcpEndpoint) {
152-
153-
clientBuilders.put("httpclient", McpClient
154-
.sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + port).endpoint(mcpEndpoint).build())
155-
.initializationTimeout(Duration.ofHours(10))
156-
.requestTimeout(Duration.ofHours(10)));
157-
158-
clientBuilders.put("webflux",
159-
McpClient.sync(WebClientStreamableHttpTransport
160-
.builder(WebClient.builder().baseUrl("http://localhost:" + port))
161-
.endpoint(mcpEndpoint)
162-
.build()));
163-
}
164-
165130
}

mcp-spring/mcp-spring-webmvc/src/test/java/io/modelcontextprotocol/server/WebMvcStreamableIntegrationTests.java

Lines changed: 6 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -124,42 +124,20 @@ public void after() {
124124
}
125125
}
126126

127-
@ParameterizedTest(name = "{0} : {displayName} ")
128-
@ValueSource(strings = { "httpclient", "webflux" })
129-
void simple(String clientType) {
130-
131-
var clientBuilder = clientBuilders.get(clientType);
132-
133-
var server = McpServer.async(mcpServerTransportProvider)
134-
.serverInfo("test-server", "1.0.0")
135-
.requestTimeout(Duration.ofSeconds(1000))
136-
.build();
137-
138-
try (
139-
// Create client without sampling capabilities
140-
var client = clientBuilder.clientInfo(new McpSchema.Implementation("Sample " + "client", "0.0.0"))
141-
.requestTimeout(Duration.ofSeconds(1000))
142-
.build()) {
143-
144-
assertThat(client.initialize()).isNotNull();
145-
146-
}
147-
server.closeGracefully();
148-
}
149-
150127
@Override
151128
protected void prepareClients(int port, String mcpEndpoint) {
152129

153130
clientBuilders.put("httpclient", McpClient
154131
.sync(HttpClientStreamableHttpTransport.builder("http://localhost:" + port).endpoint(mcpEndpoint).build())
155-
.initializationTimeout(Duration.ofHours(10))
156132
.requestTimeout(Duration.ofHours(10)));
157133

158134
clientBuilders.put("webflux",
159-
McpClient.sync(WebClientStreamableHttpTransport
160-
.builder(WebClient.builder().baseUrl("http://localhost:" + port))
161-
.endpoint(mcpEndpoint)
162-
.build()));
135+
McpClient
136+
.sync(WebClientStreamableHttpTransport
137+
.builder(WebClient.builder().baseUrl("http://localhost:" + port))
138+
.endpoint(mcpEndpoint)
139+
.build())
140+
.requestTimeout(Duration.ofHours(10)));
163141
}
164142

165143
}

0 commit comments

Comments
 (0)