feat(test): Use dynamic port allocation in integration tests (#133)

- Add TestUtil class with findAvailablePort() method to the mcp-test module
- Add findAvailablePort() method to TomcatTestUtil classes
- Replace hardcoded port numbers with dynamic port allocation

Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
a.darafeyeu 2025-04-09 19:43:29 +02:00 • committed by Christian Tzolov
commit 263e3741b2
8 changed files with 87 additions and 29 deletions

View file

@ -18,6 +18,7 @@ import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.server.TestUtil;
import io.modelcontextprotocol.server.transport.WebFluxSseServerTransportProvider;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.spec.McpSchema;
@ -50,9 +51,9 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.mockito.Mockito.mock;
public class WebFluxSseIntegrationTests {
class WebFluxSseIntegrationTests {
private static final int PORT = 8182;
private static final int PORT = TestUtil.findAvailablePort();
private static final String CUSTOM_SSE_ENDPOINT = "/somePath/sse";
@ -133,7 +134,7 @@ public class WebFluxSseIntegrationTests {
@ParameterizedTest(name = "{0} : {displayName} ")
@ValueSource(strings = { "httpclient", "webflux" })
void testCreateMessageSuccess(String clientType) throws InterruptedException {
void testCreateMessageSuccess(String clientType) {
var clientBuilder = clientBuilders.get(clientType);

View file

@ -23,7 +23,7 @@ import org.springframework.web.reactive.function.server.RouterFunctions;
@Timeout(15) // Giving extra time beyond the client timeout
class WebFluxSseMcpAsyncServerTests extends AbstractMcpAsyncServerTests {
private static final int PORT = 8181;
private static final int PORT = TestUtil.findAvailablePort();
private static final String MESSAGE_ENDPOINT = "/mcp/message";

View file

@ -23,7 +23,7 @@ import org.springframework.web.reactive.function.server.RouterFunctions;
@Timeout(15) // Giving extra time beyond the client timeout
class WebFluxSseMcpSyncServerTests extends AbstractMcpSyncServerTests {
private static final int PORT = 8182;
private static final int PORT = TestUtil.findAvailablePort();
private static final String MESSAGE_ENDPOINT = "/mcp/message";

View file

@ -3,6 +3,10 @@
*/
package io.modelcontextprotocol.server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import org.apache.catalina.Context;
import org.apache.catalina.startup.Tomcat;
@ -14,10 +18,14 @@ import org.springframework.web.servlet.DispatcherServlet;
*/
public class TomcatTestUtil {
TomcatTestUtil() {
// Prevent instantiation
}
public record TomcatServer(Tomcat tomcat, AnnotationConfigWebApplicationContext appContext) {
}
public TomcatServer createTomcatServer(String contextPath, int port, Class<?> componentClass) {
public static TomcatServer createTomcatServer(String contextPath, int port, Class<?> componentClass) {
// Set up Tomcat first
var tomcat = new Tomcat();

View file

@ -25,7 +25,7 @@ class WebMvcSseAsyncServerTransportTests extends AbstractMcpAsyncServerTests {
private static final String MESSAGE_ENDPOINT = "/mcp/message";
private static final int PORT = 8181;
private static final int PORT = TestUtil.findAvailablePort();
private Tomcat tomcat;
@ -73,7 +73,6 @@ class WebMvcSseAsyncServerTransportTests extends AbstractMcpAsyncServerTests {
// Create DispatcherServlet with our Spring context
DispatcherServlet dispatcherServlet = new DispatcherServlet(appContext);
// dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
// Add servlet to Tomcat and get the wrapper
var wrapper = Tomcat.addServlet(context, "dispatcherServlet", dispatcherServlet);

View file

@ -22,11 +22,11 @@ import org.springframework.web.servlet.function.ServerResponse;
import static org.assertj.core.api.Assertions.assertThat;
public class WebMvcSseCustomContextPathTests {
class WebMvcSseCustomContextPathTests {
private static final String CUSTOM_CONTEXT_PATH = "/app/1";
private static final int PORT = 8183;
private static final int PORT = TestUtil.findAvailablePort();
private static final String MESSAGE_ENDPOINT = "/mcp/message";
@ -39,11 +39,11 @@ public class WebMvcSseCustomContextPathTests {
@BeforeEach
public void before() {
tomcatServer = new TomcatTestUtil().createTomcatServer(CUSTOM_CONTEXT_PATH, PORT, TestConfig.class);
tomcatServer = TomcatTestUtil.createTomcatServer(CUSTOM_CONTEXT_PATH, PORT, TestConfig.class);
try {
tomcatServer.tomcat().start();
assertThat(tomcatServer.tomcat().getServer().getState() == LifecycleState.STARTED);
assertThat(tomcatServer.tomcat().getServer().getState()).isEqualTo(LifecycleState.STARTED);
}
catch (Exception e) {
throw new RuntimeException("Failed to start Tomcat", e);

View file

@ -46,7 +46,7 @@ import static org.mockito.Mockito.mock;
class WebMvcSseIntegrationTests {
private static final int PORT = 8183;
private static final int PORT = TestUtil.findAvailablePort();
private static final String MESSAGE_ENDPOINT = "/mcp/message";
@ -75,7 +75,7 @@ class WebMvcSseIntegrationTests {
@BeforeEach
public void before() {
tomcatServer = new TomcatTestUtil().createTomcatServer("", PORT, TestConfig.class);
tomcatServer = TomcatTestUtil.createTomcatServer("", PORT, TestConfig.class);
try {
tomcatServer.tomcat().start();
@ -151,7 +151,7 @@ class WebMvcSseIntegrationTests {
}
@Test
void testCreateMessageSuccess() throws InterruptedException {
void testCreateMessageSuccess() {
Function<CreateMessageRequest, CreateMessageResult> samplingHandler = request -> {
assertThat(request.messages()).hasSize(1);

View file

@ -24,7 +24,7 @@ class WebMvcSseSyncServerTransportTests extends AbstractMcpSyncServerTests {
private static final String MESSAGE_ENDPOINT = "/mcp/message";
private static final int PORT = 8181;
private static final int PORT = TestUtil.findAvailablePort();
private Tomcat tomcat;
@ -72,7 +72,6 @@ class WebMvcSseSyncServerTransportTests extends AbstractMcpSyncServerTests {
// Create DispatcherServlet with our Spring context
DispatcherServlet dispatcherServlet = new DispatcherServlet(appContext);
// dispatcherServlet.setThrowExceptionIfNoHandlerFound(true);
// Add servlet to Tomcat and get the wrapper
var wrapper = Tomcat.addServlet(context, "dispatcherServlet", dispatcherServlet);