Merge pull request #3243 from dotnet-maestro-bot/merge/release/2.2-to-master
[automated] Merge branch 'release/2.2' => 'master'
This commit is contained in:
commit
e5e51ac6ca
|
|
@ -7,27 +7,37 @@ using System.IO.Pipelines;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http.Connections.Internal;
|
using Microsoft.AspNetCore.Http.Connections.Internal;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Tests;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
{
|
{
|
||||||
public class HttpConnectionManagerTests
|
public class HttpConnectionManagerTests : VerifiableLoggedTest
|
||||||
{
|
{
|
||||||
|
public HttpConnectionManagerTests(ITestOutputHelper output)
|
||||||
|
: base(output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void NewConnectionsHaveConnectionId()
|
public void NewConnectionsHaveConnectionId()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection();
|
{
|
||||||
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection();
|
||||||
|
|
||||||
Assert.NotNull(connection.ConnectionId);
|
Assert.NotNull(connection.ConnectionId);
|
||||||
Assert.Equal(HttpConnectionStatus.Inactive, connection.Status);
|
Assert.Equal(HttpConnectionStatus.Inactive, connection.Status);
|
||||||
Assert.Null(connection.ApplicationTask);
|
Assert.Null(connection.ApplicationTask);
|
||||||
Assert.Null(connection.TransportTask);
|
Assert.Null(connection.TransportTask);
|
||||||
Assert.Null(connection.Cancellation);
|
Assert.Null(connection.Cancellation);
|
||||||
Assert.NotEqual(default, connection.LastSeenUtc);
|
Assert.NotEqual(default, connection.LastSeenUtc);
|
||||||
Assert.NotNull(connection.Transport);
|
Assert.NotNull(connection.Transport);
|
||||||
Assert.NotNull(connection.Application);
|
Assert.NotNull(connection.Application);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -42,305 +52,341 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
[InlineData(ConnectionStates.CloseGracefully | ConnectionStates.ApplicationFaulted | ConnectionStates.TransportNotFaulted)]
|
[InlineData(ConnectionStates.CloseGracefully | ConnectionStates.ApplicationFaulted | ConnectionStates.TransportNotFaulted)]
|
||||||
public async Task DisposingConnectionsClosesBothSidesOfThePipe(ConnectionStates states)
|
public async Task DisposingConnectionsClosesBothSidesOfThePipe(ConnectionStates states)
|
||||||
{
|
{
|
||||||
var closeGracefully = (states & ConnectionStates.CloseGracefully) != 0;
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var applicationFaulted = (states & ConnectionStates.ApplicationFaulted) != 0;
|
|
||||||
var transportFaulted = (states & ConnectionStates.TransportFaulted) != 0;
|
|
||||||
|
|
||||||
var connectionManager = CreateConnectionManager();
|
|
||||||
var connection = connectionManager.CreateConnection();
|
|
||||||
|
|
||||||
if (applicationFaulted)
|
|
||||||
{
|
{
|
||||||
// If the application is faulted then we want to make sure the transport task only completes after
|
var closeGracefully = (states & ConnectionStates.CloseGracefully) != 0;
|
||||||
// the application completes
|
var applicationFaulted = (states & ConnectionStates.ApplicationFaulted) != 0;
|
||||||
connection.ApplicationTask = Task.FromException(new Exception("Application failed"));
|
var transportFaulted = (states & ConnectionStates.TransportFaulted) != 0;
|
||||||
connection.TransportTask = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
// Wait for the application to end
|
|
||||||
var result = await connection.Application.Input.ReadAsync();
|
|
||||||
connection.Application.Input.AdvanceTo(result.Buffer.End);
|
|
||||||
|
|
||||||
if (transportFaulted)
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection();
|
||||||
|
|
||||||
|
if (applicationFaulted)
|
||||||
|
{
|
||||||
|
// If the application is faulted then we want to make sure the transport task only completes after
|
||||||
|
// the application completes
|
||||||
|
connection.ApplicationTask = Task.FromException(new Exception("Application failed"));
|
||||||
|
connection.TransportTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
throw new Exception("Transport failed");
|
// Wait for the application to end
|
||||||
}
|
var result = await connection.Application.Input.ReadAsync();
|
||||||
});
|
connection.Application.Input.AdvanceTo(result.Buffer.End);
|
||||||
|
|
||||||
}
|
if (transportFaulted)
|
||||||
else if (transportFaulted)
|
{
|
||||||
{
|
throw new Exception("Transport failed");
|
||||||
// If the transport is faulted then we want to make sure the transport task only completes after
|
}
|
||||||
// the application completes
|
});
|
||||||
connection.TransportTask = Task.FromException(new Exception("Application failed"));
|
|
||||||
connection.ApplicationTask = Task.Run(async () =>
|
}
|
||||||
|
else if (transportFaulted)
|
||||||
{
|
{
|
||||||
// Wait for the application to end
|
// If the transport is faulted then we want to make sure the transport task only completes after
|
||||||
var result = await connection.Transport.Input.ReadAsync();
|
// the application completes
|
||||||
connection.Transport.Input.AdvanceTo(result.Buffer.End);
|
connection.TransportTask = Task.FromException(new Exception("Application failed"));
|
||||||
});
|
connection.ApplicationTask = Task.Run(async () =>
|
||||||
}
|
{
|
||||||
else
|
// Wait for the application to end
|
||||||
{
|
var result = await connection.Transport.Input.ReadAsync();
|
||||||
connection.ApplicationTask = Task.CompletedTask;
|
connection.Transport.Input.AdvanceTo(result.Buffer.End);
|
||||||
connection.TransportTask = Task.CompletedTask;
|
});
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connection.ApplicationTask = Task.CompletedTask;
|
||||||
|
connection.TransportTask = Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
var applicationInputTcs = new TaskCompletionSource<object>();
|
var applicationInputTcs = new TaskCompletionSource<object>();
|
||||||
var applicationOutputTcs = new TaskCompletionSource<object>();
|
var applicationOutputTcs = new TaskCompletionSource<object>();
|
||||||
var transportInputTcs = new TaskCompletionSource<object>();
|
var transportInputTcs = new TaskCompletionSource<object>();
|
||||||
var transportOutputTcs = new TaskCompletionSource<object>();
|
var transportOutputTcs = new TaskCompletionSource<object>();
|
||||||
|
|
||||||
connection.Transport.Input.OnWriterCompleted((_, __) => transportInputTcs.TrySetResult(null), null);
|
connection.Transport.Input.OnWriterCompleted((_, __) => transportInputTcs.TrySetResult(null), null);
|
||||||
connection.Transport.Output.OnReaderCompleted((_, __) => transportOutputTcs.TrySetResult(null), null);
|
connection.Transport.Output.OnReaderCompleted((_, __) => transportOutputTcs.TrySetResult(null), null);
|
||||||
connection.Application.Input.OnWriterCompleted((_, __) => applicationInputTcs.TrySetResult(null), null);
|
connection.Application.Input.OnWriterCompleted((_, __) => applicationInputTcs.TrySetResult(null), null);
|
||||||
connection.Application.Output.OnReaderCompleted((_, __) => applicationOutputTcs.TrySetResult(null), null);
|
connection.Application.Output.OnReaderCompleted((_, __) => applicationOutputTcs.TrySetResult(null), null);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await connection.DisposeAsync(closeGracefully).OrTimeout();
|
await connection.DisposeAsync(closeGracefully).OrTimeout();
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (!(ex is TimeoutException))
|
||||||
|
{
|
||||||
|
// Ignore the exception that bubbles out of the failing task
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.WhenAll(applicationInputTcs.Task, applicationOutputTcs.Task, transportInputTcs.Task, transportOutputTcs.Task).OrTimeout();
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!(ex is TimeoutException))
|
|
||||||
{
|
|
||||||
// Ignore the exception that bubbles out of the failing task
|
|
||||||
}
|
|
||||||
|
|
||||||
await Task.WhenAll(applicationInputTcs.Task, applicationOutputTcs.Task, transportInputTcs.Task, transportOutputTcs.Task).OrTimeout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void NewConnectionsCanBeRetrieved()
|
public void NewConnectionsCanBeRetrieved()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection();
|
{
|
||||||
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection();
|
||||||
|
|
||||||
Assert.NotNull(connection.ConnectionId);
|
Assert.NotNull(connection.ConnectionId);
|
||||||
|
|
||||||
Assert.True(connectionManager.TryGetConnection(connection.ConnectionId, out var newConnection));
|
Assert.True(connectionManager.TryGetConnection(connection.ConnectionId, out var newConnection));
|
||||||
Assert.Same(newConnection, connection);
|
Assert.Same(newConnection, connection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void AddNewConnection()
|
public void AddNewConnection()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
{
|
||||||
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
|
||||||
var transport = connection.Transport;
|
var transport = connection.Transport;
|
||||||
|
|
||||||
Assert.NotNull(connection.ConnectionId);
|
Assert.NotNull(connection.ConnectionId);
|
||||||
Assert.NotNull(transport);
|
Assert.NotNull(transport);
|
||||||
|
|
||||||
Assert.True(connectionManager.TryGetConnection(connection.ConnectionId, out var newConnection));
|
Assert.True(connectionManager.TryGetConnection(connection.ConnectionId, out var newConnection));
|
||||||
Assert.Same(newConnection, connection);
|
Assert.Same(newConnection, connection);
|
||||||
Assert.Same(transport, newConnection.Transport);
|
Assert.Same(transport, newConnection.Transport);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void RemoveConnection()
|
public void RemoveConnection()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
{
|
||||||
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
|
||||||
var transport = connection.Transport;
|
var transport = connection.Transport;
|
||||||
|
|
||||||
Assert.NotNull(connection.ConnectionId);
|
Assert.NotNull(connection.ConnectionId);
|
||||||
Assert.NotNull(transport);
|
Assert.NotNull(transport);
|
||||||
|
|
||||||
Assert.True(connectionManager.TryGetConnection(connection.ConnectionId, out var newConnection));
|
Assert.True(connectionManager.TryGetConnection(connection.ConnectionId, out var newConnection));
|
||||||
Assert.Same(newConnection, connection);
|
Assert.Same(newConnection, connection);
|
||||||
Assert.Same(transport, newConnection.Transport);
|
Assert.Same(transport, newConnection.Transport);
|
||||||
|
|
||||||
connectionManager.RemoveConnection(connection.ConnectionId);
|
connectionManager.RemoveConnection(connection.ConnectionId);
|
||||||
Assert.False(connectionManager.TryGetConnection(connection.ConnectionId, out newConnection));
|
Assert.False(connectionManager.TryGetConnection(connection.ConnectionId, out newConnection));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task CloseConnectionsEndsAllPendingConnections()
|
public async Task CloseConnectionsEndsAllPendingConnections()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
|
||||||
|
|
||||||
connection.ApplicationTask = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
var result = await connection.Transport.Input.ReadAsync();
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
|
||||||
try
|
connection.ApplicationTask = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Assert.True(result.IsCompleted);
|
var result = await connection.Transport.Input.ReadAsync();
|
||||||
|
|
||||||
// We should be able to write
|
try
|
||||||
await connection.Transport.Output.WriteAsync(new byte[] { 1 });
|
{
|
||||||
}
|
Assert.True(result.IsCompleted);
|
||||||
finally
|
|
||||||
{
|
|
||||||
connection.Transport.Input.AdvanceTo(result.Buffer.End);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connection.TransportTask = Task.Run(async () =>
|
// We should be able to write
|
||||||
{
|
await connection.Transport.Output.WriteAsync(new byte[] { 1 });
|
||||||
var result = await connection.Application.Input.ReadAsync();
|
}
|
||||||
Assert.Equal(new byte[] { 1 }, result.Buffer.ToArray());
|
finally
|
||||||
connection.Application.Input.AdvanceTo(result.Buffer.End);
|
{
|
||||||
|
connection.Transport.Input.AdvanceTo(result.Buffer.End);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
result = await connection.Application.Input.ReadAsync();
|
connection.TransportTask = Task.Run(async () =>
|
||||||
try
|
|
||||||
{
|
|
||||||
Assert.True(result.IsCompleted);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
{
|
||||||
|
var result = await connection.Application.Input.ReadAsync();
|
||||||
|
Assert.Equal(new byte[] { 1 }, result.Buffer.ToArray());
|
||||||
connection.Application.Input.AdvanceTo(result.Buffer.End);
|
connection.Application.Input.AdvanceTo(result.Buffer.End);
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
connectionManager.CloseConnections();
|
result = await connection.Application.Input.ReadAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Assert.True(result.IsCompleted);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
connection.Application.Input.AdvanceTo(result.Buffer.End);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
await connection.DisposeAsync();
|
connectionManager.CloseConnections();
|
||||||
|
|
||||||
|
await connection.DisposeAsync();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DisposingConnectionMultipleTimesWaitsOnConnectionClose()
|
public async Task DisposingConnectionMultipleTimesWaitsOnConnectionClose()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
{
|
||||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
connection.ApplicationTask = tcs.Task;
|
connection.ApplicationTask = tcs.Task;
|
||||||
connection.TransportTask = tcs.Task;
|
connection.TransportTask = tcs.Task;
|
||||||
|
|
||||||
var firstTask = connection.DisposeAsync();
|
var firstTask = connection.DisposeAsync();
|
||||||
var secondTask = connection.DisposeAsync();
|
var secondTask = connection.DisposeAsync();
|
||||||
Assert.False(firstTask.IsCompleted);
|
Assert.False(firstTask.IsCompleted);
|
||||||
Assert.False(secondTask.IsCompleted);
|
Assert.False(secondTask.IsCompleted);
|
||||||
|
|
||||||
tcs.TrySetResult(null);
|
tcs.TrySetResult(null);
|
||||||
|
|
||||||
await Task.WhenAll(firstTask, secondTask).OrTimeout();
|
await Task.WhenAll(firstTask, secondTask).OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DisposingConnectionMultipleGetsExceptionFromTransportOrApp()
|
public async Task DisposingConnectionMultipleGetsExceptionFromTransportOrApp()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
{
|
||||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
connection.ApplicationTask = tcs.Task;
|
connection.ApplicationTask = tcs.Task;
|
||||||
connection.TransportTask = tcs.Task;
|
connection.TransportTask = tcs.Task;
|
||||||
|
|
||||||
var firstTask = connection.DisposeAsync();
|
var firstTask = connection.DisposeAsync();
|
||||||
var secondTask = connection.DisposeAsync();
|
var secondTask = connection.DisposeAsync();
|
||||||
Assert.False(firstTask.IsCompleted);
|
Assert.False(firstTask.IsCompleted);
|
||||||
Assert.False(secondTask.IsCompleted);
|
Assert.False(secondTask.IsCompleted);
|
||||||
|
|
||||||
tcs.TrySetException(new InvalidOperationException("Error"));
|
tcs.TrySetException(new InvalidOperationException("Error"));
|
||||||
|
|
||||||
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await firstTask.OrTimeout());
|
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await firstTask.OrTimeout());
|
||||||
Assert.Equal("Error", exception.Message);
|
Assert.Equal("Error", exception.Message);
|
||||||
|
|
||||||
exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await secondTask.OrTimeout());
|
exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await secondTask.OrTimeout());
|
||||||
Assert.Equal("Error", exception.Message);
|
Assert.Equal("Error", exception.Message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DisposingConnectionMultipleGetsCancellation()
|
public async Task DisposingConnectionMultipleGetsCancellation()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
{
|
||||||
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
|
||||||
connection.ApplicationTask = tcs.Task;
|
connection.ApplicationTask = tcs.Task;
|
||||||
connection.TransportTask = tcs.Task;
|
connection.TransportTask = tcs.Task;
|
||||||
|
|
||||||
var firstTask = connection.DisposeAsync();
|
var firstTask = connection.DisposeAsync();
|
||||||
var secondTask = connection.DisposeAsync();
|
var secondTask = connection.DisposeAsync();
|
||||||
Assert.False(firstTask.IsCompleted);
|
Assert.False(firstTask.IsCompleted);
|
||||||
Assert.False(secondTask.IsCompleted);
|
Assert.False(secondTask.IsCompleted);
|
||||||
|
|
||||||
tcs.TrySetCanceled();
|
tcs.TrySetCanceled();
|
||||||
|
|
||||||
await Assert.ThrowsAsync<TaskCanceledException>(async () => await firstTask.OrTimeout());
|
await Assert.ThrowsAsync<TaskCanceledException>(async () => await firstTask.OrTimeout());
|
||||||
await Assert.ThrowsAsync<TaskCanceledException>(async () => await secondTask.OrTimeout());
|
await Assert.ThrowsAsync<TaskCanceledException>(async () => await secondTask.OrTimeout());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DisposeInactiveConnection()
|
public async Task DisposeInactiveConnection()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
{
|
||||||
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
|
||||||
Assert.NotNull(connection.ConnectionId);
|
Assert.NotNull(connection.ConnectionId);
|
||||||
Assert.NotNull(connection.Transport);
|
Assert.NotNull(connection.Transport);
|
||||||
|
|
||||||
await connection.DisposeAsync();
|
await connection.DisposeAsync();
|
||||||
Assert.Equal(HttpConnectionStatus.Disposed, connection.Status);
|
Assert.Equal(HttpConnectionStatus.Disposed, connection.Status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task DisposeInactiveConnectionWithNoPipes()
|
public async Task DisposeInactiveConnectionWithNoPipes()
|
||||||
{
|
{
|
||||||
var connectionManager = CreateConnectionManager();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = connectionManager.CreateConnection();
|
{
|
||||||
|
var connectionManager = CreateConnectionManager(loggerFactory);
|
||||||
|
var connection = connectionManager.CreateConnection();
|
||||||
|
|
||||||
Assert.NotNull(connection.ConnectionId);
|
Assert.NotNull(connection.ConnectionId);
|
||||||
Assert.NotNull(connection.Transport);
|
Assert.NotNull(connection.Transport);
|
||||||
Assert.NotNull(connection.Application);
|
Assert.NotNull(connection.Application);
|
||||||
|
|
||||||
await connection.DisposeAsync();
|
await connection.DisposeAsync();
|
||||||
Assert.Equal(HttpConnectionStatus.Disposed, connection.Status);
|
Assert.Equal(HttpConnectionStatus.Disposed, connection.Status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ApplicationLifetimeIsHookedUp()
|
public async Task ApplicationLifetimeIsHookedUp()
|
||||||
{
|
{
|
||||||
var appLifetime = new TestApplicationLifetime();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connectionManager = CreateConnectionManager(appLifetime);
|
|
||||||
var tcs = new TaskCompletionSource<object>();
|
|
||||||
|
|
||||||
appLifetime.Start();
|
|
||||||
|
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
|
||||||
|
|
||||||
connection.Application.Output.OnReaderCompleted((error, state) =>
|
|
||||||
{
|
{
|
||||||
tcs.TrySetResult(null);
|
var appLifetime = new TestApplicationLifetime();
|
||||||
},
|
var connectionManager = CreateConnectionManager(loggerFactory, appLifetime);
|
||||||
null);
|
var tcs = new TaskCompletionSource<object>();
|
||||||
|
|
||||||
appLifetime.StopApplication();
|
appLifetime.Start();
|
||||||
|
|
||||||
// Connection should be disposed so this should complete immediately
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
await tcs.Task.OrTimeout();
|
|
||||||
|
connection.Application.Output.OnReaderCompleted((error, state) =>
|
||||||
|
{
|
||||||
|
tcs.TrySetResult(null);
|
||||||
|
},
|
||||||
|
null);
|
||||||
|
|
||||||
|
appLifetime.StopApplication();
|
||||||
|
|
||||||
|
// Connection should be disposed so this should complete immediately
|
||||||
|
await tcs.Task.OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task ApplicationLifetimeCanStartBeforeHttpConnectionManagerInitialized()
|
public async Task ApplicationLifetimeCanStartBeforeHttpConnectionManagerInitialized()
|
||||||
{
|
{
|
||||||
var appLifetime = new TestApplicationLifetime();
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
appLifetime.Start();
|
|
||||||
|
|
||||||
var connectionManager = CreateConnectionManager(appLifetime);
|
|
||||||
var tcs = new TaskCompletionSource<object>();
|
|
||||||
|
|
||||||
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
|
||||||
|
|
||||||
connection.Application.Output.OnReaderCompleted((error, state) =>
|
|
||||||
{
|
{
|
||||||
tcs.TrySetResult(null);
|
var appLifetime = new TestApplicationLifetime();
|
||||||
},
|
appLifetime.Start();
|
||||||
null);
|
|
||||||
|
|
||||||
appLifetime.StopApplication();
|
var connectionManager = CreateConnectionManager(loggerFactory, appLifetime);
|
||||||
|
var tcs = new TaskCompletionSource<object>();
|
||||||
|
|
||||||
// Connection should be disposed so this should complete immediately
|
var connection = connectionManager.CreateConnection(PipeOptions.Default, PipeOptions.Default);
|
||||||
await tcs.Task.OrTimeout();
|
|
||||||
|
connection.Application.Output.OnReaderCompleted((error, state) =>
|
||||||
|
{
|
||||||
|
tcs.TrySetResult(null);
|
||||||
|
},
|
||||||
|
null);
|
||||||
|
|
||||||
|
appLifetime.StopApplication();
|
||||||
|
|
||||||
|
// Connection should be disposed so this should complete immediately
|
||||||
|
await tcs.Task.OrTimeout();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static HttpConnectionManager CreateConnectionManager(IApplicationLifetime lifetime = null)
|
private static HttpConnectionManager CreateConnectionManager(ILoggerFactory loggerFactory, IApplicationLifetime lifetime = null)
|
||||||
{
|
{
|
||||||
lifetime = lifetime ?? new EmptyApplicationLifetime();
|
lifetime = lifetime ?? new EmptyApplicationLifetime();
|
||||||
return new HttpConnectionManager(new LoggerFactory(), lifetime);
|
return new HttpConnectionManager(loggerFactory, lifetime);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|
|
||||||
|
|
@ -9,92 +9,111 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
using Microsoft.AspNetCore.Http.Connections.Internal.Transports;
|
using Microsoft.AspNetCore.Http.Connections.Internal.Transports;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Tests;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
{
|
{
|
||||||
public class LongPollingTests
|
public class LongPollingTests : VerifiableLoggedTest
|
||||||
{
|
{
|
||||||
|
public LongPollingTests(ITestOutputHelper output)
|
||||||
|
: base(output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Set204StatusCodeWhenChannelComplete()
|
public async Task Set204StatusCodeWhenChannelComplete()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
|
||||||
var context = new DefaultHttpContext();
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var poll = new LongPollingTransport(CancellationToken.None, connection.Application.Input, loggerFactory: new LoggerFactory());
|
var poll = new LongPollingTransport(CancellationToken.None, connection.Application.Input, loggerFactory);
|
||||||
|
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
|
|
||||||
await poll.ProcessRequestAsync(context, context.RequestAborted).OrTimeout();
|
await poll.ProcessRequestAsync(context, context.RequestAborted).OrTimeout();
|
||||||
|
|
||||||
Assert.Equal(204, context.Response.StatusCode);
|
Assert.Equal(204, context.Response.StatusCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Set200StatusCodeWhenTimeoutTokenFires()
|
public async Task Set200StatusCodeWhenTimeoutTokenFires()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
|
||||||
var context = new DefaultHttpContext();
|
|
||||||
|
|
||||||
var timeoutToken = new CancellationToken(true);
|
|
||||||
var poll = new LongPollingTransport(timeoutToken, connection.Application.Input, loggerFactory: new LoggerFactory());
|
|
||||||
|
|
||||||
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutToken, context.RequestAborted))
|
|
||||||
{
|
{
|
||||||
await poll.ProcessRequestAsync(context, cts.Token).OrTimeout();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
Assert.Equal(0, context.Response.ContentLength);
|
var timeoutToken = new CancellationToken(true);
|
||||||
Assert.Equal(200, context.Response.StatusCode);
|
var poll = new LongPollingTransport(timeoutToken, connection.Application.Input, loggerFactory);
|
||||||
|
|
||||||
|
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(timeoutToken, context.RequestAborted))
|
||||||
|
{
|
||||||
|
await poll.ProcessRequestAsync(context, cts.Token).OrTimeout();
|
||||||
|
|
||||||
|
Assert.Equal(0, context.Response.ContentLength);
|
||||||
|
Assert.Equal(200, context.Response.StatusCode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task FrameSentAsSingleResponse()
|
public async Task FrameSentAsSingleResponse()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var poll = new LongPollingTransport(CancellationToken.None, connection.Application.Input, loggerFactory: new LoggerFactory());
|
var poll = new LongPollingTransport(CancellationToken.None, connection.Application.Input, loggerFactory);
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
context.Response.Body = ms;
|
context.Response.Body = ms;
|
||||||
|
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello World"));
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
|
|
||||||
await poll.ProcessRequestAsync(context, context.RequestAborted).OrTimeout();
|
await poll.ProcessRequestAsync(context, context.RequestAborted).OrTimeout();
|
||||||
|
|
||||||
Assert.Equal(200, context.Response.StatusCode);
|
Assert.Equal(200, context.Response.StatusCode);
|
||||||
Assert.Equal("Hello World", Encoding.UTF8.GetString(ms.ToArray()));
|
Assert.Equal("Hello World", Encoding.UTF8.GetString(ms.ToArray()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task MultipleFramesSentAsSingleResponse()
|
public async Task MultipleFramesSentAsSingleResponse()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var poll = new LongPollingTransport(CancellationToken.None, connection.Application.Input, loggerFactory: new LoggerFactory());
|
var poll = new LongPollingTransport(CancellationToken.None, connection.Application.Input, loggerFactory);
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
context.Response.Body = ms;
|
context.Response.Body = ms;
|
||||||
|
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello"));
|
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("Hello"));
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes(" "));
|
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes(" "));
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("World"));
|
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes("World"));
|
||||||
|
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
|
|
||||||
await poll.ProcessRequestAsync(context, context.RequestAborted).OrTimeout();
|
await poll.ProcessRequestAsync(context, context.RequestAborted).OrTimeout();
|
||||||
|
|
||||||
Assert.Equal(200, context.Response.StatusCode);
|
Assert.Equal(200, context.Response.StatusCode);
|
||||||
|
|
||||||
var payload = ms.ToArray();
|
var payload = ms.ToArray();
|
||||||
Assert.Equal("Hello World", Encoding.UTF8.GetString(payload));
|
Assert.Equal("Hello World", Encoding.UTF8.GetString(payload));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
|
||||||
|
|
@ -11,85 +11,104 @@ using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Http.Connections.Internal.Transports;
|
using Microsoft.AspNetCore.Http.Connections.Internal.Transports;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
using Microsoft.AspNetCore.SignalR.Tests;
|
||||||
|
using Xunit.Abstractions;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
{
|
{
|
||||||
public class ServerSentEventsTests
|
public class ServerSentEventsTests : VerifiableLoggedTest
|
||||||
{
|
{
|
||||||
|
public ServerSentEventsTests(ITestOutputHelper output)
|
||||||
|
: base(output)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SSESetsContentType()
|
public async Task SSESetsContentType()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory: new LoggerFactory());
|
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory);
|
||||||
|
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
|
|
||||||
await sse.ProcessRequestAsync(context, context.RequestAborted);
|
await sse.ProcessRequestAsync(context, context.RequestAborted);
|
||||||
|
|
||||||
Assert.Equal("text/event-stream", context.Response.ContentType);
|
Assert.Equal("text/event-stream", context.Response.ContentType);
|
||||||
Assert.Equal("no-cache", context.Response.Headers["Cache-Control"]);
|
Assert.Equal("no-cache", context.Response.Headers["Cache-Control"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SSETurnsResponseBufferingOff()
|
public async Task SSETurnsResponseBufferingOff()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var feature = new HttpBufferingFeature();
|
var feature = new HttpBufferingFeature();
|
||||||
context.Features.Set<IHttpBufferingFeature>(feature);
|
context.Features.Set<IHttpBufferingFeature>(feature);
|
||||||
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: connection.ConnectionId, loggerFactory: new LoggerFactory());
|
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: connection.ConnectionId, loggerFactory);
|
||||||
|
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
|
|
||||||
await sse.ProcessRequestAsync(context, context.RequestAborted);
|
await sse.ProcessRequestAsync(context, context.RequestAborted);
|
||||||
|
|
||||||
Assert.True(feature.ResponseBufferingDisabled);
|
Assert.True(feature.ResponseBufferingDisabled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SSEWritesMessages()
|
public async Task SSEWritesMessages()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, new PipeOptions(readerScheduler: PipeScheduler.Inline));
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, new PipeOptions(readerScheduler: PipeScheduler.Inline));
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
context.Response.Body = ms;
|
context.Response.Body = ms;
|
||||||
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory: new LoggerFactory());
|
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory);
|
||||||
|
|
||||||
var task = sse.ProcessRequestAsync(context, context.RequestAborted);
|
var task = sse.ProcessRequestAsync(context, context.RequestAborted);
|
||||||
|
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes("Hello"));
|
await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes("Hello"));
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
await task.OrTimeout();
|
await task.OrTimeout();
|
||||||
Assert.Equal(":\r\ndata: Hello\r\n\r\n", Encoding.ASCII.GetString(ms.ToArray()));
|
Assert.Equal(":\r\ndata: Hello\r\n\r\n", Encoding.ASCII.GetString(ms.ToArray()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task SSEWritesVeryLargeMessages()
|
public async Task SSEWritesVeryLargeMessages()
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, new PipeOptions(readerScheduler: PipeScheduler.Inline));
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, new PipeOptions(readerScheduler: PipeScheduler.Inline));
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
context.Response.Body = ms;
|
context.Response.Body = ms;
|
||||||
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory: new LoggerFactory());
|
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory);
|
||||||
|
|
||||||
var task = sse.ProcessRequestAsync(context, context.RequestAborted);
|
var task = sse.ProcessRequestAsync(context, context.RequestAborted);
|
||||||
|
|
||||||
string hText = new string('H', 60000);
|
string hText = new string('H', 60000);
|
||||||
string wText = new string('W', 60000);
|
string wText = new string('W', 60000);
|
||||||
|
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes(hText + wText));
|
await connection.Transport.Output.WriteAsync(Encoding.ASCII.GetBytes(hText + wText));
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
await task.OrTimeout();
|
await task.OrTimeout();
|
||||||
Assert.Equal(":\r\ndata: " + hText + wText + "\r\n\r\n", Encoding.ASCII.GetString(ms.ToArray()));
|
Assert.Equal(":\r\ndata: " + hText + wText + "\r\n\r\n", Encoding.ASCII.GetString(ms.ToArray()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -98,21 +117,24 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
[InlineData("Hello\r\nWorld", ":\r\ndata: Hello\r\ndata: World\r\n\r\n")]
|
[InlineData("Hello\r\nWorld", ":\r\ndata: Hello\r\ndata: World\r\n\r\n")]
|
||||||
public async Task SSEAddsAppropriateFraming(string message, string expected)
|
public async Task SSEAddsAppropriateFraming(string message, string expected)
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
using (StartVerifiableLog(out var loggerFactory))
|
||||||
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
{
|
||||||
var context = new DefaultHttpContext();
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
|
var connection = new DefaultConnectionContext("foo", pair.Transport, pair.Application);
|
||||||
|
var context = new DefaultHttpContext();
|
||||||
|
|
||||||
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory: new LoggerFactory());
|
var sse = new ServerSentEventsTransport(connection.Application.Input, connectionId: string.Empty, loggerFactory);
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
context.Response.Body = ms;
|
context.Response.Body = ms;
|
||||||
|
|
||||||
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes(message));
|
await connection.Transport.Output.WriteAsync(Encoding.UTF8.GetBytes(message));
|
||||||
|
|
||||||
connection.Transport.Output.Complete();
|
connection.Transport.Output.Complete();
|
||||||
|
|
||||||
await sse.ProcessRequestAsync(context, context.RequestAborted);
|
await sse.ProcessRequestAsync(context, context.RequestAborted);
|
||||||
|
|
||||||
Assert.Equal(expected, Encoding.UTF8.GetString(ms.ToArray()));
|
Assert.Equal(expected, Encoding.UTF8.GetString(ms.ToArray()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class HttpBufferingFeature : IHttpBufferingFeature
|
private class HttpBufferingFeature : IHttpBufferingFeature
|
||||||
|
|
|
||||||
|
|
@ -38,11 +38,11 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
|
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
|
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application, loggerFactory.CreateLogger("HttpConnectionContext1"));
|
||||||
|
|
||||||
using (var feature = new TestWebSocketConnectionFeature())
|
using (var feature = new TestWebSocketConnectionFeature())
|
||||||
{
|
{
|
||||||
var connectionContext = new HttpConnectionContext(string.Empty, null, null);
|
var connectionContext = new HttpConnectionContext(string.Empty, null, null, loggerFactory.CreateLogger("HttpConnectionContext2"));
|
||||||
var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);
|
var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);
|
||||||
|
|
||||||
// Give the server socket to the transport and run it
|
// Give the server socket to the transport and run it
|
||||||
|
|
@ -86,11 +86,11 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
|
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
|
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application, loggerFactory.CreateLogger("HttpConnectionContext1"));
|
||||||
|
|
||||||
using (var feature = new TestWebSocketConnectionFeature())
|
using (var feature = new TestWebSocketConnectionFeature())
|
||||||
{
|
{
|
||||||
var connectionContext = new HttpConnectionContext(string.Empty, null, null);
|
var connectionContext = new HttpConnectionContext(string.Empty, null, null, loggerFactory.CreateLogger("HttpConnectionContext2"));
|
||||||
connectionContext.ActiveFormat = transferFormat;
|
connectionContext.ActiveFormat = transferFormat;
|
||||||
var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);
|
var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);
|
||||||
|
|
||||||
|
|
@ -123,7 +123,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
|
using (StartVerifiableLog(out var loggerFactory, LogLevel.Debug))
|
||||||
{
|
{
|
||||||
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
var pair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);
|
||||||
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application);
|
var connection = new HttpConnectionContext("foo", pair.Transport, pair.Application, loggerFactory.CreateLogger("HttpConnectionContext1"));
|
||||||
|
|
||||||
using (var feature = new TestWebSocketConnectionFeature())
|
using (var feature = new TestWebSocketConnectionFeature())
|
||||||
{
|
{
|
||||||
|
|
@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Http.Connections.Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var connectionContext = new HttpConnectionContext(string.Empty, null, null);
|
var connectionContext = new HttpConnectionContext(string.Empty, null, null, loggerFactory.CreateLogger("HttpConnectionContext2"));
|
||||||
var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);
|
var ws = new WebSocketsTransport(new WebSocketOptions(), connection.Application, connectionContext, loggerFactory);
|
||||||
|
|
||||||
// Give the server socket to the transport and run it
|
// Give the server socket to the transport and run it
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue