Skip to content

Commit 231e013

Browse files
Copilothalter73
andauthored
Reduce flakiness in long-running stateless HTTP tool timeout test (#1300)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: halter73 <54385+halter73@users.noreply.github.com>
1 parent b967835 commit 231e013

File tree

1 file changed

+39
-24
lines changed

1 file changed

+39
-24
lines changed

tests/ModelContextProtocol.AspNetCore.Tests/MapMcpTests.cs

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -245,34 +245,49 @@ public async Task LongRunningToolCall_DoesNotTimeout_WhenNoEventStreamStore()
245245
app.MapMcp();
246246
await app.StartAsync(TestContext.Current.CancellationToken);
247247

248-
// Create a custom HttpClient with a very short timeout (1 second)
249-
// The tool will take 2 seconds to complete
250-
using var shortTimeoutClient = new HttpClient(SocketsHttpHandler)
248+
// Retry a couple of times to reduce occasional flakiness on low-resource machines.
249+
// If the server regresses to flushing only after tool completion, each attempt should still fail
250+
// because HttpClient timeout (1 second) is below the tool duration (2 seconds).
251+
for (var attempt = 0; attempt < 3; attempt++)
251252
{
252-
BaseAddress = new Uri("http://localhost:5000/"),
253-
Timeout = TimeSpan.FromSeconds(1)
254-
};
255-
256-
var path = UseStreamableHttp ? "/" : "/sse";
257-
var transportMode = UseStreamableHttp ? HttpTransportMode.StreamableHttp : HttpTransportMode.Sse;
258-
259-
await using var transport = new HttpClientTransport(new()
260-
{
261-
Endpoint = new($"http://localhost:5000{path}"),
262-
TransportMode = transportMode,
263-
}, shortTimeoutClient, LoggerFactory);
253+
try
254+
{
255+
// Create a custom HttpClient with a very short timeout (1 second)
256+
// The tool will take 2 seconds to complete
257+
using var shortTimeoutClient = new HttpClient(SocketsHttpHandler, disposeHandler: false)
258+
{
259+
BaseAddress = new Uri("http://localhost:5000/"),
260+
Timeout = TimeSpan.FromSeconds(1)
261+
};
264262

265-
await using var mcpClient = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
263+
var path = UseStreamableHttp ? "/" : "/sse";
264+
var transportMode = UseStreamableHttp ? HttpTransportMode.StreamableHttp : HttpTransportMode.Sse;
266265

267-
// Call a tool that takes 2 seconds - this should succeed despite the 1 second HttpClient timeout
268-
// because the response stream is flushed immediately after receiving the request
269-
var response = await mcpClient.CallToolAsync(
270-
"long_running_operation",
271-
new Dictionary<string, object?>() { ["durationMs"] = 2000 },
272-
cancellationToken: TestContext.Current.CancellationToken);
266+
await using var transport = new HttpClientTransport(new()
267+
{
268+
Endpoint = new($"http://localhost:5000{path}"),
269+
TransportMode = transportMode,
270+
}, shortTimeoutClient, LoggerFactory);
271+
272+
await using var mcpClient = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
273+
274+
// Call a tool that takes 2 seconds - this should succeed despite the 1 second HttpClient timeout
275+
// because the response stream is flushed immediately after receiving the request
276+
var response = await mcpClient.CallToolAsync(
277+
"long_running_operation",
278+
new Dictionary<string, object?>() { ["durationMs"] = 2000 },
279+
cancellationToken: TestContext.Current.CancellationToken);
280+
281+
var content = Assert.Single(response.Content.OfType<TextContentBlock>());
282+
Assert.Equal("Operation completed after 2000ms", content.Text);
283+
return;
284+
}
285+
catch (OperationCanceledException) when (attempt < 2)
286+
{
287+
// Retry intermittent timeout-related failures on slow CI machines.
288+
}
289+
}
273290

274-
var content = Assert.Single(response.Content.OfType<TextContentBlock>());
275-
Assert.Equal("Operation completed after 2000ms", content.Text);
276291
}
277292

278293
private ClaimsPrincipal CreateUser(string name)

0 commit comments

Comments
 (0)