Skip to content

Commit 5baface

Browse files
committed
Fix integration tests
Signed-off-by: Daniel Garnier-Moiroux <[email protected]>
1 parent f4eb6fe commit 5baface

File tree

8 files changed

+116
-34
lines changed

8 files changed

+116
-34
lines changed

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-common/src/test/java/org/springframework/ai/mcp/client/common/autoconfigure/annotations/McpClientListChangedAnnotationsScanningIT.java

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,21 @@
1616

1717
package org.springframework.ai.mcp.client.common.autoconfigure.annotations;
1818

19+
import java.util.ArrayList;
20+
import java.util.Collections;
1921
import java.util.List;
2022

2123
import io.modelcontextprotocol.spec.McpSchema;
24+
import org.junit.Test;
2225
import org.junit.jupiter.params.ParameterizedTest;
2326
import org.junit.jupiter.params.provider.ValueSource;
2427
import org.springaicommunity.mcp.annotation.McpPromptListChanged;
2528
import org.springaicommunity.mcp.annotation.McpResourceListChanged;
2629
import org.springaicommunity.mcp.annotation.McpToolListChanged;
30+
import reactor.core.publisher.Mono;
2731

32+
import org.springframework.ai.mcp.annotation.spring.ClientMcpAsyncHandlersRegistry;
33+
import org.springframework.ai.mcp.annotation.spring.ClientMcpSyncHandlersRegistry;
2834
import org.springframework.boot.autoconfigure.AutoConfigurations;
2935
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3036
import org.springframework.context.annotation.Bean;
@@ -47,25 +53,65 @@ public class McpClientListChangedAnnotationsScanningIT {
4753
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
4854
.withConfiguration(AutoConfigurations.of(McpClientAnnotationScannerAutoConfiguration.class));
4955

50-
@ParameterizedTest
51-
@ValueSource(strings = { "SYNC", "ASYNC" })
52-
void shouldScanAllThreeListChangedAnnotations(String clientType) {
53-
String prefix = clientType.toLowerCase();
56+
@Test
57+
public void shouldScanAllThreeListChangedAnnotationsSync() {
58+
this.contextRunner.withUserConfiguration(AllListChangedConfiguration.class)
59+
.withPropertyValues("spring.ai.mcp.client.type=SYNC")
60+
.run(context -> {
61+
// Verify all three annotations were scanned
62+
var registry = context.getBean(ClientMcpSyncHandlersRegistry.class);
63+
var handlers = context.getBean(TestListChangedHandlers.class);
64+
assertThat(registry).isNotNull();
65+
66+
List<McpSchema.Tool> updatedTools = List.of(McpSchema.Tool.builder().name("tool-1").build(),
67+
McpSchema.Tool.builder().name("tool-2").build());
68+
List<McpSchema.Prompt> updatedPrompts = List.of(
69+
new McpSchema.Prompt("prompt-1", "a test prompt", Collections.emptyList()),
70+
new McpSchema.Prompt("prompt-2", "another test prompt", Collections.emptyList()));
71+
List<McpSchema.Resource> updatedResources = List.of(
72+
McpSchema.Resource.builder().name("resource-1").uri("file:///resource/1").build(),
73+
McpSchema.Resource.builder().name("resource-2").uri("file:///resource/2").build());
74+
75+
registry.handleToolListChanged("test-client", updatedTools);
76+
registry.handleResourceListChanged("test-client", updatedResources);
77+
registry.handlePromptListChanged("test-client", updatedPrompts);
78+
79+
assertThat(handlers.getCalls()).hasSize(3)
80+
.containsExactlyInAnyOrder(
81+
new TestListChangedHandlers.Call("resource-list-changed", updatedResources),
82+
new TestListChangedHandlers.Call("prompt-list-changed", updatedPrompts),
83+
new TestListChangedHandlers.Call("tool-list-changed", updatedTools));
84+
});
85+
}
5486

87+
@Test
88+
public void shouldScanAllThreeListChangedAnnotationsAsync() {
5589
this.contextRunner.withUserConfiguration(AllListChangedConfiguration.class)
56-
.withPropertyValues("spring.ai.mcp.client.type=" + clientType)
90+
.withPropertyValues("spring.ai.mcp.client.type=ASYNC")
5791
.run(context -> {
5892
// Verify all three annotations were scanned
59-
McpClientAnnotationScannerAutoConfiguration.ClientMcpAnnotatedBeans annotatedBeans = context
60-
.getBean(McpClientAnnotationScannerAutoConfiguration.ClientMcpAnnotatedBeans.class);
61-
assertThat(annotatedBeans.getBeansByAnnotation(McpToolListChanged.class)).hasSize(1);
62-
assertThat(annotatedBeans.getBeansByAnnotation(McpResourceListChanged.class)).hasSize(1);
63-
assertThat(annotatedBeans.getBeansByAnnotation(McpPromptListChanged.class)).hasSize(1);
64-
65-
// Verify all three specification beans were created
66-
assertThat(context).hasBean(prefix + "ToolListChangedSpecs");
67-
assertThat(context).hasBean(prefix + "ResourceListChangedSpecs");
68-
assertThat(context).hasBean(prefix + "PromptListChangedSpecs");
93+
var registry = context.getBean(ClientMcpAsyncHandlersRegistry.class);
94+
var handlers = context.getBean(TestListChangedHandlers.class);
95+
assertThat(registry).isNotNull();
96+
97+
List<McpSchema.Tool> updatedTools = List.of(McpSchema.Tool.builder().name("tool-1").build(),
98+
McpSchema.Tool.builder().name("tool-2").build());
99+
List<McpSchema.Prompt> updatedPrompts = List.of(
100+
new McpSchema.Prompt("prompt-1", "a test prompt", Collections.emptyList()),
101+
new McpSchema.Prompt("prompt-2", "another test prompt", Collections.emptyList()));
102+
List<McpSchema.Resource> updatedResources = List.of(
103+
McpSchema.Resource.builder().name("resource-1").uri("file:///resource/1").build(),
104+
McpSchema.Resource.builder().name("resource-2").uri("file:///resource/2").build());
105+
106+
registry.handleToolListChanged("test-client", updatedTools).block();
107+
registry.handleResourceListChanged("test-client", updatedResources).block();
108+
registry.handlePromptListChanged("test-client", updatedPrompts).block();
109+
110+
assertThat(handlers.getCalls()).hasSize(3)
111+
.containsExactlyInAnyOrder(
112+
new TestListChangedHandlers.Call("resource-list-changed", updatedResources),
113+
new TestListChangedHandlers.Call("prompt-list-changed", updatedPrompts),
114+
new TestListChangedHandlers.Call("tool-list-changed", updatedTools));
69115
});
70116
}
71117

@@ -79,10 +125,8 @@ void shouldNotScanAnnotationsWhenScannerDisabled(String clientType) {
79125
"spring.ai.mcp.client.annotation-scanner.enabled=false")
80126
.run(context -> {
81127
// Verify scanner beans were not created
82-
assertThat(context).doesNotHaveBean(McpClientAnnotationScannerAutoConfiguration.class);
83-
assertThat(context).doesNotHaveBean(prefix + "ToolListChangedSpecs");
84-
assertThat(context).doesNotHaveBean(prefix + "ResourceListChangedSpecs");
85-
assertThat(context).doesNotHaveBean(prefix + "PromptListChangedSpecs");
128+
assertThat(context).doesNotHaveBean(ClientMcpSyncHandlersRegistry.class);
129+
assertThat(context).doesNotHaveBean(ClientMcpAsyncHandlersRegistry.class);
86130
});
87131
}
88132

@@ -98,19 +142,47 @@ TestListChangedHandlers testHandlers() {
98142

99143
static class TestListChangedHandlers {
100144

145+
private final List<Call> calls = new ArrayList<>();
146+
147+
public List<Call> getCalls() {
148+
return this.calls;
149+
}
150+
101151
@McpToolListChanged(clients = "test-client")
102152
public void onToolListChanged(List<McpSchema.Tool> updatedTools) {
103-
// Test handler for tool list changes
153+
this.calls.add(new Call("tool-list-changed", updatedTools));
104154
}
105155

106156
@McpResourceListChanged(clients = "test-client")
107157
public void onResourceListChanged(List<McpSchema.Resource> updatedResources) {
108-
// Test handler for resource list changes
158+
this.calls.add(new Call("resource-list-changed", updatedResources));
109159
}
110160

111161
@McpPromptListChanged(clients = "test-client")
112162
public void onPromptListChanged(List<McpSchema.Prompt> updatedPrompts) {
113-
// Test handler for prompt list changes
163+
this.calls.add(new Call("prompt-list-changed", updatedPrompts));
164+
}
165+
166+
@McpToolListChanged(clients = "test-client")
167+
public Mono<Void> onToolListChangedReactive(List<McpSchema.Tool> updatedTools) {
168+
this.calls.add(new Call("tool-list-changed", updatedTools));
169+
return Mono.empty();
170+
}
171+
172+
@McpResourceListChanged(clients = "test-client")
173+
public Mono<Void> onResourceListChangedReactive(List<McpSchema.Resource> updatedResources) {
174+
this.calls.add(new Call("resource-list-changed", updatedResources));
175+
return Mono.empty();
176+
}
177+
178+
@McpPromptListChanged(clients = "test-client")
179+
public Mono<Void> onPromptListChangedReactive(List<McpSchema.Prompt> updatedPrompts) {
180+
this.calls.add(new Call("prompt-list-changed", updatedPrompts));
181+
return Mono.empty();
182+
}
183+
184+
// Record calls made to this object
185+
record Call(String name, Object callRequest) {
114186
}
115187

116188
}

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/test/java/org/springframework/ai/mcp/client/autoconfigure/SseHttpClientTransportAutoConfigurationIT.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import reactor.core.publisher.Mono;
3434

3535
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
36+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerAutoConfiguration;
3637
import org.springframework.ai.mcp.client.httpclient.autoconfigure.SseHttpClientTransportAutoConfiguration;
3738
import org.springframework.boot.autoconfigure.AutoConfigurations;
3839
import org.springframework.boot.context.annotation.UserConfigurations;
@@ -56,8 +57,8 @@ public class SseHttpClientTransportAutoConfigurationIT {
5657
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
5758
.withPropertyValues("spring.ai.mcp.client.initialized=false",
5859
"spring.ai.mcp.client.sse.connections.server1.url=" + host)
59-
.withConfiguration(
60-
AutoConfigurations.of(McpClientAutoConfiguration.class, SseHttpClientTransportAutoConfiguration.class));
60+
.withConfiguration(AutoConfigurations.of(McpClientAutoConfiguration.class,
61+
McpClientAnnotationScannerAutoConfiguration.class, SseHttpClientTransportAutoConfiguration.class));
6162

6263
static String host = "http://localhost:3001";
6364

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/test/java/org/springframework/ai/mcp/client/autoconfigure/StreamableHttpHttpClientTransportAutoConfigurationIT.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import reactor.core.publisher.Mono;
3434

3535
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
36+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerAutoConfiguration;
3637
import org.springframework.ai.mcp.client.httpclient.autoconfigure.StreamableHttpHttpClientTransportAutoConfiguration;
3738
import org.springframework.boot.autoconfigure.AutoConfigurations;
3839
import org.springframework.boot.context.annotation.UserConfigurations;
@@ -58,6 +59,7 @@ public class StreamableHttpHttpClientTransportAutoConfigurationIT {
5859
.withPropertyValues("spring.ai.mcp.client.initialized=false",
5960
"spring.ai.mcp.client.streamable-http.connections.server1.url=" + host)
6061
.withConfiguration(AutoConfigurations.of(McpClientAutoConfiguration.class,
62+
McpClientAnnotationScannerAutoConfiguration.class,
6163
StreamableHttpHttpClientTransportAutoConfiguration.class));
6264

6365
static String host = "http://localhost:3001";

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/test/java/org/springframework/ai/mcp/client/webflux/autoconfigure/SseWebFluxTransportAutoConfigurationIT.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.testcontainers.containers.wait.strategy.Wait;
3131

3232
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
33+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerAutoConfiguration;
3334
import org.springframework.boot.autoconfigure.AutoConfigurations;
3435
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3536

@@ -43,8 +44,8 @@ public class SseWebFluxTransportAutoConfigurationIT {
4344
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
4445
.withPropertyValues("spring.ai.mcp.client.initialized=false",
4546
"spring.ai.mcp.client.sse.connections.server1.url=" + host)
46-
.withConfiguration(
47-
AutoConfigurations.of(McpClientAutoConfiguration.class, SseWebFluxTransportAutoConfiguration.class));
47+
.withConfiguration(AutoConfigurations.of(McpClientAutoConfiguration.class,
48+
McpClientAnnotationScannerAutoConfiguration.class, SseWebFluxTransportAutoConfiguration.class));
4849

4950
static String host = "http://localhost:3001";
5051

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/test/java/org/springframework/ai/mcp/client/webflux/autoconfigure/StreamableHttpHttpClientTransportAutoConfigurationIT.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.testcontainers.containers.wait.strategy.Wait;
3131

3232
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
33+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerAutoConfiguration;
3334
import org.springframework.boot.autoconfigure.AutoConfigurations;
3435
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3536

@@ -45,6 +46,7 @@ public class StreamableHttpHttpClientTransportAutoConfigurationIT {
4546
.withPropertyValues("spring.ai.mcp.client.initialized=false",
4647
"spring.ai.mcp.client.streamable-http.connections.server1.url=" + host)
4748
.withConfiguration(AutoConfigurations.of(McpClientAutoConfiguration.class,
49+
McpClientAnnotationScannerAutoConfiguration.class,
4850
StreamableHttpWebFluxTransportAutoConfiguration.class));
4951

5052
static String host = "http://localhost:3001";

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/SseWebClientWebFluxServerIT.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262

6363
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
6464
import org.springframework.ai.mcp.client.common.autoconfigure.McpToolCallbackAutoConfiguration;
65+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerAutoConfiguration;
6566
import org.springframework.ai.mcp.client.webflux.autoconfigure.SseWebFluxTransportAutoConfiguration;
6667
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
6768
import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration;
@@ -93,9 +94,9 @@ public class SseWebClientWebFluxServerIT {
9394
AutoConfigurations.of(McpServerAutoConfiguration.class, McpServerObjectMapperAutoConfiguration.class,
9495
ToolCallbackConverterAutoConfiguration.class, McpServerSseWebFluxAutoConfiguration.class));
9596

96-
private final ApplicationContextRunner clientApplicationContext = new ApplicationContextRunner()
97-
.withConfiguration(AutoConfigurations.of(McpToolCallbackAutoConfiguration.class,
98-
McpClientAutoConfiguration.class, SseWebFluxTransportAutoConfiguration.class));
97+
private final ApplicationContextRunner clientApplicationContext = new ApplicationContextRunner().withConfiguration(
98+
AutoConfigurations.of(McpToolCallbackAutoConfiguration.class, McpClientAutoConfiguration.class,
99+
McpClientAnnotationScannerAutoConfiguration.class, SseWebFluxTransportAutoConfiguration.class));
99100

100101
@Test
101102
void clientServerCapabilities() {

auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-webflux/src/test/java/org/springframework/ai/mcp/server/autoconfigure/StreamableWebClientWebFluxServerIT.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363

6464
import org.springframework.ai.mcp.client.common.autoconfigure.McpClientAutoConfiguration;
6565
import org.springframework.ai.mcp.client.common.autoconfigure.McpToolCallbackAutoConfiguration;
66+
import org.springframework.ai.mcp.client.common.autoconfigure.annotations.McpClientAnnotationScannerAutoConfiguration;
6667
import org.springframework.ai.mcp.client.webflux.autoconfigure.StreamableHttpWebFluxTransportAutoConfiguration;
6768
import org.springframework.ai.mcp.customizer.McpSyncClientCustomizer;
6869
import org.springframework.ai.mcp.server.common.autoconfigure.McpServerAutoConfiguration;
@@ -99,7 +100,8 @@ public class StreamableWebClientWebFluxServerIT {
99100

100101
private final ApplicationContextRunner clientApplicationContext = new ApplicationContextRunner()
101102
.withConfiguration(AutoConfigurations.of(McpToolCallbackAutoConfiguration.class,
102-
McpClientAutoConfiguration.class, StreamableHttpWebFluxTransportAutoConfiguration.class));
103+
McpClientAutoConfiguration.class, McpClientAnnotationScannerAutoConfiguration.class,
104+
StreamableHttpWebFluxTransportAutoConfiguration.class));
103105

104106
@Test
105107
void clientServerCapabilities() {
@@ -521,6 +523,7 @@ McpSyncClientCustomizer clientCustomizer(TestContext testContext) {
521523
testContext.progressNotifications.add(progressNotification);
522524
testContext.progressLatch.countDown();
523525
});
526+
mcpClientSpec.capabilities(McpSchema.ClientCapabilities.builder().sampling().elicitation().build());
524527
};
525528
}
526529

mcp/mcp-annotations-spring/src/test/java/org/springframework/ai/mcp/annotation/spring/ClientMcpSyncHandlersRegistryTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,14 +276,14 @@ void promptListChanged() {
276276
registry.afterSingletonsInstantiated();
277277
var handlers = beanFactory.getBean(HandlersConfiguration.class);
278278

279-
List<McpSchema.Prompt> updatedTools = List.of(
279+
List<McpSchema.Prompt> updatedPrompts = List.of(
280280
new McpSchema.Prompt("prompt-1", "a test prompt", Collections.emptyList()),
281281
new McpSchema.Prompt("prompt-2", "another test prompt", Collections.emptyList()));
282282

283-
registry.handlePromptListChanged("client-1", updatedTools);
283+
registry.handlePromptListChanged("client-1", updatedPrompts);
284284
assertThat(handlers.getCalls()).hasSize(2)
285-
.containsExactlyInAnyOrder(new HandlersConfiguration.Call("handlePromptListChanged", updatedTools),
286-
new HandlersConfiguration.Call("handlePromptListChangedAgain", updatedTools));
285+
.containsExactlyInAnyOrder(new HandlersConfiguration.Call("handlePromptListChanged", updatedPrompts),
286+
new HandlersConfiguration.Call("handlePromptListChangedAgain", updatedPrompts));
287287
}
288288

289289
@Test

0 commit comments

Comments
 (0)