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 <git@garnier.wf>
This commit is contained in:
Daniel Garnier-Moiroux 2025-09-03 16:36:46 +02:00 • committed by GitHub
commit a5fd1ebff5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 69 additions and 119 deletions

View file

@ -4,6 +4,8 @@
package io.modelcontextprotocol.client;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Timeout;
import org.springframework.web.reactive.function.client.WebClient;
import org.testcontainers.containers.GenericContainer;
@ -19,7 +21,7 @@ public class WebClientStreamableHttpAsyncClientTests extends AbstractMcpAsyncCli
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
@SuppressWarnings("resource")
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
.withCommand("node dist/index.js streamableHttp")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
@ -30,15 +32,15 @@ public class WebClientStreamableHttpAsyncClientTests extends AbstractMcpAsyncCli
return WebClientStreamableHttpTransport.builder(WebClient.builder().baseUrl(host)).build();
}
@Override
protected void onStart() {
@BeforeAll
static void startContainer() {
container.start();
int port = container.getMappedPort(3001);
host = "http://" + container.getHost() + ":" + port;
}
@Override
public void onClose() {
@AfterAll
static void stopContainer() {
container.stop();
}

View file

@ -4,6 +4,8 @@
package io.modelcontextprotocol.client;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Timeout;
import org.springframework.web.reactive.function.client.WebClient;
import org.testcontainers.containers.GenericContainer;
@ -19,7 +21,7 @@ public class WebClientStreamableHttpSyncClientTests extends AbstractMcpSyncClien
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
@SuppressWarnings("resource")
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
.withCommand("node dist/index.js streamableHttp")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
@ -30,15 +32,15 @@ public class WebClientStreamableHttpSyncClientTests extends AbstractMcpSyncClien
return WebClientStreamableHttpTransport.builder(WebClient.builder().baseUrl(host)).build();
}
@Override
protected void onStart() {
@BeforeAll
static void startContainer() {
container.start();
int port = container.getMappedPort(3001);
host = "http://" + container.getHost() + ":" + port;
}
@Override
public void onClose() {
@AfterAll
static void stopContainer() {
container.stop();
}

View file

@ -6,6 +6,8 @@ package io.modelcontextprotocol.client;
import java.time.Duration;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Timeout;
import org.springframework.web.reactive.function.client.WebClient;
import org.testcontainers.containers.GenericContainer;
@ -26,7 +28,7 @@ class WebFluxSseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
@SuppressWarnings("resource")
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
.withCommand("node dist/index.js sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
@ -37,15 +39,15 @@ class WebFluxSseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {
return WebFluxSseClientTransport.builder(WebClient.builder().baseUrl(host)).build();
}
@Override
protected void onStart() {
@BeforeAll
static void startContainer() {
container.start();
int port = container.getMappedPort(3001);
host = "http://" + container.getHost() + ":" + port;
}
@Override
public void onClose() {
@AfterAll
static void stopContainer() {
container.stop();
}

View file

@ -8,6 +8,8 @@ import java.time.Duration;
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
import io.modelcontextprotocol.spec.McpClientTransport;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Timeout;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
@ -26,7 +28,7 @@ class WebFluxSseMcpSyncClientTests extends AbstractMcpSyncClientTests {
// Uses the https://github.com/tzolov/mcp-everything-server-docker-image
@SuppressWarnings("resource")
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
.withCommand("node dist/index.js sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
@ -37,15 +39,15 @@ class WebFluxSseMcpSyncClientTests extends AbstractMcpSyncClientTests {
return WebFluxSseClientTransport.builder(WebClient.builder().baseUrl(host)).build();
}
@Override
protected void onStart() {
@BeforeAll
static void startContainer() {
container.start();
int port = container.getMappedPort(3001);
host = "http://" + container.getHost() + ":" + port;
}
@Override
protected void onClose() {
@AfterAll
static void stopContainer() {
container.stop();
}

View file

@ -13,7 +13,9 @@ import java.util.function.Function;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.JSONRPCRequest;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
@ -42,7 +44,7 @@ class WebFluxSseClientTransportTests {
static String host = "http://localhost:3001";
@SuppressWarnings("resource")
GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
static GenericContainer<?> container = new GenericContainer<>("docker.io/tzolov/mcp-everything-server:v2")
.withCommand("node dist/index.js sse")
.withLogConsumer(outputFrame -> System.out.println(outputFrame.getUtf8String()))
.withExposedPorts(3001)
@ -95,15 +97,20 @@ class WebFluxSseClientTransportTests {
}
void startContainer() {
@BeforeAll
static void startContainer() {
container.start();
int port = container.getMappedPort(3001);
host = "http://" + container.getHost() + ":" + port;
}
@AfterAll
static void cleanup() {
container.stop();
}
@BeforeEach
void setUp() {
startContainer();
webClientBuilder = WebClient.builder().baseUrl(host);
objectMapper = new ObjectMapper();
transport = new TestSseClientTransport(webClientBuilder, objectMapper);
@ -115,11 +122,6 @@ class WebFluxSseClientTransportTests {
if (transport != null) {
assertThatCode(() -> transport.closeGracefully().block(Duration.ofSeconds(10))).doesNotThrowAnyException();
}
cleanup();
}
void cleanup() {
container.stop();
}
@Test