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:
parent
26bd01337d
commit
f253dbc0c0
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
|
|
@ -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)" />
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
@ -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>
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
|
@ -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();
|
||||
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -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
|
||||
{
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/xunit.runner.schema",
|
||||
"appDomain": "denied",
|
||||
"methodDisplay": "method",
|
||||
"longRunningTestSeconds": 60
|
||||
}
|
||||
|
|
@ -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/"),
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue