Skip to content

Commit

Permalink
Add timeout exception for .NET 5 or greater targets.
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminsampica authored and skwasjer committed Mar 24, 2023
1 parent df1bbfa commit 6448126
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 2 deletions.
15 changes: 14 additions & 1 deletion src/MockHttp/Responses/TimeoutBehavior.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,27 @@ public TimeoutBehavior(TimeSpan timeoutAfter)

public Task HandleAsync(MockHttpRequestContext requestContext, HttpResponseMessage responseMessage, ResponseHandlerDelegate next, CancellationToken cancellationToken)
{
// It is somewhat unintuitive to throw TaskCanceledException but this is what HttpClient does atm,
// It is somewhat unintuitive to throw TaskCanceledException but this is what HttpClient does,
// so we simulate same behavior.
// https://github.com/dotnet/corefx/issues/20296
// Beginning in .NET 5, the TaskCanceledException's inner exception is a TimeoutException to clarify client timeout.

return Task.Delay(_timeoutAfter, cancellationToken)
.ContinueWith(_ =>
{
var tcs = new TaskCompletionSource<HttpResponseMessage>();
#if NET5_0_OR_GREATER
if (!cancellationToken.IsCancellationRequested)
{
tcs.TrySetException(new TaskCanceledException(null, new TimeoutException()));
}
else
{
tcs.TrySetCanceled();
}
#else
tcs.TrySetCanceled();
#endif
return tcs.Task;
},
TaskScheduler.Current)
Expand Down
8 changes: 7 additions & 1 deletion test/MockHttp.Tests/Responses/TimeoutBehaviorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ public async Task Given_timeout_when_sending_should_timeout_after_time_passed(in

// Assert
sw.Start();

#if NET5_0_OR_GREATER
await act.Should().ThrowAsync<TaskCanceledException>().WithInnerException(typeof(TimeoutException), "the timeout expired");
#else
await act.Should().ThrowAsync<TaskCanceledException>("the timeout expired");
#endif

sw.Elapsed.Should()
// Allow 5% diff.
.BeGreaterThan(timeout - TimeSpan.FromMilliseconds(timeoutInMilliseconds * 0.95));
Expand All @@ -41,7 +47,7 @@ public async Task Given_cancellation_token_is_cancelled_when_sending_should_thro
Func<Task> act = () => sut.HandleAsync(new MockHttpRequestContext(new HttpRequestMessage()), new HttpResponseMessage(), next.Object, ct);

// Assert
await act.Should().ThrowAsync<TaskCanceledException>();
await act.Should().ThrowAsync<TaskCanceledException>().Where(ex => ex.InnerException == null);
sw.Elapsed.Should().BeLessThan(timeout);
next.VerifyNoOtherCalls();
}
Expand Down

0 comments on commit 6448126

Please sign in to comment.