aspnetcore/test/Kestrel.Transport.Libuv.Tests/LibuvTransportTests.cs

144 lines
5.7 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class LibuvTransportTests
{
public static TheoryData<ListenOptions> ConnectionAdapterData => new TheoryData<ListenOptions>
{
new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)),
new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0))
{
ConnectionAdapters = { new PassThroughConnectionAdapter() }
}
};
public static IEnumerable<object[]> OneToTen => Enumerable.Range(1, 10).Select(i => new object[] { i });
[Fact]
public async Task TransportCanBindAndStop()
{
var transportContext = new TestLibuvTransportContext();
var transport = new LibuvTransport(transportContext,
new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)));
// The transport can no longer start threads without binding to an endpoint.
await transport.BindAsync();
await transport.StopAsync();
}
[Fact]
public async Task TransportCanBindUnbindAndStop()
{
var transportContext = new TestLibuvTransportContext();
var transport = new LibuvTransport(transportContext, new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0)));
await transport.BindAsync();
await transport.UnbindAsync();
await transport.StopAsync();
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ConnectionCanReadAndWrite(ListenOptions listenOptions)
{
var serviceContext = new TestServiceContext();
listenOptions.UseHttpServer(listenOptions.ConnectionAdapters, serviceContext, new DummyApplication(TestApp.EchoApp), HttpProtocols.Http1);
var transportContext = new TestLibuvTransportContext
{
ConnectionDispatcher = new ConnectionDispatcher(serviceContext, listenOptions.Build())
};
var transport = new LibuvTransport(transportContext, listenOptions);
await transport.BindAsync();
using (var socket = TestConnection.CreateConnectedLoopbackSocket(listenOptions.IPEndPoint.Port))
{
var data = "Hello World";
socket.Send(Encoding.ASCII.GetBytes($"POST / HTTP/1.0\r\nContent-Length: 11\r\n\r\n{data}"));
var buffer = new byte[data.Length];
var read = 0;
while (read < data.Length)
{
read += socket.Receive(buffer, read, buffer.Length - read, SocketFlags.None);
}
}
Assert.True(await serviceContext.ConnectionManager.CloseAllConnectionsAsync(new CancellationTokenSource(TestConstants.DefaultTimeout).Token));
await transport.UnbindAsync();
await transport.StopAsync();
}
[ConditionalTheory]
[MemberData(nameof(OneToTen))]
[OSSkipCondition(OperatingSystems.MacOSX, SkipReason = "Tests fail on OS X due to low file descriptor limit.")]
public async Task OneToTenThreads(int threadCount)
{
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var serviceContext = new TestServiceContext();
var testApplication = new DummyApplication(context =>
{
return context.Response.WriteAsync("Hello World");
});
listenOptions.UseHttpServer(listenOptions.ConnectionAdapters, serviceContext, testApplication, HttpProtocols.Http1);
var transportContext = new TestLibuvTransportContext
{
ConnectionDispatcher = new ConnectionDispatcher(serviceContext, listenOptions.Build()),
Options = new LibuvTransportOptions { ThreadCount = threadCount }
};
var transport = new LibuvTransport(transportContext, listenOptions);
await transport.BindAsync();
using (var client = new HttpClient())
{
// Send 20 requests just to make sure we don't get any failures
var requestTasks = new List<Task<string>>();
for (int i = 0; i < 20; i++)
{
var requestTask = client.GetStringAsync($"http://127.0.0.1:{listenOptions.IPEndPoint.Port}/");
requestTasks.Add(requestTask);
}
foreach (var result in await Task.WhenAll(requestTasks))
{
Assert.Equal("Hello World", result);
}
}
await transport.UnbindAsync();
if (!await serviceContext.ConnectionManager.CloseAllConnectionsAsync(default).ConfigureAwait(false))
{
await serviceContext.ConnectionManager.AbortAllConnectionsAsync().ConfigureAwait(false);
}
await transport.StopAsync();
}
}
}