Skip to content

Commit a5fd1eb

Browse files
authored
Use static container in all client and transport tests (#531)
- This allows reusing the containerized MCP server for all tests in a single class, significantly speeding up the tests, roughly 10x. Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent 629464b commit a5fd1eb

13 files changed

+69
-119
lines changed

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/client/WebClientStreamableHttpAsyncClientTests.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package io.modelcontextprotocol.client;
66

7+
import org.junit.jupiter.api.AfterAll;
8+
import org.junit.jupiter.api.BeforeAll;
79
import org.junit.jupiter.api.Timeout;
810
import org.springframework.web.reactive.function.client.WebClient;
911
import org.testcontainers.containers.GenericContainer;
@@ -19,7 +21,7 @@ public class WebClientStreamableHttpAsyncClientTests extends AbstractMcpAsyncCli
1921

2022
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
2123
@SuppressWarnings("resource")
22-
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
24+
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
2325
.withCommand("node dist/index.js streamableHttp")
2426
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
2527
.withExposedPorts(3001)
@@ -30,15 +32,15 @@ protected McpClientTransport createMcpTransport() {
3032
return WebClientStreamableHttpTransport.builder(WebClient.builder().baseUrl(host)).build();
3133
}
3234

33-
@Override
34-
protected void onStart() {
35+
@BeforeAll
36+
static void startContainer() {
3537
container.start();
3638
int port = container.getMappedPort(3001);
3739
host = "http://" + container.getHost() + ":" + port;
3840
}
3941

40-
@Override
41-
public void onClose() {
42+
@AfterAll
43+
static void stopContainer() {
4244
container.stop();
4345
}
4446

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/client/WebClientStreamableHttpSyncClientTests.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package io.modelcontextprotocol.client;
66

7+
import org.junit.jupiter.api.AfterAll;
8+
import org.junit.jupiter.api.BeforeAll;
79
import org.junit.jupiter.api.Timeout;
810
import org.springframework.web.reactive.function.client.WebClient;
911
import org.testcontainers.containers.GenericContainer;
@@ -19,7 +21,7 @@ public class WebClientStreamableHttpSyncClientTests extends AbstractMcpSyncClien
1921

2022
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
2123
@SuppressWarnings("resource")
22-
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
24+
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
2325
.withCommand("node dist/index.js streamableHttp")
2426
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
2527
.withExposedPorts(3001)
@@ -30,15 +32,15 @@ protected McpClientTransport createMcpTransport() {
3032
return WebClientStreamableHttpTransport.builder(WebClient.builder().baseUrl(host)).build();
3133
}
3234

33-
@Override
34-
protected void onStart() {
35+
@BeforeAll
36+
static void startContainer() {
3537
container.start();
3638
int port = container.getMappedPort(3001);
3739
host = "http://" + container.getHost() + ":" + port;
3840
}
3941

40-
@Override
41-
public void onClose() {
42+
@AfterAll
43+
static void stopContainer() {
4244
container.stop();
4345
}
4446

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/client/WebFluxSseMcpAsyncClientTests.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
import java.time.Duration;
88

9+
import org.junit.jupiter.api.AfterAll;
10+
import org.junit.jupiter.api.BeforeAll;
911
import org.junit.jupiter.api.Timeout;
1012
import org.springframework.web.reactive.function.client.WebClient;
1113
import org.testcontainers.containers.GenericContainer;
@@ -26,7 +28,7 @@ class WebFluxSseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {
2628

2729
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
2830
@SuppressWarnings("resource")
29-
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
31+
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
3032
.withCommand("node dist/index.js sse")
3133
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
3234
.withExposedPorts(3001)
@@ -37,15 +39,15 @@ protected McpClientTransport createMcpTransport() {
3739
return WebFluxSseClientTransport.builder(WebClient.builder().baseUrl(host)).build();
3840
}
3941

40-
@Override
41-
protected void onStart() {
42+
@BeforeAll
43+
static void startContainer() {
4244
container.start();
4345
int port = container.getMappedPort(3001);
4446
host = "http://" + container.getHost() + ":" + port;
4547
}
4648

47-
@Override
48-
public void onClose() {
49+
@AfterAll
50+
static void stopContainer() {
4951
container.stop();
5052
}
5153

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/client/WebFluxSseMcpSyncClientTests.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
1010
import io.modelcontextprotocol.spec.McpClientTransport;
11+
import org.junit.jupiter.api.AfterAll;
12+
import org.junit.jupiter.api.BeforeAll;
1113
import org.junit.jupiter.api.Timeout;
1214
import org.testcontainers.containers.GenericContainer;
1315
import org.testcontainers.containers.wait.strategy.Wait;
@@ -26,7 +28,7 @@ class WebFluxSseMcpSyncClientTests extends AbstractMcpSyncClientTests {
2628

2729
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
2830
@SuppressWarnings("resource")
29-
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
31+
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
3032
.withCommand("node dist/index.js sse")
3133
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
3234
.withExposedPorts(3001)
@@ -37,15 +39,15 @@ protected McpClientTransport createMcpTransport() {
3739
return WebFluxSseClientTransport.builder(WebClient.builder().baseUrl(host)).build();
3840
}
3941

40-
@Override
41-
protected void onStart() {
42+
@BeforeAll
43+
static void startContainer() {
4244
container.start();
4345
int port = container.getMappedPort(3001);
4446
host = "http://" + container.getHost() + ":" + port;
4547
}
4648

47-
@Override
48-
protected void onClose() {
49+
@AfterAll
50+
static void stopContainer() {
4951
container.stop();
5052
}
5153

mcp-spring/mcp-spring-webflux/src/test/java/io/modelcontextprotocol/client/transport/WebFluxSseClientTransportTests.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
import com.fasterxml.jackson.databind.ObjectMapper;
1414
import io.modelcontextprotocol.spec.McpSchema;
1515
import io.modelcontextprotocol.spec.McpSchema.JSONRPCRequest;
16+
import org.junit.jupiter.api.AfterAll;
1617
import org.junit.jupiter.api.AfterEach;
18+
import org.junit.jupiter.api.BeforeAll;
1719
import org.junit.jupiter.api.BeforeEach;
1820
import org.junit.jupiter.api.Test;
1921
import org.junit.jupiter.api.Timeout;
@@ -42,7 +44,7 @@ class WebFluxSseClientTransportTests {
4244
static String host = "http://localhost:3001";
4345

4446
@SuppressWarnings("resource")
45-
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
47+
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
4648
.withCommand("node dist/index.js sse")
4749
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
4850
.withExposedPorts(3001)
@@ -95,15 +97,20 @@ public void simulateMessageEvent(String jsonMessage) {
9597

9698
}
9799

98-
void startContainer() {
100+
@BeforeAll
101+
static void startContainer() {
99102
container.start();
100103
int port = container.getMappedPort(3001);
101104
host = "http://" + container.getHost() + ":" + port;
102105
}
103106

107+
@AfterAll
108+
static void cleanup() {
109+
container.stop();
110+
}
111+
104112
@BeforeEach
105113
void setUp() {
106-
startContainer();
107114
webClientBuilder = WebClient.builder().baseUrl(host);
108115
objectMapper = new ObjectMapper();
109116
transport = new TestSseClientTransport(webClientBuilder, objectMapper);
@@ -115,11 +122,6 @@ void afterEach() {
115122
if (transport != null) {
116123
assertThatCode(() -> transport.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
117124
}
118-
cleanup();
119-
}
120-
121-
void cleanup() {
122-
container.stop();
123125
}
124126

125127
@Test

mcp-test/src/main/java/io/modelcontextprotocol/client/AbstractMcpAsyncClientTests.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ public abstract class AbstractMcpAsyncClientTests {
6767

6868
abstract protected McpClientTransport createMcpTransport();
6969

70-
protected void onStart() {
71-
}
72-
73-
protected void onClose() {
74-
}
75-
7670
protected Duration getRequestTimeout() {
7771
return Duration.ofSeconds(14);
7872
}
@@ -117,16 +111,6 @@ void withClient(McpClientTransport transport, Function<McpClient.AsyncSpec, McpC
117111
}
118112
}
119113

120-
@BeforeEach
121-
void setUp() {
122-
onStart();
123-
}
124-
125-
@AfterEach
126-
void tearDown() {
127-
onClose();
128-
}
129-
130114
<T> void verifyNotificationSucceedsWithImplicitInitialization(Function<McpAsyncClient, Mono<T>> operation,
131115
String action) {
132116
withClient(createMcpTransport(), mcpAsyncClient -> {

mcp-test/src/main/java/io/modelcontextprotocol/client/AbstractMcpSyncClientTests.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,6 @@ public abstract class AbstractMcpSyncClientTests {
6666

6767
abstract protected McpClientTransport createMcpTransport();
6868

69-
protected void onStart() {
70-
}
71-
72-
protected void onClose() {
73-
}
74-
7569
protected Duration getRequestTimeout() {
7670
return Duration.ofSeconds(14);
7771
}
@@ -114,17 +108,6 @@ void withClient(McpClientTransport transport, Function<McpClient.SyncSpec, McpCl
114108
}
115109
}
116110

117-
@BeforeEach
118-
void setUp() {
119-
onStart();
120-
121-
}
122-
123-
@AfterEach
124-
void tearDown() {
125-
onClose();
126-
}
127-
128111
static final Object DUMMY_RETURN_VALUE = new Object();
129112

130113
<T> void verifyNotificationSucceedsWithImplicitInitialization(Consumer<McpSyncClient> operation, String action) {

mcp/src/test/java/io/modelcontextprotocol/client/AbstractMcpAsyncClientTests.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ public abstract class AbstractMcpAsyncClientTests {
6868

6969
abstract protected McpClientTransport createMcpTransport();
7070

71-
protected void onStart() {
72-
}
73-
74-
protected void onClose() {
75-
}
76-
7771
protected Duration getRequestTimeout() {
7872
return Duration.ofSeconds(14);
7973
}
@@ -118,16 +112,6 @@ void withClient(McpClientTransport transport, Function<McpClient.AsyncSpec, McpC
118112
}
119113
}
120114

121-
@BeforeEach
122-
void setUp() {
123-
onStart();
124-
}
125-
126-
@AfterEach
127-
void tearDown() {
128-
onClose();
129-
}
130-
131115
<T> void verifyNotificationSucceedsWithImplicitInitialization(Function<McpAsyncClient, Mono<T>> operation,
132116
String action) {
133117
withClient(createMcpTransport(), mcpAsyncClient -> {

mcp/src/test/java/io/modelcontextprotocol/client/AbstractMcpSyncClientTests.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ public abstract class AbstractMcpSyncClientTests {
6767

6868
abstract protected McpClientTransport createMcpTransport();
6969

70-
protected void onStart() {
71-
}
72-
73-
protected void onClose() {
74-
}
75-
7670
protected Duration getRequestTimeout() {
7771
return Duration.ofSeconds(14);
7872
}
@@ -115,17 +109,6 @@ void withClient(McpClientTransport transport, Function<McpClient.SyncSpec, McpCl
115109
}
116110
}
117111

118-
@BeforeEach
119-
void setUp() {
120-
onStart();
121-
122-
}
123-
124-
@AfterEach
125-
void tearDown() {
126-
onClose();
127-
}
128-
129112
static final Object DUMMY_RETURN_VALUE = new Object();
130113

131114
<T> void verifyNotificationSucceedsWithImplicitInitialization(Consumer<McpSyncClient> operation, String action) {

mcp/src/test/java/io/modelcontextprotocol/client/HttpClientStreamableHttpAsyncClientTests.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package io.modelcontextprotocol.client;
66

7+
import org.junit.jupiter.api.AfterAll;
8+
import org.junit.jupiter.api.BeforeAll;
79
import org.junit.jupiter.api.Timeout;
810
import org.testcontainers.containers.GenericContainer;
911
import org.testcontainers.containers.wait.strategy.Wait;
@@ -14,11 +16,11 @@
1416
@Timeout(15)
1517
public class HttpClientStreamableHttpAsyncClientTests extends AbstractMcpAsyncClientTests {
1618

17-
private String host = "http://localhost:3001";
19+
private static String host = "http://localhost:3001";
1820

1921
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
2022
@SuppressWarnings("resource")
21-
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
23+
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
2224
.withCommand("node dist/index.js streamableHttp")
2325
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
2426
.withExposedPorts(3001)
@@ -30,15 +32,15 @@ protected McpClientTransport createMcpTransport() {
3032
return HttpClientStreamableHttpTransport.builder(host).build();
3133
}
3234

33-
@Override
34-
protected void onStart() {
35+
@BeforeAll
36+
static void startContainer() {
3537
container.start();
3638
int port = container.getMappedPort(3001);
3739
host = "http://" + container.getHost() + ":" + port;
3840
}
3941

40-
@Override
41-
public void onClose() {
42+
@AfterAll
43+
static void stopContainer() {
4244
container.stop();
4345
}
4446

0 commit comments

Comments
 (0)