Skip to content

Commit 8e57ac6

Browse files
Copilotericstj
andauthored
Centralize test timeout constants to fix sporadic CI failures (#1210)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ericstj <8918108+ericstj@users.noreply.github.com> Co-authored-by: Eric StJohn <ericstj@microsoft.com>
1 parent 7c85ac6 commit 8e57ac6

14 files changed

Lines changed: 56 additions & 35 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace ModelContextProtocol.Tests.Utils;
2+
3+
/// <summary>
4+
/// Provides centralized constants for tests
5+
/// </summary>
6+
public static class TestConstants
7+
{
8+
/// <summary>
9+
/// Default timeout for test operations that may be affected by CI machine load.
10+
/// Set to 60 seconds to provide sufficient buffer for slow CI environments.
11+
/// </summary>
12+
public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(60);
13+
}

tests/ModelContextProtocol.AspNetCore.Tests/MapMcpStreamableHttpTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using ModelContextProtocol.Client;
55
using ModelContextProtocol.Protocol;
66
using ModelContextProtocol.Server;
7+
using ModelContextProtocol.Tests.Utils;
78
using System.Collections.Concurrent;
89
using System.Threading;
910
using System.Threading.Tasks;
@@ -251,7 +252,7 @@ public async Task CanResumeSessionWithMapMcpAndRunSessionHandler()
251252
Assert.NotNull(serverInfo);
252253
Assert.False(string.IsNullOrEmpty(resumedSessionId));
253254

254-
await serverTcs.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
255+
await serverTcs.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
255256

256257
await using var resumeTransport = new HttpClientTransport(new()
257258
{

tests/ModelContextProtocol.AspNetCore.Tests/ResumabilityIntegrationTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using ModelContextProtocol.Client;
1111
using ModelContextProtocol.Protocol;
1212
using ModelContextProtocol.Server;
13+
using ModelContextProtocol.Tests.Utils;
1314

1415
namespace ModelContextProtocol.AspNetCore.Tests;
1516

@@ -279,7 +280,7 @@ public async Task Client_CanResumePostResponseStream_AfterDisconnection()
279280
[Fact]
280281
public async Task Client_CanResumeUnsolicitedMessageStream_AfterDisconnection()
281282
{
282-
var timeout = TimeSpan.FromSeconds(10);
283+
var timeout = TestConstants.DefaultTimeout;
283284
using var faultingStreamHandler = new FaultingStreamHandler()
284285
{
285286
InnerHandler = SocketsHttpHandler,

tests/ModelContextProtocol.AspNetCore.Tests/ServerConformanceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public async ValueTask DisposeAsync()
8383
{
8484
try
8585
{
86-
await _serverTask.WaitAsync(TimeSpan.FromSeconds(5));
86+
await _serverTask.WaitAsync(TestConstants.DefaultTimeout);
8787
}
8888
catch
8989
{

tests/ModelContextProtocol.AspNetCore.Tests/SseIntegrationTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using ModelContextProtocol.Client;
99
using ModelContextProtocol.Protocol;
1010
using ModelContextProtocol.Server;
11+
using ModelContextProtocol.Tests.Utils;
1112
using System.Text.Json.Serialization;
1213
using TestServerWithHosting.Tools;
1314

@@ -110,7 +111,7 @@ public async Task ConnectAndReceiveNotification_InMemoryServer()
110111
// Send a test message through POST endpoint
111112
await mcpClient.SendNotificationAsync("test/notification", new Envelope { Message = "Hello from client!" }, serializerOptions: JsonContext.Default.Options, cancellationToken: TestContext.Current.CancellationToken);
112113

113-
var message = await receivedNotification.Task.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken);
114+
var message = await receivedNotification.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
114115
Assert.Equal("Hello from server!", message);
115116
}
116117

tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpClientConformanceTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using ModelContextProtocol.Client;
77
using ModelContextProtocol.Protocol;
88
using ModelContextProtocol.Server;
9+
using ModelContextProtocol.Tests.Utils;
910
using System.Threading;
1011
using System.Threading.Tasks;
1112
using System.Text.Json;
@@ -245,7 +246,7 @@ public async Task ResumeSessionStartsGetImmediately()
245246
loggerFactory: LoggerFactory,
246247
cancellationToken: TestContext.Current.CancellationToken))
247248
{
248-
var observedSessionId = await resumeServer.GetStarted.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
249+
var observedSessionId = await resumeServer.GetStarted.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
249250
Assert.Equal(sessionId, observedSessionId);
250251

251252
var tools = await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken);

tests/ModelContextProtocol.AspNetCore.Tests/StreamableHttpServerConformanceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ public async Task MultipleConcurrentJsonRpcRequests_IsHandled_InParallel()
249249
await Task.WhenAll(echoTasks);
250250
}
251251

252-
[Fact]
252+
[Fact(Skip = "https://github.com/modelcontextprotocol/csharp-sdk/issues/1211")]
253253
public async Task GetRequest_Receives_UnsolicitedNotifications()
254254
{
255255
McpServer? server = null;

tests/ModelContextProtocol.Tests/Client/McpClientResourceSubscriptionTests.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using ModelContextProtocol.Client;
33
using ModelContextProtocol.Protocol;
44
using ModelContextProtocol.Server;
5+
using ModelContextProtocol.Tests.Utils;
56
using System.ComponentModel;
67

78
namespace ModelContextProtocol.Tests.Client;
@@ -50,7 +51,7 @@ await Server.SendNotificationAsync(
5051
cancellationToken: TestContext.Current.CancellationToken);
5152

5253
// Assert
53-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
54+
using var cts = new CancellationTokenSource(TestConstants.DefaultTimeout);
5455
var receivedNotification = await notificationReceived.Task.WaitAsync(cts.Token);
5556
Assert.NotNull(receivedNotification);
5657
Assert.Equal(resourceUri, receivedNotification.Uri);
@@ -92,7 +93,7 @@ await Server.SendNotificationAsync(
9293
cancellationToken: TestContext.Current.CancellationToken);
9394

9495
// Assert
95-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
96+
using var cts = new CancellationTokenSource(TestConstants.DefaultTimeout);
9697
await correctNotificationReceived.Task.WaitAsync(cts.Token);
9798

9899
// Give a small delay to ensure no other notifications are processed
@@ -168,7 +169,7 @@ await Server.SendNotificationAsync(
168169
cancellationToken: TestContext.Current.CancellationToken);
169170

170171
// Assert
171-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
172+
using var cts = new CancellationTokenSource(TestConstants.DefaultTimeout);
172173
var receivedNotification = await notificationReceived.Task.WaitAsync(cts.Token);
173174
Assert.NotNull(receivedNotification);
174175
Assert.Equal(resourceUri.AbsoluteUri, receivedNotification.Uri);
@@ -263,7 +264,7 @@ await Server.SendNotificationAsync(
263264
cancellationToken: TestContext.Current.CancellationToken);
264265

265266
// Assert
266-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
267+
using var cts = new CancellationTokenSource(TestConstants.DefaultTimeout);
267268
var combined = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, TestContext.Current.CancellationToken);
268269
await Task.WhenAll(
269270
notification1Received.Task.WaitAsync(combined.Token),
@@ -341,7 +342,7 @@ await Server.SendNotificationAsync(
341342
cancellationToken: TestContext.Current.CancellationToken);
342343

343344
// Assert - Both handlers should be invoked
344-
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5));
345+
using var cts = new CancellationTokenSource(TestConstants.DefaultTimeout);
345346
var combined = CancellationTokenSource.CreateLinkedTokenSource(cts.Token, TestContext.Current.CancellationToken);
346347
await Task.WhenAll(
347348
handler1Called.Task.WaitAsync(combined.Token),
@@ -360,7 +361,7 @@ await Server.SendNotificationAsync(
360361
cancellationToken: TestContext.Current.CancellationToken);
361362

362363
// Wait for handler2 to be called again
363-
using var cts2 = new CancellationTokenSource(TimeSpan.FromSeconds(5));
364+
using var cts2 = new CancellationTokenSource(TestConstants.DefaultTimeout);
364365
var combined2 = CancellationTokenSource.CreateLinkedTokenSource(cts2.Token, TestContext.Current.CancellationToken);
365366
await handler2CalledAgain.Task.WaitAsync(combined2.Token);
366367

tests/ModelContextProtocol.Tests/Client/McpClientTaskSamplingElicitationTests.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using ModelContextProtocol.Client;
33
using ModelContextProtocol.Protocol;
44
using ModelContextProtocol.Server;
5+
using ModelContextProtocol.Tests.Utils;
56
using System.Text.Json;
67

78
namespace ModelContextProtocol.Tests.Client;
@@ -219,7 +220,7 @@ public async Task Client_WithTaskStore_CanExecuteSamplingAsTask()
219220
Assert.Equal(McpTaskStatus.Working, mcpTask.Status);
220221

221222
// Wait for sampling to complete
222-
await samplingCompleted.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
223+
await samplingCompleted.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
223224

224225
// Poll until task is complete
225226
McpTask taskStatus;
@@ -375,7 +376,7 @@ public async Task Client_WithTaskStore_CanExecuteElicitationAsTask()
375376
Assert.Equal(McpTaskStatus.Working, mcpTask.Status);
376377

377378
// Wait for elicitation to complete
378-
await elicitationCompleted.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
379+
await elicitationCompleted.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
379380

380381
// Poll until task is complete
381382
McpTask taskStatus;
@@ -488,7 +489,7 @@ public async Task Client_CanCancelTasks()
488489
TestContext.Current.CancellationToken);
489490

490491
// Wait for sampling to start
491-
await samplingStarted.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
492+
await samplingStarted.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
492493

493494
// Act - Cancel the task
494495
var cancelledTask = await Server.CancelTaskAsync(mcpTask.TaskId, TestContext.Current.CancellationToken);
@@ -600,8 +601,8 @@ public async Task Client_TaskStatusNotifications_SentWhenEnabled()
600601
// Wait for both Working and Completed notifications to arrive
601602
// The notifications are sent asynchronously so we need to wait for both
602603
await Task.WhenAll(
603-
workingNotificationReceived.Task.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken),
604-
completedNotificationReceived.Task.WaitAsync(TimeSpan.FromSeconds(10), TestContext.Current.CancellationToken));
604+
workingNotificationReceived.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken),
605+
completedNotificationReceived.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken));
605606

606607
// Assert - Should have received notifications for status transitions
607608
await notificationHandler.DisposeAsync();
@@ -653,7 +654,7 @@ public async Task Client_SamplingHandlerException_ResultsInFailedTask()
653654
TestContext.Current.CancellationToken);
654655

655656
// Wait for sampling attempt
656-
await samplingAttempted.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
657+
await samplingAttempted.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
657658

658659
// Poll until task status changes
659660
McpTask taskStatus;
@@ -703,7 +704,7 @@ public async Task Client_ElicitationHandlerException_ResultsInFailedTask()
703704
TestContext.Current.CancellationToken);
704705

705706
// Wait for elicitation attempt
706-
await elicitationAttempted.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
707+
await elicitationAttempted.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
707708

708709
// Poll until task status changes
709710
McpTask taskStatus;

tests/ModelContextProtocol.Tests/Protocol/UrlElicitationTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Microsoft.Extensions.DependencyInjection;
33
using ModelContextProtocol.Client;
44
using ModelContextProtocol.Protocol;
5+
using ModelContextProtocol.Tests.Utils;
56

67
namespace ModelContextProtocol.Tests.Configuration;
78

@@ -275,7 +276,7 @@ public async Task Can_Elicit_OutOfBand_With_Url()
275276
Assert.NotNull(capturedMessage);
276277
Assert.Contains(capturedElicitationId, capturedUrl);
277278

278-
var notifiedElicitationId = await completionNotification.Task.WaitAsync(TimeSpan.FromSeconds(5), TestContext.Current.CancellationToken);
279+
var notifiedElicitationId = await completionNotification.Task.WaitAsync(TestConstants.DefaultTimeout, TestContext.Current.CancellationToken);
279280
Assert.Equal(capturedElicitationId, notifiedElicitationId);
280281
}
281282

0 commit comments

Comments
 (0)