Skip to content

Commit 0dc383b

Browse files
Copilothalter73
andcommitted
Update and improve auto-detect transport tests
Co-authored-by: halter73 <54385+halter73@users.noreply.github.com>
1 parent 96c619e commit 0dc383b

File tree

1 file changed

+86
-46
lines changed

1 file changed

+86
-46
lines changed

tests/ModelContextProtocol.Tests/Transport/SseClientTransportAutoDetectTests.cs

Lines changed: 86 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,36 @@ public async Task AutoDetect_Should_Use_StreamableHttp_When_Server_Supports_It()
2727
using var httpClient = new HttpClient(mockHttpHandler);
2828
await using var transport = new SseClientTransport(options, httpClient, LoggerFactory);
2929

30-
var requestCount = 0;
30+
// Simulate successful Streamable HTTP response for initialize
3131
mockHttpHandler.RequestHandler = (request) =>
3232
{
33-
requestCount++;
34-
35-
// Simulate successful Streamable HTTP response
36-
return Task.FromResult(new HttpResponseMessage
33+
if (request.Method == HttpMethod.Post)
3734
{
38-
StatusCode = HttpStatusCode.OK,
39-
Content = new StringContent("{\"jsonrpc\":\"2.0\",\"id\":\"test-id\",\"result\":{}}"),
40-
Headers =
35+
return Task.FromResult(new HttpResponseMessage
4136
{
42-
{ "Content-Type", "application/json" },
43-
{ "mcp-session-id", "test-session" }
44-
}
45-
});
37+
StatusCode = HttpStatusCode.OK,
38+
Content = new StringContent("{\"jsonrpc\":\"2.0\",\"id\":\"init-id\",\"result\":{\"protocolVersion\":\"2024-11-05\",\"capabilities\":{\"tools\":{}}}}"),
39+
Headers =
40+
{
41+
{ "Content-Type", "application/json" },
42+
{ "mcp-session-id", "test-session" }
43+
}
44+
});
45+
}
46+
47+
// Shouldn't reach here for successful Streamable HTTP
48+
throw new InvalidOperationException("Unexpected request");
4649
};
4750

4851
await using var session = await transport.ConnectAsync(TestContext.Current.CancellationToken);
4952

50-
// The auto-detecting transport should be returned and connected
53+
// The auto-detecting transport should be returned
5154
Assert.NotNull(session);
5255
Assert.True(session.IsConnected);
5356
Assert.IsType<AutoDetectingClientTransport>(session);
54-
55-
// Send a test message to trigger the transport selection
56-
await session.SendMessageAsync(new JsonRpcRequest
57-
{
58-
Method = RequestMethods.Initialize,
59-
Id = new RequestId("test-id")
60-
}, CancellationToken.None);
61-
62-
// Verify that we only made one request (Streamable HTTP worked)
63-
Assert.Equal(1, requestCount);
6457
}
6558

66-
[Fact]
59+
[Fact]
6760
public async Task AutoDetect_Should_Fallback_To_Sse_When_StreamableHttp_Fails()
6861
{
6962
var options = new SseClientTransportOptions
@@ -79,26 +72,24 @@ public async Task AutoDetect_Should_Fallback_To_Sse_When_StreamableHttp_Fails()
7972
await using var transport = new SseClientTransport(options, httpClient, LoggerFactory);
8073

8174
var requestCount = 0;
82-
var isFirstRequest = true;
8375

8476
mockHttpHandler.RequestHandler = (request) =>
8577
{
8678
requestCount++;
8779

88-
if (isFirstRequest && request.Method == HttpMethod.Post)
80+
if (request.Method == HttpMethod.Post && requestCount == 1)
8981
{
90-
isFirstRequest = false;
91-
// Simulate Streamable HTTP failure (e.g., 404 Not Found)
82+
// First POST (Streamable HTTP) fails
9283
return Task.FromResult(new HttpResponseMessage
9384
{
9485
StatusCode = HttpStatusCode.NotFound,
9586
Content = new StringContent("Streamable HTTP not supported")
9687
});
9788
}
9889

99-
// Simulate SSE endpoint response for GET request
10090
if (request.Method == HttpMethod.Get)
10191
{
92+
// SSE connection request
10293
return Task.FromResult(new HttpResponseMessage
10394
{
10495
StatusCode = HttpStatusCode.OK,
@@ -107,33 +98,29 @@ public async Task AutoDetect_Should_Fallback_To_Sse_When_StreamableHttp_Fails()
10798
});
10899
}
109100

110-
// Simulate successful SSE POST response
111-
return Task.FromResult(new HttpResponseMessage
101+
if (request.Method == HttpMethod.Post && requestCount > 1)
112102
{
113-
StatusCode = HttpStatusCode.OK,
114-
Content = new StringContent("accepted")
115-
});
103+
// Subsequent POST to SSE endpoint succeeds
104+
return Task.FromResult(new HttpResponseMessage
105+
{
106+
StatusCode = HttpStatusCode.OK,
107+
Content = new StringContent("accepted")
108+
});
109+
}
110+
111+
throw new InvalidOperationException($"Unexpected request: {request.Method}, count: {requestCount}");
116112
};
117113

118114
await using var session = await transport.ConnectAsync(TestContext.Current.CancellationToken);
119115

120116
// The auto-detecting transport should be returned
121117
Assert.NotNull(session);
118+
Assert.True(session.IsConnected);
122119
Assert.IsType<AutoDetectingClientTransport>(session);
123-
124-
// Send a test message to trigger the transport selection and fallback
125-
await session.SendMessageAsync(new JsonRpcRequest
126-
{
127-
Method = RequestMethods.Initialize,
128-
Id = new RequestId("test-id")
129-
}, CancellationToken.None);
130-
131-
// Verify that we made multiple requests (Streamable HTTP failed, SSE succeeded)
132-
Assert.True(requestCount >= 2, $"Expected at least 2 requests, but got {requestCount}");
133120
}
134121

135122
[Fact]
136-
public async Task AutoDetect_Should_Be_Default_When_UseStreamableHttp_Is_False()
123+
public async Task UseStreamableHttp_False_Should_Default_To_AutoDetect()
137124
{
138125
var options = new SseClientTransportOptions
139126
{
@@ -147,9 +134,9 @@ public async Task AutoDetect_Should_Be_Default_When_UseStreamableHttp_Is_False()
147134
using var httpClient = new HttpClient(mockHttpHandler);
148135
await using var transport = new SseClientTransport(options, httpClient, LoggerFactory);
149136

137+
// Configure for successful Streamable HTTP response
150138
mockHttpHandler.RequestHandler = (request) =>
151139
{
152-
// Simulate successful Streamable HTTP response
153140
return Task.FromResult(new HttpResponseMessage
154141
{
155142
StatusCode = HttpStatusCode.OK,
@@ -164,6 +151,27 @@ public async Task AutoDetect_Should_Be_Default_When_UseStreamableHttp_Is_False()
164151
Assert.IsType<AutoDetectingClientTransport>(session);
165152
}
166153

154+
[Fact]
155+
public async Task UseStreamableHttp_True_Should_Return_StreamableHttp_Transport()
156+
{
157+
var options = new SseClientTransportOptions
158+
{
159+
Endpoint = new Uri("http://localhost:8080"),
160+
UseStreamableHttp = true, // This should map to StreamableHttp mode
161+
ConnectionTimeout = TimeSpan.FromSeconds(2),
162+
Name = "Test Server"
163+
};
164+
165+
using var mockHttpHandler = new MockHttpHandler();
166+
using var httpClient = new HttpClient(mockHttpHandler);
167+
await using var transport = new SseClientTransport(options, httpClient, LoggerFactory);
168+
169+
await using var session = await transport.ConnectAsync(TestContext.Current.CancellationToken);
170+
171+
// Should return StreamableHttpClientSessionTransport directly
172+
Assert.IsType<StreamableHttpClientSessionTransport>(session);
173+
}
174+
167175
[Fact]
168176
public async Task StreamableHttp_Mode_Should_Return_StreamableHttp_Transport()
169177
{
@@ -216,4 +224,36 @@ public async Task Sse_Mode_Should_Return_Sse_Transport()
216224
// Should return SseClientSessionTransport directly
217225
Assert.IsType<SseClientSessionTransport>(session);
218226
}
227+
228+
[Fact]
229+
public void GetEffectiveTransportMode_Should_Respect_TransportMode_Over_UseStreamableHttp()
230+
{
231+
var options = new SseClientTransportOptions
232+
{
233+
Endpoint = new Uri("http://localhost:8080"),
234+
UseStreamableHttp = true,
235+
TransportMode = SseTransportMode.Sse // This should override UseStreamableHttp
236+
};
237+
238+
var effectiveMode = options.GetEffectiveTransportMode();
239+
Assert.Equal(SseTransportMode.Sse, effectiveMode);
240+
}
241+
242+
[Fact]
243+
public void GetEffectiveTransportMode_Should_Use_UseStreamableHttp_When_TransportMode_Not_Set()
244+
{
245+
var options1 = new SseClientTransportOptions
246+
{
247+
Endpoint = new Uri("http://localhost:8080"),
248+
UseStreamableHttp = true
249+
};
250+
Assert.Equal(SseTransportMode.StreamableHttp, options1.GetEffectiveTransportMode());
251+
252+
var options2 = new SseClientTransportOptions
253+
{
254+
Endpoint = new Uri("http://localhost:8080"),
255+
UseStreamableHttp = false
256+
};
257+
Assert.Equal(SseTransportMode.AutoDetect, options2.GetEffectiveTransportMode());
258+
}
219259
}

0 commit comments

Comments
 (0)