Fix flaky test and improve TestServer (#1859)

This commit is contained in:
Stephen Halter 2017-05-24 15:45:54 -07:00 committed by GitHub
parent 197eb43d8a
commit 6c0af445e5
8 changed files with 152 additions and 163 deletions

View File

@ -5,11 +5,9 @@ using System;
using System.Diagnostics; using System.Diagnostics;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Moq; using Moq;
using Xunit; using Xunit;
@ -17,7 +15,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
public class FrameConnectionManagerTests public class FrameConnectionManagerTests
{ {
private const int _applicationNeverCompletedId = 23;
[ConditionalFact] [ConditionalFact]
[NoDebuggerCondition] [NoDebuggerCondition]
@ -31,45 +28,23 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
var logWh = new SemaphoreSlim(0); var logWh = new SemaphoreSlim(0);
var appStartedWh = new SemaphoreSlim(0); var appStartedWh = new SemaphoreSlim(0);
var mockLogger = new Mock<ILogger>(); var mockTrace = new Mock<IKestrelTrace>();
mockLogger mockTrace
.Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>())) .Setup(trace => trace.ApplicationNeverCompleted(It.IsAny<string>()))
.Returns(true);
mockLogger
.Setup(logger => logger.Log(LogLevel.Critical, _applicationNeverCompletedId, It.IsAny<object>(), null,
It.IsAny<Func<object, Exception, string>>()))
.Callback(() => .Callback(() =>
{ {
logWh.Release(); logWh.Release();
}); });
var mockLoggerFactory = new Mock<ILoggerFactory>(); using (var server = new TestServer(context =>
mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel"))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsNotIn("Microsoft.AspNetCore.Server.Kestrel")))
.Returns(Mock.Of<ILogger>());
var builder = new WebHostBuilder()
.UseLoggerFactory(mockLoggerFactory.Object)
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app =>
{ {
app.Run(context => appStartedWh.Release();
{ var tcs = new TaskCompletionSource<object>();
appStartedWh.Release(); return tcs.Task;
var tcs = new TaskCompletionSource<object>(); },
return tcs.Task; new TestServiceContext(new KestrelTestLoggerFactory(), mockTrace.Object)))
});
});
using (var host = builder.Build())
{ {
host.Start(); using (var connection = server.CreateConnection())
using (var connection = new TestConnection(host.GetPort()))
{ {
await connection.Send("GET / HTTP/1.1", await connection.Send("GET / HTTP/1.1",
"Host:", "Host:",

View File

@ -19,7 +19,6 @@ using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit; using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
@ -34,7 +33,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public class RequestTests public class RequestTests
{ {
private const int _connectionStartedEventId = 1; private const int _connectionStartedEventId = 1;
private const int _connectionKeepAliveEventId = 9;
private const int _connectionResetEventId = 19; private const int _connectionResetEventId = 19;
private const int _semaphoreWaitTimeout = 2500; private const int _semaphoreWaitTimeout = 2500;
@ -257,54 +255,48 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{ {
var connectionStarted = new SemaphoreSlim(0); var connectionStarted = new SemaphoreSlim(0);
var connectionReset = new SemaphoreSlim(0); var connectionReset = new SemaphoreSlim(0);
var loggedHigherThanDebug = false;
var mockLogger = new Mock<ILogger>(); var mockLogger = new Mock<ILogger>();
mockLogger mockLogger
.Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>())) .Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>()))
.Returns(true); .Returns(true);
mockLogger mockLogger
.Setup(logger => logger.Log(LogLevel.Debug, _connectionStartedEventId, It.IsAny<object>(), null, It.IsAny<Func<object, Exception, string>>())) .Setup(logger => logger.Log(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<object>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()))
.Callback(() => .Callback<LogLevel, EventId, object, Exception, Func<object, Exception, string>>((logLevel, eventId, state, exception, formatter) =>
{ {
connectionStarted.Release(); if (eventId.Id == _connectionStartedEventId)
}); {
mockLogger connectionStarted.Release();
.Setup(logger => logger.Log(LogLevel.Debug, _connectionResetEventId, It.IsAny<object>(), null, It.IsAny<Func<object, Exception, string>>())) }
.Callback(() => else if (eventId.Id == _connectionResetEventId)
{ {
connectionReset.Release(); connectionReset.Release();
}
if (logLevel > LogLevel.Debug)
{
loggedHigherThanDebug = true;
}
}); });
var mockLoggerFactory = new Mock<ILoggerFactory>(); var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel")) .Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsNotIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv")))
.Returns(Mock.Of<ILogger>()); .Returns(Mock.Of<ILogger>());
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv")))
.Returns(mockLogger.Object);
var builder = new WebHostBuilder() using (var server = new TestServer(context => TaskCache.CompletedTask, new TestServiceContext(mockLoggerFactory.Object)))
.UseLoggerFactory(mockLoggerFactory.Object)
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(context => TaskCache.CompletedTask));
using (var host = builder.Build())
{ {
host.Start(); using (var connection = server.CreateConnection())
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{ {
socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort()));
// Wait until connection is established // Wait until connection is established
Assert.True(await connectionStarted.WaitAsync(TimeSpan.FromSeconds(10))); Assert.True(await connectionStarted.WaitAsync(TimeSpan.FromSeconds(10)));
// Force a reset // Force a reset
socket.LingerState = new LingerOption(true, 0); connection.Socket.LingerState = new LingerOption(true, 0);
} }
// If the reset is correctly logged as Debug, the wait below should complete shortly. // If the reset is correctly logged as Debug, the wait below should complete shortly.
@ -313,63 +305,64 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
// and therefore not logged. // and therefore not logged.
Assert.True(await connectionReset.WaitAsync(TimeSpan.FromSeconds(10))); Assert.True(await connectionReset.WaitAsync(TimeSpan.FromSeconds(10)));
} }
Assert.False(loggedHigherThanDebug);
} }
[Fact(Skip= "https://github.com/aspnet/KestrelHttpServer/issues/1835")] [Fact]
public async Task ConnectionResetBetweenRequestsIsLoggedAsDebug() public async Task ConnectionResetBetweenRequestsIsLoggedAsDebug()
{ {
var requestDone = new SemaphoreSlim(0);
var connectionReset = new SemaphoreSlim(0); var connectionReset = new SemaphoreSlim(0);
var loggedHigherThanDebug = false;
var mockLogger = new Mock<ILogger>(); var mockLogger = new Mock<ILogger>();
mockLogger mockLogger
.Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>())) .Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>()))
.Returns(true); .Returns(true);
mockLogger mockLogger
.Setup(logger => logger.Log(LogLevel.Debug, _connectionKeepAliveEventId, It.IsAny<object>(), null, It.IsAny<Func<object, Exception, string>>())) .Setup(logger => logger.Log(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<object>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()))
.Callback(() => .Callback<LogLevel, EventId, object, Exception, Func<object, Exception, string>>((logLevel, eventId, state, exception, formatter) =>
{ {
requestDone.Release(); if (eventId.Id == _connectionResetEventId)
}); {
mockLogger connectionReset.Release();
.Setup(logger => logger.Log(LogLevel.Debug, _connectionResetEventId, It.IsAny<object>(), null, It.IsAny<Func<object, Exception, string>>())) }
.Callback(() =>
{ if (logLevel > LogLevel.Debug)
connectionReset.Release(); {
loggedHigherThanDebug = true;
}
}); });
var mockLoggerFactory = new Mock<ILoggerFactory>(); var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel")) .Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsNotIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv")))
.Returns(Mock.Of<ILogger>()); .Returns(Mock.Of<ILogger>());
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv")))
.Returns(mockLogger.Object);
using (var server = new TestServer(context => TaskCache.CompletedTask, new TestServiceContext(mockLoggerFactory.Object)))
var builder = new WebHostBuilder()
.UseLoggerFactory(mockLoggerFactory.Object)
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(context => TaskCache.CompletedTask));
using (var host = builder.Build())
{ {
host.Start(); using (var connection = server.CreateConnection())
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{ {
socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort())); await connection.Send(
socket.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n")); "GET / HTTP/1.1",
"Host:",
"",
"");
// Wait until request is done being processed // Make sure the response is fully received, so a write failure (e.g. EPIPE) doesn't cause
Assert.True(await requestDone.WaitAsync(TimeSpan.FromSeconds(10))); // a more critical log message.
await connection.Receive(
"HTTP/1.1 200 OK",
$"Date: {server.Context.DateHeaderValue}",
"Content-Length: 0",
"",
"");
// Force a reset // Force a reset
socket.LingerState = new LingerOption(true, 0); connection.Socket.LingerState = new LingerOption(true, 0);
} }
// If the reset is correctly logged as Debug, the wait below should complete shortly. // If the reset is correctly logged as Debug, the wait below should complete shortly.
@ -378,61 +371,64 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
// and therefore not logged. // and therefore not logged.
Assert.True(await connectionReset.WaitAsync(TimeSpan.FromSeconds(10))); Assert.True(await connectionReset.WaitAsync(TimeSpan.FromSeconds(10)));
} }
Assert.False(loggedHigherThanDebug);
} }
[Fact] [Fact]
public async Task ConnectionResetMidRequestIsLoggedAsDebug() public async Task ConnectionResetMidRequestIsLoggedAsDebug()
{ {
var requestStarted = new SemaphoreSlim(0);
var connectionReset = new SemaphoreSlim(0); var connectionReset = new SemaphoreSlim(0);
var loggedHigherThanDebug = false;
var mockLogger = new Mock<ILogger>(); var mockLogger = new Mock<ILogger>();
mockLogger mockLogger
.Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>())) .Setup(logger => logger.IsEnabled(It.IsAny<LogLevel>()))
.Returns(true); .Returns(true);
mockLogger mockLogger
.Setup(logger => logger.Log(LogLevel.Debug, _connectionResetEventId, It.IsAny<object>(), null, It.IsAny<Func<object, Exception, string>>())) .Setup(logger => logger.Log(It.IsAny<LogLevel>(), It.IsAny<EventId>(), It.IsAny<object>(), It.IsAny<Exception>(), It.IsAny<Func<object, Exception, string>>()))
.Callback(() => .Callback<LogLevel, EventId, object, Exception, Func<object, Exception, string>>((logLevel, eventId, state, exception, formatter) =>
{ {
connectionReset.Release(); if (eventId.Id == _connectionResetEventId)
}); {
connectionReset.Release();
}
if (logLevel > LogLevel.Debug)
{
loggedHigherThanDebug = true;
}
});
var mockLoggerFactory = new Mock<ILoggerFactory>(); var mockLoggerFactory = new Mock<ILoggerFactory>();
mockLoggerFactory mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel")) .Setup(factory => factory.CreateLogger(It.IsAny<string>()))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv"))
.Returns(mockLogger.Object);
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsNotIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv")))
.Returns(Mock.Of<ILogger>()); .Returns(Mock.Of<ILogger>());
mockLoggerFactory
.Setup(factory => factory.CreateLogger(It.IsIn("Microsoft.AspNetCore.Server.Kestrel", "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv")))
.Returns(mockLogger.Object);
var requestStarted = new SemaphoreSlim(0); using (var server = new TestServer(async context =>
var builder = new WebHostBuilder()
.UseLoggerFactory(mockLoggerFactory.Object)
.UseKestrel()
.UseUrls("http://127.0.0.1:0")
.Configure(app => app.Run(async context =>
{ {
requestStarted.Release(); requestStarted.Release();
await context.Request.Body.ReadAsync(new byte[1], 0, 1); await context.Request.Body.ReadAsync(new byte[1], 0, 1);
})); },
new TestServiceContext(mockLoggerFactory.Object)))
using (var host = builder.Build())
{ {
host.Start(); using (var connection = server.CreateConnection())
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{ {
socket.Connect(new IPEndPoint(IPAddress.Loopback, host.GetPort())); await connection.Send(
socket.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\nHost:\r\n\r\n")); "GET / HTTP/1.1",
"Host:",
"",
"");
// Wait until connection is established // Wait until connection is established
Assert.True(await requestStarted.WaitAsync(TimeSpan.FromSeconds(10))); Assert.True(await requestStarted.WaitAsync(TimeSpan.FromSeconds(10)));
// Force a reset // Force a reset
socket.LingerState = new LingerOption(true, 0); connection.Socket.LingerState = new LingerOption(true, 0);
} }
// If the reset is correctly logged as Debug, the wait below should complete shortly. // If the reset is correctly logged as Debug, the wait below should complete shortly.
@ -441,6 +437,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
// and therefore not logged. // and therefore not logged.
Assert.True(await connectionReset.WaitAsync(TimeSpan.FromSeconds(10))); Assert.True(await connectionReset.WaitAsync(TimeSpan.FromSeconds(10)));
} }
Assert.False(loggedHigherThanDebug);
} }
[Fact] [Fact]

View File

@ -20,6 +20,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Internal; using Microsoft.Extensions.Internal;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Primitives;
@ -300,7 +301,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
disposedTcs.TrySetResult(c.Response.StatusCode); disposedTcs.TrySetResult(c.Response.StatusCode);
}); });
using (var server = new TestServer(handler, new TestServiceContext(), mockHttpContextFactory.Object)) using (var server = new TestServer(handler, new TestServiceContext(), new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)),
services => services.AddSingleton(mockHttpContextFactory.Object)))
{ {
if (!sendMalformedRequest) if (!sendMalformedRequest)
{ {

View File

@ -34,21 +34,16 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
public TestServer(RequestDelegate app, TestServiceContext context) public TestServer(RequestDelegate app, TestServiceContext context)
: this(app, context, httpContextFactory: null) : this(app, context, new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)))
{
}
public TestServer(RequestDelegate app, TestServiceContext context, IHttpContextFactory httpContextFactory)
: this(app, context, new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)), httpContextFactory)
{ {
} }
public TestServer(RequestDelegate app, TestServiceContext context, ListenOptions listenOptions) public TestServer(RequestDelegate app, TestServiceContext context, ListenOptions listenOptions)
: this(app, context, listenOptions, null) : this(app, context, listenOptions, _ => { })
{ {
} }
public TestServer(RequestDelegate app, TestServiceContext context, ListenOptions listenOptions, IHttpContextFactory httpContextFactory) public TestServer(RequestDelegate app, TestServiceContext context, ListenOptions listenOptions, Action<IServiceCollection> configureServices)
{ {
_app = app; _app = app;
_listenOptions = listenOptions; _listenOptions = listenOptions;
@ -61,13 +56,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
}) })
.ConfigureServices(services => .ConfigureServices(services =>
{ {
if (httpContextFactory != null)
{
services.AddSingleton(httpContextFactory);
}
services.AddSingleton<IStartup>(this); services.AddSingleton<IStartup>(this);
services.AddSingleton<ILoggerFactory>(new KestrelTestLoggerFactory(context.ErrorLogger)); services.AddSingleton(context.LoggerFactory);
services.AddSingleton<IServer>(sp => services.AddSingleton<IServer>(sp =>
{ {
// Manually configure options on the TestServiceContext. // Manually configure options on the TestServiceContext.
@ -79,6 +69,8 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
} }
return new KestrelServer(sp.GetRequiredService<ITransportFactory>(), context); return new KestrelServer(sp.GetRequiredService<ITransportFactory>(), context);
}); });
configureServices(services);
}) })
.UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName) .UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName)
.Build(); .Build();

View File

@ -10,6 +10,11 @@ namespace Microsoft.AspNetCore.Testing
{ {
private readonly ILogger _testLogger; private readonly ILogger _testLogger;
public KestrelTestLoggerFactory()
: this(new TestApplicationErrorLogger())
{
}
public KestrelTestLoggerFactory(ILogger testLogger) public KestrelTestLoggerFactory(ILogger testLogger)
{ {
_testLogger = testLogger; _testLogger = testLogger;

View File

@ -15,8 +15,6 @@ namespace Microsoft.AspNetCore.Testing
// Application errors are logged using 13 as the eventId. // Application errors are logged using 13 as the eventId.
private const int ApplicationErrorEventId = 13; private const int ApplicationErrorEventId = 13;
private TaskCompletionSource<object> _messageLoggedTcs = new TaskCompletionSource<object>();
public bool ThrowOnCriticalErrors { get; set; } = true; public bool ThrowOnCriticalErrors { get; set; } = true;
public ConcurrentBag<LogMessage> Messages { get; } = new ConcurrentBag<LogMessage>(); public ConcurrentBag<LogMessage> Messages { get; } = new ConcurrentBag<LogMessage>();
@ -27,8 +25,6 @@ namespace Microsoft.AspNetCore.Testing
public int ApplicationErrorsLogged => Messages.Count(message => message.EventId.Id == ApplicationErrorEventId); public int ApplicationErrorsLogged => Messages.Count(message => message.EventId.Id == ApplicationErrorEventId);
public Task MessageLoggedTask => _messageLoggedTcs.Task;
public IDisposable BeginScope<TState>(TState state) public IDisposable BeginScope<TState>(TState state)
{ {
return new Disposable(() => { }); return new Disposable(() => { });
@ -60,8 +56,6 @@ namespace Microsoft.AspNetCore.Testing
Exception = exception, Exception = exception,
Message = formatter(state, exception) Message = formatter(state, exception)
}); });
_messageLoggedTcs.TrySetResult(null);
} }
public class LogMessage public class LogMessage

View File

@ -17,35 +17,48 @@ namespace Microsoft.AspNetCore.Testing
/// </summary> /// </summary>
public class TestConnection : IDisposable public class TestConnection : IDisposable
{ {
private Socket _socket;
private NetworkStream _stream;
private StreamReader _reader;
private static readonly TimeSpan Timeout = TimeSpan.FromMinutes(1); private static readonly TimeSpan Timeout = TimeSpan.FromMinutes(1);
private readonly bool _ownsSocket;
private readonly Socket _socket;
private readonly NetworkStream _stream;
private readonly StreamReader _reader;
public TestConnection(int port) public TestConnection(int port)
: this(port, AddressFamily.InterNetwork) : this(port, AddressFamily.InterNetwork)
{ {
} }
public TestConnection(int port, AddressFamily addressFamily) public TestConnection(int port, AddressFamily addressFamily)
: this(CreateConnectedLoopbackSocket(port, addressFamily), ownsSocket: true)
{ {
Create(port, addressFamily);
} }
public StreamReader Reader => _reader; public TestConnection(Socket socket)
: this(socket, ownsSocket: false)
public void Create(int port, AddressFamily addressFamily)
{ {
_socket = CreateConnectedLoopbackSocket(port, addressFamily); }
_stream = new NetworkStream(_socket, false); private TestConnection(Socket socket, bool ownsSocket)
{
_ownsSocket = ownsSocket;
_socket = socket;
_stream = new NetworkStream(_socket, ownsSocket: false);
_reader = new StreamReader(_stream, Encoding.ASCII); _reader = new StreamReader(_stream, Encoding.ASCII);
} }
public Socket Socket => _socket;
public StreamReader Reader => _reader;
public void Dispose() public void Dispose()
{ {
_stream.Dispose(); _stream.Dispose();
_socket.Dispose();
if (_ownsSocket)
{
_socket.Dispose();
}
} }
public async Task SendAll(params string[] lines) public async Task SendAll(params string[] lines)

View File

@ -12,9 +12,19 @@ namespace Microsoft.AspNetCore.Testing
public class TestServiceContext : ServiceContext public class TestServiceContext : ServiceContext
{ {
public TestServiceContext() public TestServiceContext()
: this(new KestrelTestLoggerFactory())
{ {
ErrorLogger = new TestApplicationErrorLogger(); }
Log = new TestKestrelTrace(ErrorLogger);
public TestServiceContext(ILoggerFactory loggerFactory)
: this(loggerFactory, new KestrelTrace(loggerFactory.CreateLogger("Microsoft.AspNetCore.Server.Kestrel")))
{
}
public TestServiceContext(ILoggerFactory loggerFactory, IKestrelTrace kestrelTrace)
{
LoggerFactory = loggerFactory;
Log = kestrelTrace;
ThreadPool = new LoggingThreadPool(Log); ThreadPool = new LoggingThreadPool(Log);
SystemClock = new MockSystemClock(); SystemClock = new MockSystemClock();
DateHeaderValueManager = new DateHeaderValueManager(SystemClock); DateHeaderValueManager = new DateHeaderValueManager(SystemClock);
@ -27,7 +37,7 @@ namespace Microsoft.AspNetCore.Testing
}; };
} }
public TestApplicationErrorLogger ErrorLogger { get; } public ILoggerFactory LoggerFactory { get; }
public string DateHeaderValue { get; } public string DateHeaderValue { get; }
} }