Split transport-specific tests and general tests into distinct test projects (#1588).

* Rename EngineTests to LibuvTransportTests.
* Move libuv-specific tests into their own test project.
* Move LibuvOutputConsumerTests.AllocCommitCanBeCalledAfterConnectionClose to new OutputProducerTests class and rename it to WritesNoopAfterConnectionCloses.
* Remove TransportContext from TestServiceContext.
* Make KestrelTests depend on Kestrel.Core only.
* Rename Microsoft.AspNetCore.Server.Kestrel.KestrelTests to Microsoft.AspNetCore.Server.Kestrel.Core.Tests.
* Add Microsoft.AspNetCore.Server.Kestrel.Tests test project for WebHostBuilderKestrelExtensionsTests.
* Increase socket receive timeout in MaxRequestBufferSizeTests to mitigate flakiness.
* Anything using TestServer should be a functional test.
* Move out of LibuvTransportTests tests that are not specific to LibuvTransport.
  - Move to RequestTests:
    - Http11 (rename to Http11KeptAliveByDefault)
    - Http10ContentLength (rename to Http10NotKeptAliveByDefault)
    - Http10KeepAlive
    - Http10KeepAliveNotUsedIfResponseContentLengthNotSet (rename to Http10KeepAliveNotHonoredIfResponseContentLengthNotSet)
    - Http10ContentLengthKeepAlive (rename to Http10KeepAliveHonoredIfResponseContentLengthSet)
    - Expect100ContinueForBody (rename to Expect100ContinueHonored)
    - ZeroContentLengthAssumedOnNonKeepAliveRequestsWithoutContentLengthOrTransferEncodingHeader
    - ConnectionClosesWhenFinReceivedBeforeRequestCompletes (test was actually not marked as Theory, and was incorrect)
    - RequestsCanBeAbortedMidRead
    - RequestHeadersAreResetOnEachRequest
    - UpgradeRequestIsNotKeptAliveOrChunked
    - HeadersAndStreamsAreReused (rename to HeadersAndStreamsAreReusedAcrossRequests)
  - Move to ResponseTests:
    - Http10RequestReceivesHttp11Response (rename to Http11ResponseSentToHttp10Request)
    - ZeroContentLengthSetAutomaticallyAfterNoWrites
    - ZeroContentLengthSetAutomaticallyForNonKeepAliveRequests
    - ZeroContentLengthNotSetAutomaticallyForHeadRequests
    - ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes
    - ConnectionClosedAfter101Response
    - ThrowingResultsIn500Response
    - ThrowingAfterWritingKillsConnection
    - ThrowingAfterPartialWriteKillsConnection
    - ThrowingInOnStartingResultsInFailedWritesAnd500Response
    - ThrowingInOnCompletedIsLoggedAndClosesConnection
    - FailedWritesResultInAbortedRequest
    - NoErrorsLoggedWhenServerEndsConnectionBeforeClient
    - NoResponseSentWhenConnectionIsClosedByServerBeforeClientFinishesSendingRequest
    - ResponseHeadersAreResetOnEachRequest
    - OnStartingCallbacksAreCalledInLastInFirstOutOrder
    - OnCompletedCallbacksAreCalledInLastInFirstOutOrder
  - Remove:
    - RePathEscapeTests (theory data to HttpParsingData)
    - ReDisconnectingClient (what was that testing?)
This commit is contained in:
Cesar Blum Silveira 2017-04-06 19:09:40 -07:00 committed by GitHub
parent 26bd01337d
commit f253dbc0c0
67 changed files with 1727 additions and 1596 deletions

View File

@ -1,6 +1,6 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26327.1
VisualStudioVersion = 15.0.26405.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7972A5D6-3385-4127-9277-428506DD44FF}"
ProjectSection(SolutionItems) = preProject
@ -24,11 +24,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0EF2AC
test\shared\HttpParsingData.cs = test\shared\HttpParsingData.cs
test\shared\KestrelTestLoggerFactory.cs = test\shared\KestrelTestLoggerFactory.cs
test\shared\LifetimeNotImplemented.cs = test\shared\LifetimeNotImplemented.cs
test\shared\MockConnection.cs = test\shared\MockConnection.cs
test\shared\MockFrameControl.cs = test\shared\MockFrameControl.cs
test\shared\MockSocketOutput.cs = test\shared\MockSocketOutput.cs
test\shared\MockSystemClock.cs = test\shared\MockSystemClock.cs
test\shared\SocketInputExtensions.cs = test\shared\SocketInputExtensions.cs
test\shared\StringExtensions.cs = test\shared\StringExtensions.cs
test\shared\TestApp.cs = test\shared\TestApp.cs
test\shared\TestApplicationErrorLogger.cs = test\shared\TestApplicationErrorLogger.cs
@ -36,13 +34,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0EF2AC
test\shared\TestFrame.cs = test\shared\TestFrame.cs
test\shared\TestKestrelTrace.cs = test\shared\TestKestrelTrace.cs
test\shared\TestResources.cs = test\shared\TestResources.cs
test\shared\TestServer.cs = test\shared\TestServer.cs
test\shared\TestServiceContext.cs = test\shared\TestServiceContext.cs
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Core", "src\Microsoft.AspNetCore.Server.Kestrel.Core\Microsoft.AspNetCore.Server.Kestrel.Core.csproj", "{F510611A-3BEE-4B88-A613-5F4A74ED82A1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.KestrelTests", "test\Microsoft.AspNetCore.Server.KestrelTests\Microsoft.AspNetCore.Server.KestrelTests.csproj", "{37F3BFB2-6454-49E5-9D7F-581BF755CCFE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Core.Tests", "test\Microsoft.AspNetCore.Server.Kestrel.Core.Tests\Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj", "{37F3BFB2-6454-49E5-9D7F-581BF755CCFE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SampleApp", "samples\SampleApp\SampleApp.csproj", "{2C3CB3DC-EEBF-4F52-9E1C-4F2F972E76C3}"
EndProject
@ -67,6 +64,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions", "src\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions\Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.csproj", "{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests", "test\Microsoft.AspNetCore.Server.Transport.Libuv.Tests\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.csproj", "{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Server.Kestrel.Tests", "test\Microsoft.AspNetCore.Server.Kestrel.Tests\Microsoft.AspNetCore.Server.Kestrel.Tests.csproj", "{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -209,6 +210,30 @@ Global
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x64.Build.0 = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x86.ActiveCfg = Release|Any CPU
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D}.Release|x86.Build.0 = Release|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Debug|x64.ActiveCfg = Debug|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Debug|x64.Build.0 = Debug|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Debug|x86.ActiveCfg = Debug|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Debug|x86.Build.0 = Debug|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Release|Any CPU.Build.0 = Release|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Release|x64.ActiveCfg = Release|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Release|x64.Build.0 = Release|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Release|x86.ActiveCfg = Release|Any CPU
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4}.Release|x86.Build.0 = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Debug|x64.ActiveCfg = Debug|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Debug|x64.Build.0 = Debug|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Debug|x86.ActiveCfg = Debug|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Debug|x86.Build.0 = Debug|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|Any CPU.Build.0 = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x64.ActiveCfg = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x64.Build.0 = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x86.ActiveCfg = Release|Any CPU
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -227,5 +252,7 @@ Global
{A76B8C8C-0DC5-4DD3-9B1F-02E51A0915F4} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{56139957-5C29-4E7D-89BD-7D20598B4EAF} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{2E9CB89D-EC8F-4DD9-A72B-08D5BABF752D} = {2D5D5227-4DBD-499A-96B1-76A36B03B750}
{D95A7EC3-48AC-4D03-B2E2-0DA3E13BD3A4} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
{4F1C30F8-CCAA-48D7-9DF6-2A84021F5BCC} = {D3273454-EA07-41D2-BF0B-FCC3675C2483}
EndGlobalSection
EndGlobal

View File

@ -4,5 +4,6 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.KestrelTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Core.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class AsciiDecodingTests
{

View File

@ -6,7 +6,7 @@ using System.Text;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class ChunkWriterTests
{

View File

@ -5,7 +5,7 @@ using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class CreateIPEndpointTests
{

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class DateHeaderValueManagerTests
{

View File

@ -8,7 +8,7 @@ using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class FrameHeadersTests
{

View File

@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.Extensions.Primitives;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class FrameRequestHeadersTests
{

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class FrameRequestStreamTests
{

View File

@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Primitives;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class FrameResponseHeadersTests
{

View File

@ -5,10 +5,10 @@ using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers;
using Microsoft.AspNetCore.Server.Kestrel.Core.Tests.TestHelpers;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class FrameResponseStreamTests
{

View File

@ -26,7 +26,7 @@ using Microsoft.Extensions.Primitives;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class FrameTests : IDisposable
{

View File

@ -16,7 +16,7 @@ using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class HttpParserTests
{

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class HttpUtilitiesTest
{

View File

@ -7,7 +7,7 @@ using System.Reflection;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class KestrelEventSourceTests
{

View File

@ -5,7 +5,7 @@ using System;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class KestrelServerLimitsTests
{

View File

@ -5,7 +5,7 @@ using System.Net;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class KestrelServerOptionsTests
{

View File

@ -16,7 +16,7 @@ using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class KestrelServerTests
{

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class LoggingThreadPoolTests
{

View File

@ -16,7 +16,7 @@ using Moq;
using Xunit;
using Xunit.Sdk;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
/// <summary>
/// Summary description for MessageBodyTests

View File

@ -22,12 +22,12 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel\Microsoft.AspNetCore.Server.Kestrel.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel.Https\Microsoft.AspNetCore.Server.Kestrel.Https.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel.Core\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="Moq" Version="$(MoqVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />

View File

@ -0,0 +1,61 @@
// 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 Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.AspNetCore.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class OutputProducerTests
{
private readonly PipeFactory _pipeFactory;
public OutputProducerTests()
{
_pipeFactory = new PipeFactory();
}
public void Dispose()
{
_pipeFactory.Dispose();
}
[Fact]
public void WritesNoopAfterConnectionCloses()
{
var pipeOptions = new PipeOptions
{
ReaderScheduler = Mock.Of<IScheduler>(),
};
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
// Close
socketOutput.Dispose();
var called = false;
((ISocketOutput)socketOutput).Write<object>((buffer, state) =>
{
called = true;
},
null);
Assert.False(called);
}
}
private OutputProducer CreateOutputProducer(PipeOptions pipeOptions)
{
var pipe = _pipeFactory.Create(pipeOptions);
var serviceContext = new TestServiceContext();
var frame = new Frame<object>(null, new FrameContext { ServiceContext = serviceContext });
var socketOutput = new OutputProducer(pipe.Writer, frame, "0", serviceContext.Log);
return socketOutput;
}
}
}

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class PathNormalizerTests
{

View File

@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Testing;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class PipeOptionsTests
{
@ -35,7 +35,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
[Theory]
[InlineData(10, 10, 10)]
[InlineData(null, 0, 0)]
public void LibuvInputPipeOptionsConfiguredCorrectly(long? maxRequestBufferSize, long expectedMaximumSizeLow, long expectedMaximumSizeHigh)
public void InputPipeOptionsConfiguredCorrectly(long? maxRequestBufferSize, long expectedMaximumSizeLow, long expectedMaximumSizeHigh)
{
var serviceContext = new TestServiceContext();
serviceContext.ServerOptions.Limits.MaxRequestBufferSize = maxRequestBufferSize;

View File

@ -9,7 +9,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class PipelineExtensionTests : IDisposable
{

View File

@ -5,7 +5,7 @@ using System;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class ServerAddressTests
{

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
public class StreamSocketOutputTests
{

View File

@ -7,7 +7,7 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests.TestHelpers
{
public class MockFrameControl : IFrameControl
{

View File

@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Tests
{
class TestInput : ITimeoutControl, IFrameControl, IDisposable
{

View File

@ -13,7 +13,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class ChunkedRequestTests
{

View File

@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class ChunkedResponseTests
{

View File

@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Adapter;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class ConnectionAdapterTests
{

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class DefaultHeaderTests
{

View File

@ -20,7 +20,7 @@ using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Internal;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class HttpsConnectionAdapterTests
{

View File

@ -248,7 +248,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
// Timeouts large enough to prevent false positives, but small enough to fail quickly.
socket.SendTimeout = 10 * 1000;
socket.ReceiveTimeout = 10 * 1000;
socket.ReceiveTimeout = 30 * 1000;
socket.Connect(IPAddress.Loopback, port);

View File

@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class RequestTargetProcessingTests
{

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
@ -15,6 +16,8 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Testing.xunit;
@ -35,6 +38,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
private const int _connectionResetEventId = 19;
private const int _semaphoreWaitTimeout = 2500;
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() }
}
};
[Theory]
[InlineData(10 * 1024 * 1024, true)]
// In the following dataset, send at least 2GB.
@ -633,6 +645,558 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Http11KeptAliveByDefault(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoAppChunked, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"GET / HTTP/1.1",
"Connection: close",
"Content-Length: 7",
"",
"Goodbye");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 7",
"",
"Goodbye");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Http10NotKeptAliveByDefault(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoApp, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.0",
"Content-Length: 11",
"",
"Hello World");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"",
"Hello World");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Http10KeepAlive(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoAppChunked, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"Connection: keep-alive",
"",
"POST / HTTP/1.0",
"Content-Length: 7",
"",
"Goodbye");
await connection.Receive(
"HTTP/1.1 200 OK",
"Connection: keep-alive",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"\r\n");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 7",
"",
"Goodbye");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Http10KeepAliveNotHonoredIfResponseContentLengthNotSet(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoApp, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"Connection: keep-alive",
"",
"");
await connection.Receive(
"HTTP/1.1 200 OK",
"Connection: keep-alive",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"\r\n");
await connection.Send(
"POST / HTTP/1.0",
"Connection: keep-alive",
"Content-Length: 7",
"",
"Goodbye");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"",
"Goodbye");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Http10KeepAliveHonoredIfResponseContentLengthSet(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoAppChunked, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.0",
"Content-Length: 11",
"Connection: keep-alive",
"",
"Hello World");
await connection.Receive(
"HTTP/1.1 200 OK",
"Connection: keep-alive",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello World");
await connection.Send(
"POST / HTTP/1.0",
"Connection: keep-alive",
"Content-Length: 11",
"",
"Hello Again");
await connection.Receive(
"HTTP/1.1 200 OK",
"Connection: keep-alive",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello Again");
await connection.Send(
"POST / HTTP/1.0",
"Content-Length: 7",
"",
"Goodbye");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 7",
"",
"Goodbye");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Expect100ContinueHonored(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoAppChunked, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.1",
"Expect: 100-continue",
"Connection: close",
"Content-Length: 11",
"\r\n");
await connection.Receive(
"HTTP/1.1 100 Continue",
"",
"");
await connection.Send("Hello World");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello World");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ZeroContentLengthAssumedOnNonKeepAliveRequestsWithoutContentLengthOrTransferEncodingHeader(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(async httpContext =>
{
// This will hang if 0 content length is not assumed by the server
Assert.Equal(0, await httpContext.Request.Body.ReadAsync(new byte[1], 0, 1).TimeoutAfter(TimeSpan.FromSeconds(10)));
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
// Use Send instead of SendEnd to ensure the connection will remain open while
// the app runs and reads 0 bytes from the body nonetheless. This checks that
// https://github.com/aspnet/KestrelHttpServer/issues/1104 is not regressing.
await connection.Send(
"GET / HTTP/1.1",
"Connection: close",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ConnectionClosesWhenFinReceivedBeforeRequestCompletes(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoAppChunked, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.1");
connection.Shutdown(SocketShutdown.Send);
await connection.ReceiveForcedEnd();
}
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.1",
"Content-Length: 7");
connection.Shutdown(SocketShutdown.Send);
await connection.ReceiveForcedEnd();
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task RequestsCanBeAbortedMidRead(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
var readTcs = new TaskCompletionSource<object>();
var registrationTcs = new TaskCompletionSource<int>();
var requestId = 0;
using (var server = new TestServer(async httpContext =>
{
requestId++;
var response = httpContext.Response;
var request = httpContext.Request;
var lifetime = httpContext.Features.Get<IHttpRequestLifetimeFeature>();
lifetime.RequestAborted.Register(() => registrationTcs.TrySetResult(requestId));
if (requestId == 1)
{
response.Headers["Content-Length"] = new[] { "5" };
await response.WriteAsync("World");
}
else
{
var readTask = request.Body.CopyToAsync(Stream.Null);
lifetime.Abort();
try
{
await readTask;
}
catch (Exception ex)
{
readTcs.SetException(ex);
throw;
}
readTcs.SetException(new Exception("This shouldn't be reached."));
}
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
// Never send the body so CopyToAsync always fails.
await connection.Send(
"POST / HTTP/1.1",
"Content-Length: 5",
"",
"HelloPOST / HTTP/1.1",
"Content-Length: 5",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 5",
"",
"World");
}
}
await Assert.ThrowsAsync<TaskCanceledException>(async () => await readTcs.Task);
// The cancellation token for only the last request should be triggered.
var abortedRequestId = await registrationTcs.Task;
Assert.Equal(2, abortedRequestId);
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task RequestHeadersAreResetOnEachRequest(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
IHeaderDictionary originalRequestHeaders = null;
var firstRequest = true;
using (var server = new TestServer(httpContext =>
{
var requestFeature = httpContext.Features.Get<IHttpRequestFeature>();
if (firstRequest)
{
originalRequestHeaders = requestFeature.Headers;
requestFeature.Headers = new FrameRequestHeaders();
firstRequest = false;
}
else
{
Assert.Same(originalRequestHeaders, requestFeature.Headers);
}
return TaskCache.CompletedTask;
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task UpgradeRequestIsNotKeptAliveOrChunked(ListenOptions listenOptions)
{
const string message = "Hello World";
var testContext = new TestServiceContext();
using (var server = new TestServer(async context =>
{
var upgradeFeature = context.Features.Get<IHttpUpgradeFeature>();
var duplexStream = await upgradeFeature.UpgradeAsync();
var buffer = new byte[message.Length];
var read = 0;
while (read < message.Length)
{
read += await duplexStream.ReadAsync(buffer, read, buffer.Length - read).TimeoutAfter(TimeSpan.FromSeconds(10));
}
await duplexStream.WriteAsync(buffer, 0, read);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"Connection: Upgrade",
"",
message);
await connection.ReceiveForcedEnd(
"HTTP/1.1 101 Switching Protocols",
"Connection: Upgrade",
$"Date: {testContext.DateHeaderValue}",
"",
message);
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task HeadersAndStreamsAreReusedAcrossRequests(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
var streamCount = 0;
var requestHeadersCount = 0;
var responseHeadersCount = 0;
var loopCount = 20;
Stream lastStream = null;
IHeaderDictionary lastRequestHeaders = null;
IHeaderDictionary lastResponseHeaders = null;
using (var server = new TestServer(async context =>
{
if (context.Request.Body != lastStream)
{
lastStream = context.Request.Body;
streamCount++;
}
if (context.Request.Headers != lastRequestHeaders)
{
lastRequestHeaders = context.Request.Headers;
requestHeadersCount++;
}
if (context.Response.Headers != lastResponseHeaders)
{
lastResponseHeaders = context.Response.Headers;
responseHeadersCount++;
}
var ms = new MemoryStream();
await context.Request.Body.CopyToAsync(ms);
var request = ms.ToArray();
context.Response.ContentLength = request.Length;
await context.Response.Body.WriteAsync(request, 0, request.Length);
}, testContext))
{
using (var connection = server.CreateConnection())
{
var requestData =
Enumerable.Repeat("GET / HTTP/1.1\r\n", loopCount)
.Concat(new[] { "GET / HTTP/1.1\r\nContent-Length: 7\r\nConnection: close\r\n\r\nGoodbye" });
var response = string.Join("\r\n", new string[] {
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
""});
var lastResponse = string.Join("\r\n", new string[]
{
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 7",
"",
"Goodbye"
});
var responseData =
Enumerable.Repeat(response, loopCount)
.Concat(new[] { lastResponse });
await connection.Send(requestData.ToArray());
await connection.ReceiveEnd(responseData.ToArray());
}
Assert.Equal(1, streamCount);
Assert.Equal(1, requestHeadersCount);
Assert.Equal(1, responseHeadersCount);
}
}
private async Task TestRemoteIPAddress(string registerAddress, string requestAddress, string expectAddress)
{
var builder = new WebHostBuilder()

View File

@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
@ -14,6 +16,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Testing;
@ -27,6 +30,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
public class ResponseTests
{
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() }
}
};
[Fact]
public async Task LargeDownload()
{
@ -1529,6 +1541,751 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task Http11ResponseSentToHttp10Request(ListenOptions listenOptions)
{
var serviceContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EchoApp, serviceContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.0",
"Content-Length: 11",
"",
"Hello World");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {serviceContext.DateHeaderValue}",
"",
"Hello World");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ZeroContentLengthSetAutomaticallyAfterNoWrites(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EmptyApp, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"GET / HTTP/1.0",
"Connection: keep-alive",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"HTTP/1.1 200 OK",
"Connection: keep-alive",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ZeroContentLengthSetAutomaticallyForNonKeepAliveRequests(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(async httpContext =>
{
Assert.Equal(0, await httpContext.Request.Body.ReadAsync(new byte[1], 0, 1).TimeoutAfter(TimeSpan.FromSeconds(10)));
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"Connection: close",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ZeroContentLengthNotSetAutomaticallyForHeadRequests(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(TestApp.EmptyApp, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"HEAD / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ZeroContentLengthNotSetAutomaticallyForCertainStatusCodes(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(async httpContext =>
{
var request = httpContext.Request;
var response = httpContext.Response;
using (var reader = new StreamReader(request.Body, Encoding.ASCII))
{
var statusString = await reader.ReadLineAsync();
response.StatusCode = int.Parse(statusString);
}
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.1",
"Content-Length: 3",
"",
"204POST / HTTP/1.1",
"Content-Length: 3",
"",
"205POST / HTTP/1.1",
"Content-Length: 3",
"",
"304POST / HTTP/1.1",
"Content-Length: 3",
"",
"200");
await connection.ReceiveEnd(
"HTTP/1.1 204 No Content",
$"Date: {testContext.DateHeaderValue}",
"",
"HTTP/1.1 205 Reset Content",
$"Date: {testContext.DateHeaderValue}",
"",
"HTTP/1.1 304 Not Modified",
$"Date: {testContext.DateHeaderValue}",
"",
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ConnectionClosedAfter101Response(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(async httpContext =>
{
var request = httpContext.Request;
var stream = await httpContext.Features.Get<IHttpUpgradeFeature>().UpgradeAsync();
var response = Encoding.ASCII.GetBytes("hello, world");
await stream.WriteAsync(response, 0, response.Length);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 101 Switching Protocols",
"Connection: Upgrade",
$"Date: {testContext.DateHeaderValue}",
"",
"hello, world");
}
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"Connection: keep-alive",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 101 Switching Protocols",
"Connection: Upgrade",
$"Date: {testContext.DateHeaderValue}",
"",
"hello, world");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ThrowingResultsIn500Response(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
bool onStartingCalled = false;
var testLogger = new TestApplicationErrorLogger();
testContext.Log = new KestrelTrace(testLogger);
using (var server = new TestServer(httpContext =>
{
var response = httpContext.Response;
response.OnStarting(_ =>
{
onStartingCalled = true;
return TaskCache.CompletedTask;
}, null);
// Anything added to the ResponseHeaders dictionary is ignored
response.Headers["Content-Length"] = "11";
throw new Exception();
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"GET / HTTP/1.1",
"Connection: close",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 500 Internal Server Error",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"HTTP/1.1 500 Internal Server Error",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
Assert.False(onStartingCalled);
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ThrowingInOnStartingResultsInFailedWritesAnd500Response(ListenOptions listenOptions)
{
var callback1Called = false;
var callback2CallCount = 0;
var testContext = new TestServiceContext();
var testLogger = new TestApplicationErrorLogger();
testContext.Log = new KestrelTrace(testLogger);
using (var server = new TestServer(async httpContext =>
{
var onStartingException = new Exception();
var response = httpContext.Response;
response.OnStarting(_ =>
{
callback1Called = true;
throw onStartingException;
}, null);
response.OnStarting(_ =>
{
callback2CallCount++;
throw onStartingException;
}, null);
var writeException = await Assert.ThrowsAsync<ObjectDisposedException>(async () => await response.Body.FlushAsync());
Assert.Same(onStartingException, writeException.InnerException);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 500 Internal Server Error",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"HTTP/1.1 500 Internal Server Error",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
// The first registered OnStarting callback should have been called,
// since they are called LIFO order and the other one failed.
Assert.False(callback1Called);
Assert.Equal(2, callback2CallCount);
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ThrowingInOnCompletedIsLoggedAndClosesConnection(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
var onCompletedCalled1 = false;
var onCompletedCalled2 = false;
var testLogger = new TestApplicationErrorLogger();
testContext.Log = new KestrelTrace(testLogger);
using (var server = new TestServer(async httpContext =>
{
var response = httpContext.Response;
response.OnCompleted(_ =>
{
onCompletedCalled1 = true;
throw new Exception();
}, null);
response.OnCompleted(_ =>
{
onCompletedCalled2 = true;
throw new Exception();
}, null);
response.Headers["Content-Length"] = new[] { "11" };
await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello World");
}
}
// All OnCompleted callbacks should be called even if they throw.
Assert.Equal(2, testLogger.ApplicationErrorsLogged);
Assert.True(onCompletedCalled1);
Assert.True(onCompletedCalled2);
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ThrowingAfterWritingKillsConnection(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
bool onStartingCalled = false;
var testLogger = new TestApplicationErrorLogger();
testContext.Log = new KestrelTrace(testLogger);
using (var server = new TestServer(async httpContext =>
{
var response = httpContext.Response;
response.OnStarting(_ =>
{
onStartingCalled = true;
return Task.FromResult<object>(null);
}, null);
response.Headers["Content-Length"] = new[] { "11" };
await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11);
throw new Exception();
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello World");
}
}
Assert.True(onStartingCalled);
Assert.Equal(1, testLogger.ApplicationErrorsLogged);
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ThrowingAfterPartialWriteKillsConnection(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
bool onStartingCalled = false;
var testLogger = new TestApplicationErrorLogger();
testContext.Log = new KestrelTrace(testLogger);
using (var server = new TestServer(async httpContext =>
{
var response = httpContext.Response;
response.OnStarting(_ =>
{
onStartingCalled = true;
return Task.FromResult<object>(null);
}, null);
response.Headers["Content-Length"] = new[] { "11" };
await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello"), 0, 5);
throw new Exception();
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello");
}
}
Assert.True(onStartingCalled);
Assert.Equal(1, testLogger.ApplicationErrorsLogged);
}
[MemberData(nameof(ConnectionAdapterData))]
public async Task FailedWritesResultInAbortedRequest(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
// This should match _maxBytesPreCompleted in SocketOutput
var maxBytesPreCompleted = 65536;
// Ensure string is long enough to disable write-behind buffering
var largeString = new string('a', maxBytesPreCompleted + 1);
var writeTcs = new TaskCompletionSource<object>();
var registrationWh = new ManualResetEventSlim();
var connectionCloseWh = new ManualResetEventSlim();
using (var server = new TestServer(async httpContext =>
{
var response = httpContext.Response;
var request = httpContext.Request;
var lifetime = httpContext.Features.Get<IHttpRequestLifetimeFeature>();
lifetime.RequestAborted.Register(() => registrationWh.Set());
await request.Body.CopyToAsync(Stream.Null);
connectionCloseWh.Wait();
try
{
// Ensure write is long enough to disable write-behind buffering
for (int i = 0; i < 100; i++)
{
await response.WriteAsync(largeString, lifetime.RequestAborted);
registrationWh.Wait(1000);
}
}
catch (Exception ex)
{
writeTcs.SetException(ex);
throw;
}
writeTcs.SetException(new Exception("This shouldn't be reached."));
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.1",
"Content-Length: 5",
"",
"Hello");
// Don't wait to receive the response. Just close the socket.
}
connectionCloseWh.Set();
// Write failed
await Assert.ThrowsAsync<TaskCanceledException>(async () => await writeTcs.Task);
// RequestAborted tripped
Assert.True(registrationWh.Wait(1000));
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task NoErrorsLoggedWhenServerEndsConnectionBeforeClient(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
var testLogger = new TestApplicationErrorLogger();
testContext.Log = new KestrelTrace(testLogger);
using (var server = new TestServer(async httpContext =>
{
var response = httpContext.Response;
response.Headers["Content-Length"] = new[] { "11" };
await response.Body.WriteAsync(Encoding.ASCII.GetBytes("Hello World"), 0, 11);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.0",
"",
"");
await connection.ReceiveForcedEnd(
"HTTP/1.1 200 OK",
"Connection: close",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 11",
"",
"Hello World");
}
}
Assert.Equal(0, testLogger.TotalErrorsLogged);
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task NoResponseSentWhenConnectionIsClosedByServerBeforeClientFinishesSendingRequest(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
using (var server = new TestServer(httpContext =>
{
httpContext.Abort();
return TaskCache.CompletedTask;
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"POST / HTTP/1.0",
"Content-Length: 1",
"",
"");
await connection.ReceiveForcedEnd();
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ResponseHeadersAreResetOnEachRequest(ListenOptions listenOptions)
{
var testContext = new TestServiceContext();
IHeaderDictionary originalResponseHeaders = null;
var firstRequest = true;
using (var server = new TestServer(httpContext =>
{
var responseFeature = httpContext.Features.Get<IHttpResponseFeature>();
if (firstRequest)
{
originalResponseHeaders = responseFeature.Headers;
responseFeature.Headers = new FrameResponseHeaders();
firstRequest = false;
}
else
{
Assert.Same(originalResponseHeaders, responseFeature.Headers);
}
return TaskCache.CompletedTask;
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
"Content-Length: 0",
"",
"");
}
}
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task OnStartingCallbacksAreCalledInLastInFirstOutOrder(ListenOptions listenOptions)
{
const string response = "hello, world";
var testContext = new TestServiceContext();
var callOrder = new Stack<int>();
var onStartingTcs = new TaskCompletionSource<object>();
using (var server = new TestServer(async context =>
{
context.Response.OnStarting(_ =>
{
callOrder.Push(1);
onStartingTcs.SetResult(null);
return TaskCache.CompletedTask;
}, null);
context.Response.OnStarting(_ =>
{
callOrder.Push(2);
return TaskCache.CompletedTask;
}, null);
context.Response.ContentLength = response.Length;
await context.Response.WriteAsync(response);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
$"Content-Length: {response.Length}",
"",
"hello, world");
// Wait for all callbacks to be called.
await onStartingTcs.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
}
}
Assert.Equal(1, callOrder.Pop());
Assert.Equal(2, callOrder.Pop());
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task OnCompletedCallbacksAreCalledInLastInFirstOutOrder(ListenOptions listenOptions)
{
const string response = "hello, world";
var testContext = new TestServiceContext();
var callOrder = new Stack<int>();
var onCompletedTcs = new TaskCompletionSource<object>();
using (var server = new TestServer(async context =>
{
context.Response.OnCompleted(_ =>
{
callOrder.Push(1);
onCompletedTcs.SetResult(null);
return TaskCache.CompletedTask;
}, null);
context.Response.OnCompleted(_ =>
{
callOrder.Push(2);
return TaskCache.CompletedTask;
}, null);
context.Response.ContentLength = response.Length;
await context.Response.WriteAsync(response);
}, testContext, listenOptions))
{
using (var connection = server.CreateConnection())
{
await connection.Send(
"GET / HTTP/1.1",
"",
"");
await connection.ReceiveEnd(
"HTTP/1.1 200 OK",
$"Date: {testContext.DateHeaderValue}",
$"Content-Length: {response.Length}",
"",
"hello, world");
// Wait for all callbacks to be called.
await onCompletedTcs.Task.TimeoutAfter(TimeSpan.FromSeconds(10));
}
}
Assert.Equal(1, callOrder.Pop());
Assert.Equal(2, callOrder.Pop());
}
public static TheoryData<string, StringValues, string> NullHeaderData
{
get

View File

@ -8,8 +8,10 @@ using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.Testing
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
{
/// <summary>
/// Summary description for TestServer
@ -44,11 +46,21 @@ namespace Microsoft.AspNetCore.Testing
_listenOptions = listenOptions;
Context = context;
Context.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(listenOptions, Context, new DummyApplication(app, httpContextFactory));
TransportContext = new LibuvTransportContext()
{
AppLifetime = new LifetimeNotImplemented(),
ConnectionHandler = new ConnectionHandler<HttpContext>(listenOptions, Context, new DummyApplication(app, httpContextFactory)),
Log = new LibuvTrace(new TestApplicationErrorLogger()),
Options = new LibuvTransportOptions()
{
ThreadCount = 1,
ShutdownTimeout = TimeSpan.FromSeconds(5)
}
};
try
{
_transport = new LibuvTransport(context.TransportContext, _listenOptions);
_transport = new LibuvTransport(TransportContext, _listenOptions);
_transport.BindAsync().Wait();
}
catch
@ -64,6 +76,7 @@ namespace Microsoft.AspNetCore.Testing
public AddressFamily AddressFamily => _listenOptions.IPEndPoint.AddressFamily;
public TestServiceContext Context { get; }
public LibuvTransportContext TransportContext { get; }
public TestConnection CreateConnection()
{

View File

@ -20,7 +20,6 @@
<Compile Include="..\shared\TestApplicationErrorLogger.cs" />
<Compile Include="..\shared\TestFrame.cs" />
<Compile Include="..\shared\TestKestrelTrace.cs" />
<Compile Include="..\shared\MockConnection.cs" />
<Compile Include="..\shared\MockSocketOutput.cs" />
</ItemGroup>

View File

@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks>
<PlatformTarget Condition="'$(TargetFramework)' == 'net46'">x64</PlatformTarget>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
</PropertyGroup>
<ItemGroup>
<None Update="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel\Microsoft.AspNetCore.Server.Kestrel.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Tests
{
public class WebHostBuilderKestrelExtensionsTests
{

View File

@ -0,0 +1,5 @@
{
"$schema": "http://json.schemastore.org/xunit.runner.schema",
"methodDisplay": "method",
"longRunningTestSeconds": 60
}

File diff suppressed because it is too large Load Diff

View File

@ -4,14 +4,12 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class ConnectionTests
{
@ -21,10 +19,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
using (var mockConnectionHandler = new MockConnectionHandler())
{
var mockLibuv = new MockLibuv();
var serviceContext = new TestServiceContext();
serviceContext.TransportContext.ConnectionHandler = mockConnectionHandler;
var transport = new LibuvTransport(mockLibuv, serviceContext.TransportContext, null);
var transportContext = new TestLibuvTransportContext() { ConnectionHandler = mockConnectionHandler };
var transport = new LibuvTransport(mockLibuv, transportContext, null);
var thread = new LibuvThread(transport);
try
@ -32,11 +28,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
await thread.StartAsync();
await thread.PostAsync(_ =>
{
var listenerContext = new ListenerContext(serviceContext.TransportContext)
var listenerContext = new ListenerContext(transportContext)
{
Thread = thread
};
var socket = new MockSocket(mockLibuv, Thread.CurrentThread.ManagedThreadId, serviceContext.TransportContext.Log);
var socket = new MockSocket(mockLibuv, Thread.CurrentThread.ManagedThreadId, transportContext.Log);
var connection = new LibuvConnection(listenerContext, socket);
connection.Start();

View File

@ -7,14 +7,13 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class LibuvOutputConsumerTests : IDisposable
{
@ -37,7 +36,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
_pipeFactory = new PipeFactory();
_mockLibuv = new MockLibuv();
var libuvTransport = new LibuvTransport(_mockLibuv, new TestServiceContext().TransportContext, new ListenOptions(0));
var libuvTransport = new LibuvTransport(_mockLibuv, new TestLibuvTransportContext(), new ListenOptions(0));
_libuvThread = new LibuvThread(libuvTransport, maxLoops: 1);
_libuvThread.StartAsync().Wait();
}
@ -65,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = maxResponseBufferSize ?? 0,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
// At least one run of this test should have a MaxResponseBufferSize < 1 MB.
var bufferSize = 1024 * 1024;
@ -100,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = 0,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
// Don't want to allocate anything too huge for perf. This is at least larger than the default buffer.
var bufferSize = 1024 * 1024;
@ -146,7 +145,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = 1,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
var bufferSize = 1;
var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
@ -200,7 +199,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = maxResponseBufferSize,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
var bufferSize = maxResponseBufferSize - 1;
var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
@ -260,7 +259,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = maxResponseBufferSize,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
var bufferSize = maxResponseBufferSize / 2;
var data = new byte[bufferSize];
@ -328,7 +327,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = maxResponseBufferSize,
};
using (var socketOutput = CreateSocketOutput(pipeOptions, mockConnection))
using (var socketOutput = CreateOutputProducer(pipeOptions, mockConnection))
{
var bufferSize = maxResponseBufferSize - 1;
@ -400,7 +399,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = maxResponseBufferSize,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
var bufferSize = maxResponseBufferSize - 1;
var buffer = new ArraySegment<byte>(new byte[bufferSize], 0, bufferSize);
@ -458,7 +457,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
MaximumSizeLow = maxResponseBufferSize ?? 0,
};
using (var socketOutput = CreateSocketOutput(pipeOptions))
using (var socketOutput = CreateOutputProducer(pipeOptions))
{
_mockLibuv.KestrelThreadBlocker.Reset();
@ -487,46 +486,21 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
}
}
[Fact]
public async Task AllocCommitCanBeCalledAfterConnectionClose()
{
var pipeOptions = new PipeOptions
{
ReaderScheduler = _libuvThread,
};
using (var connection = new MockConnection())
{
var socketOutput = CreateSocketOutput(pipeOptions, connection);
// Close SocketOutput
socketOutput.Dispose();
await _mockLibuv.OnPostTask;
Assert.Equal(TaskStatus.RanToCompletion, connection.SocketClosed.Status);
var called = false;
((ISocketOutput)socketOutput).Write<object>((buffer, state) =>
{
called = true;
},
null);
Assert.False(called);
}
}
private OutputProducer CreateSocketOutput(PipeOptions pipeOptions, MockConnection connection = null)
private OutputProducer CreateOutputProducer(PipeOptions pipeOptions, MockConnection connection = null)
{
var pipe = _pipeFactory.Create(pipeOptions);
var serviceContext = new TestServiceContext();
var logger = new TestApplicationErrorLogger();
var serviceContext = new TestServiceContext() { Log = new TestKestrelTrace(logger) };
var transportContext = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
var frame = new Frame<object>(null, new FrameContext { ServiceContext = serviceContext });
var socket = new MockSocket(_mockLibuv, _libuvThread.Loop.ThreadId, serviceContext.TransportContext.Log);
var socket = new MockSocket(_mockLibuv, _libuvThread.Loop.ThreadId, transportContext.Log);
var socketOutput = new OutputProducer(pipe.Writer, frame, "0", serviceContext.Log);
var consumer = new LibuvOutputConsumer(pipe.Reader, _libuvThread, socket, connection ?? new MockConnection(), "0", serviceContext.TransportContext.Log);
var consumer = new LibuvOutputConsumer(pipe.Reader, _libuvThread, socket, connection ?? new MockConnection(), "0", transportContext.Log);
var ignore = consumer.StartWrites();
return socketOutput;

View File

@ -2,14 +2,13 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class LibuvTransportFactoryTests
{

View File

@ -2,10 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class LibuvTransportOptionsTests
{

View File

@ -0,0 +1,80 @@
// 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.Net;
using System.Net.Sockets;
using System.Text;
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.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
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() }
}
};
[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();
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task TransportCanBindUnbindAndStop(ListenOptions listenOptions)
{
var transportContext = new TestLibuvTransportContext();
var transport = new LibuvTransport(transportContext, listenOptions);
await transport.BindAsync();
await transport.UnbindAsync();
await transport.StopAsync();
}
[Theory]
[MemberData(nameof(ConnectionAdapterData))]
public async Task ConnectionCanReadAndWrite(ListenOptions listenOptions)
{
var transportContext = new TestLibuvTransportContext()
{
ConnectionHandler = new ConnectionHandler<HttpContext>(listenOptions, new TestServiceContext(), new DummyApplication(TestApp.EchoApp))
};
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);
}
}
await transport.UnbindAsync();
await transport.StopAsync();
}
}
}

View File

@ -9,15 +9,14 @@ 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.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Microsoft.Extensions.Logging;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class ListenerPrimaryTests
{
@ -28,14 +27,16 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var serviceContextPrimary = new TestServiceContext();
serviceContextPrimary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
var transportContextPrimary = new TestLibuvTransportContext();
transportContextPrimary.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
var serviceContextSecondary = new TestServiceContext();
serviceContextSecondary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
var transportContextSecondary = new TestLibuvTransportContext();
transportContextSecondary.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
var libuvTransport = new LibuvTransport(libuv, serviceContextPrimary.TransportContext, listenOptions);
var libuvTransport = new LibuvTransport(libuv, transportContextPrimary, listenOptions);
var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
var pipeMessage = Guid.NewGuid().ToByteArray();
@ -43,7 +44,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
// Start primary listener
var libuvThreadPrimary = new LibuvThread(libuvTransport);
await libuvThreadPrimary.StartAsync();
var listenerPrimary = new ListenerPrimary(serviceContextPrimary.TransportContext);
var listenerPrimary = new ListenerPrimary(transportContextPrimary);
await listenerPrimary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadPrimary);
var address = listenOptions.ToString();
@ -54,7 +55,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
// Add secondary listener
var libuvThreadSecondary = new LibuvThread(libuvTransport);
await libuvThreadSecondary.StartAsync();
var listenerSecondary = new ListenerSecondary(serviceContextSecondary.TransportContext);
var listenerSecondary = new ListenerSecondary(transportContextSecondary);
await listenerSecondary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadSecondary);
// Once a secondary listener is added, TCP connections start getting dispatched to it
@ -79,8 +80,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var libuv = new LibuvFunctions();
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var logger = new TestApplicationErrorLogger();
var serviceContextPrimary = new TestServiceContext();
serviceContextPrimary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
transportContextPrimary.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
var serviceContextSecondary = new TestServiceContext
@ -90,10 +94,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
};
serviceContextSecondary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
var transportContextSecondary = new TestLibuvTransportContext();
transportContextSecondary.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
var libuvTransport = new LibuvTransport(libuv, serviceContextPrimary.TransportContext, listenOptions);
var libuvTransport = new LibuvTransport(libuv, transportContextPrimary, listenOptions);
var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
var pipeMessage = Guid.NewGuid().ToByteArray();
@ -101,14 +106,14 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
// Start primary listener
var libuvThreadPrimary = new LibuvThread(libuvTransport);
await libuvThreadPrimary.StartAsync();
var listenerPrimary = new ListenerPrimary(serviceContextPrimary.TransportContext);
var listenerPrimary = new ListenerPrimary(transportContextPrimary);
await listenerPrimary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadPrimary);
var address = listenOptions.ToString();
// Add secondary listener
var libuvThreadSecondary = new LibuvThread(libuvTransport);
await libuvThreadSecondary.StartAsync();
var listenerSecondary = new ListenerSecondary(serviceContextSecondary.TransportContext);
var listenerSecondary = new ListenerSecondary(transportContextSecondary);
await listenerSecondary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadSecondary);
// TCP Connections get round-robined
@ -155,10 +160,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
await libuvThreadPrimary.PostAsync(_ => pipe.Dispose(), (object)null);
var primaryTrace = (TestKestrelTrace)serviceContextPrimary.Log;
// Wait up to 10 seconds for error to be logged
for (var i = 0; i < 10 && primaryTrace.Logger.TotalErrorsLogged == 0; i++)
for (var i = 0; i < 10 && logger.TotalErrorsLogged == 0; i++)
{
await Task.Delay(100);
}
@ -174,8 +177,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
await listenerPrimary.DisposeAsync();
await libuvThreadPrimary.StopAsync(TimeSpan.FromSeconds(1));
Assert.Equal(1, primaryTrace.Logger.TotalErrorsLogged);
var errorMessage = primaryTrace.Logger.Messages.First(m => m.LogLevel == LogLevel.Error);
Assert.Equal(1, logger.TotalErrorsLogged);
var errorMessage = logger.Messages.First(m => m.LogLevel == LogLevel.Error);
Assert.Equal(TestConstants.EOF, Assert.IsType<UvException>(errorMessage.Exception).StatusCode);
}
@ -186,8 +189,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
var libuv = new LibuvFunctions();
var listenOptions = new ListenOptions(new IPEndPoint(IPAddress.Loopback, 0));
var logger = new TestApplicationErrorLogger();
var serviceContextPrimary = new TestServiceContext();
serviceContextPrimary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
var transportContextPrimary = new TestLibuvTransportContext() { Log = new LibuvTrace(logger) };
transportContextPrimary.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextPrimary, new DummyApplication(c => c.Response.WriteAsync("Primary")));
var serviceContextSecondary = new TestServiceContext
@ -197,10 +203,11 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
ThreadPool = serviceContextPrimary.ThreadPool,
HttpParserFactory = serviceContextPrimary.HttpParserFactory,
};
serviceContextSecondary.TransportContext.ConnectionHandler = new ConnectionHandler<HttpContext>(
var transportContextSecondary = new TestLibuvTransportContext();
transportContextSecondary.ConnectionHandler = new ConnectionHandler<HttpContext>(
listenOptions, serviceContextSecondary, new DummyApplication(c => c.Response.WriteAsync("Secondary")));
var libuvTransport = new LibuvTransport(libuv, serviceContextPrimary.TransportContext, listenOptions);
var libuvTransport = new LibuvTransport(libuv, transportContextPrimary, listenOptions);
var pipeName = (libuv.IsWindows ? @"\\.\pipe\kestrel_" : "/tmp/kestrel_") + Guid.NewGuid().ToString("n");
var pipeMessage = Guid.NewGuid().ToByteArray();
@ -208,20 +215,18 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
// Start primary listener
var libuvThreadPrimary = new LibuvThread(libuvTransport);
await libuvThreadPrimary.StartAsync();
var listenerPrimary = new ListenerPrimary(serviceContextPrimary.TransportContext);
var listenerPrimary = new ListenerPrimary(transportContextPrimary);
await listenerPrimary.StartAsync(pipeName, pipeMessage, listenOptions, libuvThreadPrimary);
var address = listenOptions.ToString();
// Add secondary listener with wrong pipe message
var libuvThreadSecondary = new LibuvThread(libuvTransport);
await libuvThreadSecondary.StartAsync();
var listenerSecondary = new ListenerSecondary(serviceContextSecondary.TransportContext);
var listenerSecondary = new ListenerSecondary(transportContextSecondary);
await listenerSecondary.StartAsync(pipeName, Guid.NewGuid().ToByteArray(), listenOptions, libuvThreadSecondary);
var primaryTrace = (TestKestrelTrace)serviceContextPrimary.Log;
// Wait up to 10 seconds for error to be logged
for (var i = 0; i < 10 && primaryTrace.Logger.TotalErrorsLogged == 0; i++)
for (var i = 0; i < 10 && logger.TotalErrorsLogged == 0; i++)
{
await Task.Delay(100);
}
@ -237,8 +242,8 @@ namespace Microsoft.AspNetCore.Server.KestrelTests
await listenerPrimary.DisposeAsync();
await libuvThreadPrimary.StopAsync(TimeSpan.FromSeconds(1));
Assert.Equal(1, primaryTrace.Logger.TotalErrorsLogged);
var errorMessage = primaryTrace.Logger.Messages.First(m => m.LogLevel == LogLevel.Error);
Assert.Equal(1, logger.TotalErrorsLogged);
var errorMessage = logger.Messages.First(m => m.LogLevel == LogLevel.Error);
Assert.IsType<IOException>(errorMessage.Exception);
Assert.Contains("Bad data", errorMessage.Exception.ToString());
}

View File

@ -0,0 +1,35 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\build\common.props" />
<PropertyGroup>
<TargetFrameworks>netcoreapp2.0;net46</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks>
<PlatformTarget Condition="'$(TargetFramework)' == 'net46'">x64</PlatformTarget>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\shared\**\*.cs" />
<None Include="xunit.runner.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel.Core\Microsoft.AspNetCore.Server.Kestrel.Core.csproj" />
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv\Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Testing" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" />
<PackageReference Include="Moq" Version="$(MoqVersion)" />
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" />
<PackageReference Include="xunit" Version="$(XunitVersion)" />
</ItemGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
</Project>

View File

@ -6,14 +6,14 @@ using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class MultipleLoopTests
{

View File

@ -12,7 +12,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
/// <summary>
/// Summary description for NetworkingTests

View File

@ -4,11 +4,10 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNetCore.Testing
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{
public class MockConnection : LibuvConnection, IDisposable
{

View File

@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{
public class MockConnectionHandler : IConnectionHandler, IDisposable
{

View File

@ -6,7 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{
public class MockLibuv : LibuvFunctions
{

View File

@ -5,7 +5,7 @@ using System;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{
class MockSocket : UvStreamHandle
{

View File

@ -1,7 +1,7 @@
// 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.
namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{
public class TestConstants
{

View File

@ -0,0 +1,26 @@
// 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;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Testing;
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers
{
public class TestLibuvTransportContext : LibuvTransportContext
{
public TestLibuvTransportContext()
{
var logger = new TestApplicationErrorLogger();
AppLifetime = new LifetimeNotImplemented();
ConnectionHandler = new MockConnectionHandler();
Log = new LibuvTrace(logger);
Options = new LibuvTransportOptions
{
ThreadCount = 1,
ShutdownTimeout = TimeSpan.FromSeconds(5)
};
}
}
}

View File

@ -3,11 +3,11 @@
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests.TestHelpers;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class UvStreamHandleTests
{

View File

@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal.Networking;
using Microsoft.AspNetCore.Testing;
using Xunit;
namespace Microsoft.AspNetCore.Server.KestrelTests
namespace Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Tests
{
public class UvTimerHandleTests
{

View File

@ -0,0 +1,6 @@
{
"$schema": "http://json.schemastore.org/xunit.runner.schema",
"appDomain": "denied",
"methodDisplay": "method",
"longRunningTestSeconds": 60
}

View File

@ -33,6 +33,8 @@ namespace Microsoft.AspNetCore.Testing
Tuple.Create("/a%C3%A5a", "/a\u00E5a"),
Tuple.Create("/%C3%A5/bc", "/\u00E5/bc"),
Tuple.Create("/%25", "/%"),
Tuple.Create("/%25%30%30", "/%00"),
Tuple.Create("/%%2000", "/% 00"),
Tuple.Create("/%2F", "/%2F"),
Tuple.Create("http://host/abs/path", "/abs/path"),
Tuple.Create("http://host/abs/path/", "/abs/path/"),

View File

@ -4,7 +4,6 @@
using System;
using System.Collections.Concurrent;
using System.Linq;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.Extensions.Logging;

View File

@ -1,13 +1,10 @@
// 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;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv;
using Microsoft.AspNetCore.Server.Kestrel.Transport.Libuv.Internal;
namespace Microsoft.AspNetCore.Testing
{
@ -26,21 +23,8 @@ namespace Microsoft.AspNetCore.Testing
{
AddServerHeader = false
};
TransportContext = new LibuvTransportContext
{
AppLifetime = new LifetimeNotImplemented(),
Log = new LibuvTrace(logger),
Options = new LibuvTransportOptions
{
ThreadCount = 1,
ShutdownTimeout = TimeSpan.FromSeconds(5)
}
};
}
public string DateHeaderValue { get; }
public LibuvTransportContext TransportContext { get; }
}
}