Enhances WebFlux SSE transport implementation with customizable endpoint paths: - Add configurable SSE endpoint support in both client and server transports - Update tests to verify custom SSE endpoint functionality - Implement builder pattern to support the new configuration options Co-authored-by: haidao <wwulfric@gmail.com> Co-authored-by: Harry <34418180+HarryFQG@users.noreply.github.com> Signed-off-by: Christian Tzolov <christian.tzolov@broadcom.com>
This commit is contained in:
parent
2934635d99
commit
55ee15604a
6 changed files with 210 additions and 19 deletions
|
|
@ -46,14 +46,17 @@ import org.springframework.web.reactive.function.server.RouterFunctions;
|
|||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class WebFluxSseIntegrationTests {
|
||||
|
||||
private static final int PORT = 8182;
|
||||
|
||||
private static final String MESSAGE_ENDPOINT = "/mcp/message";
|
||||
// private static final String MESSAGE_ENDPOINT = "/mcp/message";
|
||||
|
||||
private static final String CUSTOM_SSE_ENDPOINT = "/somePath/sse";
|
||||
|
||||
private static final String CUSTOM_MESSAGE_ENDPOINT = "/otherPath/mcp/message";
|
||||
|
||||
private DisposableServer httpServer;
|
||||
|
||||
|
|
@ -64,15 +67,25 @@ public class WebFluxSseIntegrationTests {
|
|||
@BeforeEach
|
||||
public void before() {
|
||||
|
||||
this.mcpServerTransportProvider = new WebFluxSseServerTransportProvider(new ObjectMapper(), MESSAGE_ENDPOINT);
|
||||
this.mcpServerTransportProvider = new WebFluxSseServerTransportProvider.Builder()
|
||||
.objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(CUSTOM_MESSAGE_ENDPOINT)
|
||||
.sseEndpoint(CUSTOM_SSE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
HttpHandler httpHandler = RouterFunctions.toHttpHandler(mcpServerTransportProvider.getRouterFunction());
|
||||
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
|
||||
this.httpServer = HttpServer.create().port(PORT).handle(adapter).bindNow();
|
||||
|
||||
clientBulders.put("httpclient", McpClient.sync(new HttpClientSseClientTransport("http://localhost:" + PORT)));
|
||||
clientBulders.put("httpclient",
|
||||
McpClient.sync(HttpClientSseClientTransport.builder("http://localhost:" + PORT)
|
||||
.sseEndpoint(CUSTOM_SSE_ENDPOINT)
|
||||
.build()));
|
||||
clientBulders.put("webflux",
|
||||
McpClient.sync(new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:" + PORT))));
|
||||
McpClient
|
||||
.sync(WebFluxSseClientTransport.builder(WebClient.builder().baseUrl("http://localhost:" + PORT))
|
||||
.sseEndpoint(CUSTOM_SSE_ENDPOINT)
|
||||
.build()));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class WebFluxSseMcpAsyncClientTests extends AbstractMcpAsyncClientTests {
|
|||
|
||||
@Override
|
||||
protected McpClientTransport createMcpTransport() {
|
||||
return new WebFluxSseClientTransport(WebClient.builder().baseUrl(host));
|
||||
return WebFluxSseClientTransport.builder(WebClient.builder().baseUrl(host)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class WebFluxSseMcpSyncClientTests extends AbstractMcpSyncClientTests {
|
|||
|
||||
@Override
|
||||
protected McpClientTransport createMcpTransport() {
|
||||
return new WebFluxSseClientTransport(WebClient.builder().baseUrl(host));
|
||||
return WebFluxSseClientTransport.builder(WebClient.builder().baseUrl(host)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -63,13 +63,6 @@ class WebFluxSseClientTransportTests {
|
|||
super(webClientBuilder, objectMapper);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public Mono<Void> connect(Function<Mono<McpSchema.JSONRPCMessage>,
|
||||
// Mono<McpSchema.JSONRPCMessage>> handler) {
|
||||
// simulateEndpointEvent("https://localhost:3001");
|
||||
// return super.connect(handler);
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected Flux<ServerSentEvent<String>> eventStream() {
|
||||
return super.eventStream().mergeWith(events.asFlux());
|
||||
|
|
@ -137,6 +130,33 @@ class WebFluxSseClientTransportTests {
|
|||
.hasMessageContaining("ObjectMapper must not be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBuilderPattern() {
|
||||
// Test default builder
|
||||
WebFluxSseClientTransport transport1 = WebFluxSseClientTransport.builder(webClientBuilder).build();
|
||||
assertThatCode(() -> transport1.closeGracefully().block()).doesNotThrowAnyException();
|
||||
|
||||
// Test builder with custom ObjectMapper
|
||||
ObjectMapper customMapper = new ObjectMapper();
|
||||
WebFluxSseClientTransport transport2 = WebFluxSseClientTransport.builder(webClientBuilder)
|
||||
.objectMapper(customMapper)
|
||||
.build();
|
||||
assertThatCode(() -> transport2.closeGracefully().block()).doesNotThrowAnyException();
|
||||
|
||||
// Test builder with custom SSE endpoint
|
||||
WebFluxSseClientTransport transport3 = WebFluxSseClientTransport.builder(webClientBuilder)
|
||||
.sseEndpoint("/custom-sse")
|
||||
.build();
|
||||
assertThatCode(() -> transport3.closeGracefully().block()).doesNotThrowAnyException();
|
||||
|
||||
// Test builder with all custom parameters
|
||||
WebFluxSseClientTransport transport4 = WebFluxSseClientTransport.builder(webClientBuilder)
|
||||
.objectMapper(customMapper)
|
||||
.sseEndpoint("/custom-sse")
|
||||
.build();
|
||||
assertThatCode(() -> transport4.closeGracefully().block()).doesNotThrowAnyException();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testMessageProcessing() {
|
||||
// Create a test message
|
||||
|
|
@ -240,7 +260,7 @@ class WebFluxSseClientTransportTests {
|
|||
// Create a WebClient that simulates connection failures
|
||||
WebClient.Builder failingWebClientBuilder = WebClient.builder().baseUrl("http://non-existent-host");
|
||||
|
||||
WebFluxSseClientTransport failingTransport = new WebFluxSseClientTransport(failingWebClientBuilder);
|
||||
WebFluxSseClientTransport failingTransport = WebFluxSseClientTransport.builder(failingWebClientBuilder).build();
|
||||
|
||||
// Verify that the transport attempts to reconnect
|
||||
StepVerifier.create(Mono.delay(Duration.ofSeconds(2))).expectNextCount(1).verifyComplete();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,9 @@ class WebFluxSseMcpAsyncServerTests extends AbstractMcpAsyncServerTests {
|
|||
|
||||
@Override
|
||||
protected McpServerTransportProvider createMcpTransportProvider() {
|
||||
var transportProvider = new WebFluxSseServerTransportProvider(new ObjectMapper(), MESSAGE_ENDPOINT);
|
||||
var transportProvider = new WebFluxSseServerTransportProvider.Builder().objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
|
||||
HttpHandler httpHandler = RouterFunctions.toHttpHandler(transportProvider.getRouterFunction());
|
||||
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ class WebFluxSseMcpSyncServerTests extends AbstractMcpSyncServerTests {
|
|||
|
||||
@Override
|
||||
protected McpServerTransportProvider createMcpTransportProvider() {
|
||||
transportProvider = new WebFluxSseServerTransportProvider(new ObjectMapper(), MESSAGE_ENDPOINT);
|
||||
transportProvider = new WebFluxSseServerTransportProvider.Builder().objectMapper(new ObjectMapper())
|
||||
.messageEndpoint(MESSAGE_ENDPOINT)
|
||||
.build();
|
||||
return transportProvider;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue