Fix flaky test (#622)

- Remove timeout and closed the application when the transport closes.
Made some tweaks to TestWebSocketConnectionFeature as a result.
- This uncovered some interesting issues with the WebSocketTransport itself so
further refactoring is needed to make it a bit more solid.
This commit is contained in:
David Fowler 2017-06-30 02:30:09 -07:00 committed by GitHub
parent d125a14a39
commit 53e09f8cc3
2 changed files with 49 additions and 17 deletions

View File

@ -62,6 +62,11 @@ namespace Microsoft.AspNetCore.Sockets.Tests
_state = WebSocketState.Aborted;
}
public void SendAbort()
{
_output.TryComplete(new WebSocketException(WebSocketError.ConnectionClosedPrematurely));
}
public override async Task CloseAsync(WebSocketCloseStatus closeStatus, string statusDescription, CancellationToken cancellationToken)
{
await SendMessageAsync(new WebSocketMessage
@ -100,20 +105,39 @@ namespace Microsoft.AspNetCore.Sockets.Tests
public override async Task<WebSocketReceiveResult> ReceiveAsync(ArraySegment<byte> buffer, CancellationToken cancellationToken)
{
var message = await _input.ReadAsync();
if (message.MessageType == WebSocketMessageType.Close)
try
{
_state = WebSocketState.CloseReceived;
_closeStatus = message.CloseStatus;
_closeStatusDescription = message.CloseStatusDescription;
return new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, message.CloseStatus, message.CloseStatusDescription);
await _input.WaitToReadAsync();
if (_input.TryRead(out var message))
{
if (message.MessageType == WebSocketMessageType.Close)
{
_state = WebSocketState.CloseReceived;
_closeStatus = message.CloseStatus;
_closeStatusDescription = message.CloseStatusDescription;
return new WebSocketReceiveResult(0, WebSocketMessageType.Close, true, message.CloseStatus, message.CloseStatusDescription);
}
// REVIEW: This assumes the buffer passed in is > the buffer received
Buffer.BlockCopy(message.Buffer, 0, buffer.Array, buffer.Offset, message.Buffer.Length);
return new WebSocketReceiveResult(message.Buffer.Length, message.MessageType, message.EndOfMessage);
}
}
catch (WebSocketException ex)
{
switch (ex.WebSocketErrorCode)
{
case WebSocketError.ConnectionClosedPrematurely:
_state = WebSocketState.Aborted;
break;
}
throw;
}
// REVIEW: This assumes the buffer passed in is > the buffer received
Buffer.BlockCopy(message.Buffer, 0, buffer.Array, buffer.Offset, message.Buffer.Length);
return new WebSocketReceiveResult(message.Buffer.Length, message.MessageType, message.EndOfMessage);
throw new InvalidOperationException("Unexpected close");
}
public override Task SendAsync(ArraySegment<byte> buffer, WebSocketMessageType messageType, bool endOfMessage, CancellationToken cancellationToken)

View File

@ -106,12 +106,16 @@ namespace Microsoft.AspNetCore.Sockets.Tests
using (var applicationSide = ChannelConnection.Create<byte[]>(transportToApplication, applicationToTransport))
using (var feature = new TestWebSocketConnectionFeature())
{
var options = new WebSocketOptions()
async Task CompleteApplicationAfterTransportCompletes()
{
CloseTimeout = TimeSpan.FromMilliseconds(100)
};
// Wait until the transport completes so that we can end the application
await applicationSide.In.WaitToReadAsync();
var ws = new WebSocketsTransport(options, transportSide, connectionId: string.Empty, loggerFactory: new LoggerFactory());
// Complete the application so that the connection unwinds without aborting
applicationSide.Out.TryComplete();
}
var ws = new WebSocketsTransport(new WebSocketOptions(), transportSide, connectionId: string.Empty, loggerFactory: new LoggerFactory());
// Give the server socket to the transport and run it
var transport = ws.ProcessSocketAsync(await feature.AcceptAsync());
@ -119,11 +123,15 @@ namespace Microsoft.AspNetCore.Sockets.Tests
// Run the client socket
var client = feature.Client.ExecuteAndCaptureFramesAsync();
// When the close frame is received, we complete the application so the send
// loop unwinds
_ = CompleteApplicationAfterTransportCompletes();
// Terminate the client to server channel with an exception
feature.Client.Abort();
feature.Client.SendAbort();
// Wait for the transport
await Assert.ThrowsAsync<OperationCanceledException>(() => transport).OrTimeout();
await Assert.ThrowsAsync<WebSocketException>(() => transport).OrTimeout();
var summary = await client.OrTimeout();
Assert.Equal(WebSocketCloseStatus.InternalServerError, summary.CloseResult.CloseStatus);