Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Fix several WebSocket tests blocking xunit's SynchronizationContext (#…
Browse files Browse the repository at this point in the history
…32591)

* Fix several WebSocket tests that were blocking xunit's SynchronizationContext

* Address PR feedback
  • Loading branch information
stephentoub authored Oct 3, 2018
1 parent 9cb4ea0 commit 7685f1c
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 35 deletions.
13 changes: 13 additions & 0 deletions src/Common/tests/System/Threading/Tasks/TaskTimeoutExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,19 @@ namespace System.Threading.Tasks
{
public static class TaskTimeoutExtensions
{
public static async Task WithCancellation(this Task task, CancellationToken cancellationToken)
{
var tcs = new TaskCompletionSource<bool>();
using (cancellationToken.Register(s => ((TaskCompletionSource<bool>)s).TrySetResult(true), tcs))
{
if (task != await Task.WhenAny(task, tcs.Task).ConfigureAwait(false))
{
throw new OperationCanceledException(cancellationToken);
}
await task; // already completed; propagate any exception
}
}

public static async Task TimeoutAfter(this Task task, int millisecondsTimeout)
{
var cts = new CancellationTokenSource();
Expand Down
65 changes: 31 additions & 34 deletions src/System.Net.WebSockets.Client/tests/SendReceiveTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ public async Task SendAsync_MultipleOutstandingSendOperations_Throws(Uri server)
cts.Token);
}

Task.WaitAll(tasks);
await Task.WhenAll(tasks);

Assert.Equal(WebSocketState.Open, cws.State);
}
Expand Down Expand Up @@ -225,41 +225,38 @@ await SendAsync(
tasks[i] = ReceiveAsync(cws, recvSegment, cts.Token);
}

Task.WaitAll(tasks);
await Task.WhenAll(tasks);
Assert.Equal(WebSocketState.Open, cws.State);
}
catch (AggregateException ag)
catch (Exception ex)
{
foreach (var ex in ag.InnerExceptions)
if (ex is InvalidOperationException)
{
if (ex is InvalidOperationException)
{
Assert.Equal(
ResourceHelper.GetExceptionMessage(
"net_Websockets_AlreadyOneOutstandingOperation",
"ReceiveAsync"),
ex.Message);
Assert.Equal(
ResourceHelper.GetExceptionMessage(
"net_Websockets_AlreadyOneOutstandingOperation",
"ReceiveAsync"),
ex.Message);

Assert.Equal(WebSocketState.Aborted, cws.State);
}
else if (ex is WebSocketException)
{
// Multiple cases.
Assert.Equal(WebSocketState.Aborted, cws.State);
Assert.Equal(WebSocketState.Aborted, cws.State);
}
else if (ex is WebSocketException)
{
// Multiple cases.
Assert.Equal(WebSocketState.Aborted, cws.State);

WebSocketError errCode = (ex as WebSocketException).WebSocketErrorCode;
Assert.True(
(errCode == WebSocketError.InvalidState) || (errCode == WebSocketError.Success),
"WebSocketErrorCode");
}
else if (ex is OperationCanceledException)
{
Assert.Equal(WebSocketState.Aborted, cws.State);
}
else
{
Assert.True(false, "Unexpected exception: " + ex.Message);
}
WebSocketError errCode = (ex as WebSocketException).WebSocketErrorCode;
Assert.True(
(errCode == WebSocketError.InvalidState) || (errCode == WebSocketError.Success),
"WebSocketErrorCode");
}
else if (ex is OperationCanceledException)
{
Assert.Equal(WebSocketState.Aborted, cws.State);
}
else
{
Assert.True(false, "Unexpected exception: " + ex.Message);
}
}
}
Expand Down Expand Up @@ -381,7 +378,7 @@ public async Task SendReceive_ConnectionClosedPrematurely_ReceiveAsyncFailsAndWe

Func<ClientWebSocket, LoopbackServer, Uri, Task> connectToServerThatAbortsConnection = async (clientSocket, server, url) =>
{
AutoResetEvent pendingReceiveAsyncPosted = new AutoResetEvent(false);
var pendingReceiveAsyncPosted = new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
// Start listening for incoming connections on the server side.
Task acceptTask = server.AcceptConnectionAsync(async connection =>
Expand All @@ -390,7 +387,7 @@ public async Task SendReceive_ConnectionClosedPrematurely_ReceiveAsyncFailsAndWe
Assert.True(await LoopbackHelper.WebSocketHandshakeAsync(connection));
// Wait for client-side ConnectAsync to complete and for a pending ReceiveAsync to be posted.
pendingReceiveAsyncPosted.WaitOne(TimeOutMilliseconds);
await pendingReceiveAsyncPosted.Task.TimeoutAfter(TimeOutMilliseconds);
// Close the underlying connection prematurely (without sending a WebSocket Close frame).
connection.Socket.Shutdown(SocketShutdown.Both);
Expand All @@ -405,10 +402,10 @@ public async Task SendReceive_ConnectionClosedPrematurely_ReceiveAsyncFailsAndWe
var recvBuffer = new byte[100];
var recvSegment = new ArraySegment<byte>(recvBuffer);
Task pendingReceiveAsync = ReceiveAsync(clientSocket, recvSegment, cts.Token);
pendingReceiveAsyncPosted.Set();
pendingReceiveAsyncPosted.SetResult(true);
// Wait for the server to close the underlying connection.
acceptTask.Wait(cts.Token);
await acceptTask.WithCancellation(cts.Token);
WebSocketException pendingReceiveException = await Assert.ThrowsAsync<WebSocketException>(() => pendingReceiveAsync);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ protected override async Task<WebSocketReceiveResult> ReceiveAsync(WebSocket ws,
{
ValueWebSocketReceiveResult r = await ws.ReceiveAsync(
(Memory<byte>)arraySegment,
cancellationToken);
cancellationToken).ConfigureAwait(false);
return new WebSocketReceiveResult(r.Count, r.MessageType, r.EndOfMessage, ws.CloseStatus, ws.CloseStatusDescription);
}

Expand Down

0 comments on commit 7685f1c

Please sign in to comment.