Use WebHostBuilder as an implementation detail of TestServer (#1804)

- This will make tests run more similarly so we can swap out the
transport more easily.
This commit is contained in:
David Fowler 2017-05-03 19:35:09 -07:00 committed by GitHub
parent 6c0c31640f
commit b21f84543a
2 changed files with 55 additions and 47 deletions

View File

@ -4,13 +4,16 @@
using System; using System;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Threading; using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting.Server;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions; using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets;
using Microsoft.AspNetCore.Testing; using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
@ -18,12 +21,11 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
/// <summary> /// <summary>
/// Summary description for TestServer /// Summary description for TestServer
/// </summary> /// </summary>
public class TestServer : IDisposable public class TestServer : IDisposable, IStartup
{ {
private static TimeSpan _shutdownTimeout = TimeSpan.FromSeconds(5); private IWebHost _host;
private KestrelServer _server;
private ListenOptions _listenOptions; private ListenOptions _listenOptions;
private readonly RequestDelegate _app;
public TestServer(RequestDelegate app) public TestServer(RequestDelegate app)
: this(app, new TestServiceContext()) : this(app, new TestServiceContext())
@ -47,46 +49,40 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public TestServer(RequestDelegate app, TestServiceContext context, ListenOptions listenOptions, IHttpContextFactory httpContextFactory) public TestServer(RequestDelegate app, TestServiceContext context, ListenOptions listenOptions, IHttpContextFactory httpContextFactory)
{ {
_app = app;
_listenOptions = listenOptions; _listenOptions = listenOptions;
Context = context; Context = context;
context.ServerOptions.ListenOptions.Add(_listenOptions);
// Switch this to test on socket transport _host = new WebHostBuilder()
var transportFactory = CreateLibuvTransportFactory(context); .UseKestrel(o =>
// var transportFactory = CreateSocketTransportFactory(context); {
o.ListenOptions.Add(_listenOptions);
})
.ConfigureServices(services =>
{
if (httpContextFactory != null)
{
services.AddSingleton(httpContextFactory);
}
_server = new KestrelServer(transportFactory, context); services.AddSingleton<IStartup>(this);
var httpApplication = new DummyApplication(app, httpContextFactory); services.AddSingleton<ILoggerFactory>(new KestrelTestLoggerFactory(context.ErrorLogger));
services.AddSingleton<IServer>(sp =>
{
// Manually configure options on the TestServiceContext.
// We're doing this so we can use the same instance that was passed in
var configureOptions = sp.GetServices<IConfigureOptions<KestrelServerOptions>>();
foreach (var c in configureOptions)
{
c.Configure(context.ServerOptions);
}
return new KestrelServer(sp.GetRequiredService<ITransportFactory>(), context);
});
})
.UseSetting(WebHostDefaults.ApplicationKey, typeof(TestServer).GetTypeInfo().Assembly.FullName)
.Build();
try _host.Start();
{
_server.StartAsync(httpApplication, CancellationToken.None).Wait();
}
catch
{
_server.StopAsync(new CancellationTokenSource(_shutdownTimeout).Token).Wait();
_server.Dispose();
throw;
}
}
private static ITransportFactory CreateLibuvTransportFactory(TestServiceContext context)
{
var transportOptions = new LibuvTransportOptions { ThreadCount = 1 };
var transportFactory = new LibuvTransportFactory(
Options.Create(transportOptions),
new LifetimeNotImplemented(),
new KestrelTestLoggerFactory(new TestApplicationErrorLogger()));
return transportFactory;
}
private static ITransportFactory CreateSocketTransportFactory(TestServiceContext context)
{
var options = new SocketTransportOptions();
return new SocketTransportFactory(Options.Create(options));
} }
public IPEndPoint EndPoint => _listenOptions.IPEndPoint; public IPEndPoint EndPoint => _listenOptions.IPEndPoint;
@ -95,6 +91,18 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public TestServiceContext Context { get; } public TestServiceContext Context { get; }
void IStartup.Configure(IApplicationBuilder app)
{
app.Run(_app);
}
IServiceProvider IStartup.ConfigureServices(IServiceCollection services)
{
// Unfortunately, this needs to be replaced in IStartup.ConfigureServices
services.AddSingleton<IApplicationLifetime, LifetimeNotImplemented>();
return services.BuildServiceProvider();
}
public TestConnection CreateConnection() public TestConnection CreateConnection()
{ {
return new TestConnection(Port, AddressFamily); return new TestConnection(Port, AddressFamily);
@ -102,8 +110,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
public void Dispose() public void Dispose()
{ {
_server.StopAsync(new CancellationTokenSource(_shutdownTimeout).Token).Wait(); _host.Dispose();
_server.Dispose();
} }
} }
} }

View File

@ -13,9 +13,8 @@ namespace Microsoft.AspNetCore.Testing
{ {
public TestServiceContext() public TestServiceContext()
{ {
var logger = new TestApplicationErrorLogger(); ErrorLogger = new TestApplicationErrorLogger();
Log = new TestKestrelTrace(ErrorLogger);
Log = new TestKestrelTrace(logger);
ThreadPool = new LoggingThreadPool(Log); ThreadPool = new LoggingThreadPool(Log);
SystemClock = new MockSystemClock(); SystemClock = new MockSystemClock();
DateHeaderValueManager = new DateHeaderValueManager(SystemClock); DateHeaderValueManager = new DateHeaderValueManager(SystemClock);
@ -28,6 +27,8 @@ namespace Microsoft.AspNetCore.Testing
}; };
} }
public TestApplicationErrorLogger ErrorLogger { get; }
public string DateHeaderValue { get; } public string DateHeaderValue { get; }
} }
} }