Merge remote-tracking branch 'ServerTests/rybrande/release22ToSrc' into rybrande/Mondo2.2

This commit is contained in:
Ryan Brandenburg 2018-11-21 11:14:50 -08:00
commit 7a9e1f9ec9
33 changed files with 835 additions and 4070 deletions

View File

@ -1,7 +1,10 @@
<Project>
<Project>
<PropertyGroup>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.0' ">$(MicrosoftNETCoreApp20PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">$(MicrosoftNETCoreApp21PackageVersion)</RuntimeFrameworkVersion>
<RuntimeFrameworkVersion Condition=" '$(TargetFramework)' == 'netcoreapp2.2' ">$(MicrosoftNETCoreApp22PackageVersion)</RuntimeFrameworkVersion>
<NETStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard2.0' ">$(NETStandardLibrary20PackageVersion)</NETStandardImplicitPackageVersion>
<!-- aspnet/BuildTools#662 Don't police what version of NetCoreApp we use -->
<NETCoreAppMaximumVersion>99.9</NETCoreAppMaximumVersion>
</PropertyGroup>
</Project>

View File

@ -4,6 +4,8 @@ VisualStudioVersion = 15.0.27130.2036
MinimumVisualStudioVersion = 15.0.26730.03
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{49AB8AAA-8160-48DF-A18B-78F51E54E02A}"
ProjectSection(SolutionItems) = preProject
.appveyor.yml = .appveyor.yml
.travis.yml = .travis.yml
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
NuGet.config = NuGet.config
@ -20,6 +22,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{55694E45
ProjectSection(SolutionItems) = preProject
build\dependencies.props = build\dependencies.props
build\repo.props = build\repo.props
build\sources.props = build\sources.props
EndProjectSection
EndProject
Global

View File

@ -2,38 +2,33 @@
<PropertyGroup>
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<!-- These package versions may be overridden or updated by automation. -->
<PropertyGroup Label="Package Versions: Auto">
<InternalAspNetCoreSdkPackageVersion>2.1.3-rtm-15802</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAspNetCoreModulePackageVersion>2.1.1</MicrosoftAspNetCoreAspNetCoreModulePackageVersion>
<MicrosoftAspNetCoreAspNetCoreModuleV1PackageVersion>2.1.1</MicrosoftAspNetCoreAspNetCoreModuleV1PackageVersion>
<MicrosoftAspNetCoreResponseCompressionPackageVersion>2.1.1</MicrosoftAspNetCoreResponseCompressionPackageVersion>
<MicrosoftAspNetCoreServerHttpSysPackageVersion>2.1.1</MicrosoftAspNetCoreServerHttpSysPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.1.1</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerIISPackageVersion>2.1.1</MicrosoftAspNetCoreServerIISPackageVersion>
<MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>0.5.1</MicrosoftAspNetCoreServerIntegrationTestingPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.1.2</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.1.1</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.1.1</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.1</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.1.1</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.1.1</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.1.1</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.0</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.2</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.1.1</MicrosoftNetHttpHeadersPackageVersion>
<PropertyGroup Label="Package Versions">
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview2-20181004.6</InternalAspNetCoreSdkPackageVersion>
<MicrosoftAspNetCoreAspNetCoreModulePackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreAspNetCoreModulePackageVersion>
<MicrosoftAspNetCoreAspNetCoreModuleV2PackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreAspNetCoreModuleV2PackageVersion>
<MicrosoftAspNetCoreResponseCompressionPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreResponseCompressionPackageVersion>
<MicrosoftAspNetCoreServerHttpSysPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerHttpSysPackageVersion>
<MicrosoftAspNetCoreServerIISIntegrationPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerIISIntegrationPackageVersion>
<MicrosoftAspNetCoreServerIISPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerIISPackageVersion>
<MicrosoftAspNetCoreServerIntegrationTestingIISPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerIntegrationTestingIISPackageVersion>
<MicrosoftAspNetCoreServerKestrelPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreServerKestrelPackageVersion>
<MicrosoftAspNetCoreWebUtilitiesPackageVersion>2.2.0-preview3-35425</MicrosoftAspNetCoreWebUtilitiesPackageVersion>
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsConfigurationJsonPackageVersion>
<MicrosoftExtensionsLoggingConsolePackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingConsolePackageVersion>
<MicrosoftExtensionsLoggingPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingPackageVersion>
<MicrosoftExtensionsLoggingTestingPackageVersion>2.2.0-preview3-35425</MicrosoftExtensionsLoggingTestingPackageVersion>
<MicrosoftNETCoreApp20PackageVersion>2.0.9</MicrosoftNETCoreApp20PackageVersion>
<MicrosoftNETCoreApp21PackageVersion>2.1.3</MicrosoftNETCoreApp21PackageVersion>
<MicrosoftNETCoreApp22PackageVersion>2.2.0-preview3-27001-02</MicrosoftNETCoreApp22PackageVersion>
<MicrosoftNetHttpHeadersPackageVersion>2.2.0-preview3-35425</MicrosoftNetHttpHeadersPackageVersion>
<MicrosoftNETTestSdkPackageVersion>15.6.1</MicrosoftNETTestSdkPackageVersion>
<NETStandardLibrary20PackageVersion>2.0.3</NETStandardLibrary20PackageVersion>
<SerilogExtensionsLoggingPackageVersion>1.4.0</SerilogExtensionsLoggingPackageVersion>
<SerilogSinksFilePackageVersion>3.2.0</SerilogSinksFilePackageVersion>
<SerilogSinksFilePackageVersion>4.0.0</SerilogSinksFilePackageVersion>
<XunitPackageVersion>2.3.1</XunitPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
<XunitRunnerVisualStudioPackageVersion>2.4.0</XunitRunnerVisualStudioPackageVersion>
</PropertyGroup>
<!-- This may import a generated file which may override the variables above. -->
<Import Project="$(DotNetPackageVersionPropsPath)" Condition=" '$(DotNetPackageVersionPropsPath)' != '' " />
<!-- These are package versions that should not be overridden or updated by automation. -->
<PropertyGroup Label="Package Versions: Pinned" />
</Project>

View File

@ -7,12 +7,12 @@
<PropertyGroup>
<!-- These properties are use by the automation that updates dependencies.props -->
<LineupPackageId>Internal.AspNetCore.Universe.Lineup</LineupPackageId>
<LineupPackageVersion>2.1.0-rc1-*</LineupPackageVersion>
<LineupPackageVersion>2.2.0-*</LineupPackageVersion>
<LineupPackageRestoreSource>https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json</LineupPackageRestoreSource>
</PropertyGroup>
<ItemGroup>
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp20PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp21PackageVersion)" />
<DotNetCoreRuntime Include="$(MicrosoftNETCoreApp22PackageVersion)" />
<DotNetCoreRuntime Condition="'$(OS)' == 'Windows_NT'" Include="$(MicrosoftNETCoreApp22PackageVersion)" Arch="x86" />
</ItemGroup>
</Project>

View File

@ -1,6 +0,0 @@
#!/usr/bin/env bash
curl -sSL http://nginx.org/download/nginx-1.8.0.tar.gz | tar zxfv - -C /tmp && cd /tmp/nginx-1.8.0/
./configure --prefix=$HOME/nginxinstall --with-http_ssl_module
make
make install

View File

@ -1,118 +0,0 @@
// 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.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace ServerComparison.FunctionalTests
{
public class HelloWorldTests : LoggedTest
{
public HelloWorldTests(ITestOutputHelper output) : base(output)
{
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task HelloWorld_WebListener(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return HelloWorld(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
public Task HelloWorld_IISExpress(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return HelloWorld(ServerType.IISExpress, runtimeFlavor, RuntimeArchitecture.x64, applicationType, hostingModel: hostingModel, additionalPublishParameters: additionalPublishParameters);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
public Task HelloWorld_Kestrel_Clr(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return HelloWorld(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, applicationType);
}
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task HelloWorld_Kestrel(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return HelloWorld(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task HelloWorld_Nginx(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return HelloWorld(ServerType.Nginx, runtimeFlavor, RuntimeArchitecture.x64, applicationType);
}
private async Task HelloWorld(ServerType serverType,
RuntimeFlavor runtimeFlavor,
RuntimeArchitecture architecture,
ApplicationType applicationType,
[CallerMemberName] string testName = null,
HostingModel hostingModel = HostingModel.OutOfProcess,
string additionalPublishParameters = "")
{
testName = $"{testName}_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("HelloWorld");
var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture)
{
EnvironmentName = "HelloWorld", // Will pick the Start class named 'StartupHelloWorld',
ServerConfigTemplateContent = Helpers.GetConfigContent(serverType, "Http.config", "nginx.conf"),
SiteName = "HttpTestSite", // This is configured in the Http.config
TargetFramework = Helpers.GetTargetFramework(runtimeFlavor),
ApplicationType = applicationType,
HostingModel = hostingModel,
AdditionalPublishParameters = additionalPublishParameters
};
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
var response = await RetryHelper.RetryRequest(() =>
{
return deploymentResult.HttpClient.GetAsync(string.Empty);
}, logger, deploymentResult.HostShutdownToken);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Hello World", responseText);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
}
}
}
}

View File

@ -1,331 +0,0 @@
// 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 System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace ServerComparison.FunctionalTests
{
public class ResponseCompressionTests : LoggedTest
{
// NGinx's default min size is 20 bytes
private static readonly string HelloWorldBody = "Hello World;" + new string('a', 20);
public ResponseCompressionTests(ITestOutputHelper output) : base(output)
{
}
// IIS Express
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
public Task ResponseCompression_IISExpress_NoCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseCompression(ServerType.IISExpress,
runtimeFlavor,
RuntimeArchitecture.x64,
CheckNoCompressionAsync,
applicationType,
hostCompression: false,
hostingModel: hostingModel,
additionalPublishParameters: additionalPublishParameters);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
public Task ResponseCompression_IISExpress_HostCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseCompression(ServerType.IISExpress,
runtimeFlavor,
RuntimeArchitecture.x64,
CheckHostCompressionAsync,
applicationType,
hostCompression: true,
hostingModel: hostingModel,
additionalPublishParameters: additionalPublishParameters);
}
[ConditionalTheory(Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
public Task ResponseCompression_IISExpress_AppCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseCompression(ServerType.IISExpress,
runtimeFlavor,
RuntimeArchitecture.x64,
CheckAppCompressionAsync,
applicationType,
hostCompression: true,
hostingModel: hostingModel,
additionalPublishParameters: additionalPublishParameters);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
public Task ResponseCompression_IISExpress_AppAndHostCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseCompression(ServerType.IISExpress,
runtimeFlavor,
RuntimeArchitecture.x64,
CheckAppCompressionAsync,
applicationType,
hostCompression: true,
hostingModel: hostingModel,
additionalPublishParameters: additionalPublishParameters);
}
// WebListener
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseCompression_WebListener_NoCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseCompression(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckNoCompressionAsync, applicationType, hostCompression: false);
}
// WebListener doesn't support HostCompression
// "The archive entry was compressed using an unsupported compression method."
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseCompression_WebListener_AppCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseCompression(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckAppCompressionAsync, applicationType, hostCompression: false);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseCompression_WebListener_AppAndHostCompression(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseCompression(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckAppCompressionAsync, applicationType, hostCompression: true);
}
// Kestrel
[Theory]
[InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)]
public Task ResponseCompression_Kestrel_NoCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType)
{
return ResponseCompression(serverType, runtimeFlavor, architecture, CheckNoCompressionAsync, applicationType, hostCompression: false);
}
[Theory]
[InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)]
public Task ResponseCompression_Kestrel_AppCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType)
{
return ResponseCompression(serverType, runtimeFlavor, architecture, CheckAppCompressionAsync, applicationType, hostCompression: false);
}
// Nginx
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)]
public Task ResponseCompression_Nginx_NoCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType)
{
return ResponseCompression(serverType, runtimeFlavor, architecture, CheckNoCompressionAsync, applicationType, hostCompression: false);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)]
public Task ResponseCompression_Nginx_HostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType)
{
return ResponseCompression(serverType, runtimeFlavor, architecture, CheckHostCompressionAsync, applicationType, hostCompression: true);
}
[ConditionalTheory(Skip = "No pass-through compression https://github.com/aspnet/BasicMiddleware/issues/123")]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)]
public Task ResponseCompression_Nginx_AppCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType)
{
return ResponseCompression(serverType, runtimeFlavor, architecture, CheckHostCompressionAsync, applicationType, hostCompression: false);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)]
public Task ResponseCompression_Nginx_AppAndHostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType)
{
return ResponseCompression(serverType, runtimeFlavor, architecture, CheckAppCompressionAsync, applicationType, hostCompression: true);
}
private async Task ResponseCompression(ServerType serverType,
RuntimeFlavor runtimeFlavor,
RuntimeArchitecture architecture,
Func<HttpClient, ILogger, Task> scenario,
ApplicationType applicationType,
bool hostCompression,
[CallerMemberName] string testName = null,
HostingModel hostingModel = HostingModel.OutOfProcess,
string additionalPublishParameters = "")
{
testName = $"{testName}_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("ResponseCompression");
var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture)
{
EnvironmentName = "ResponseCompression",
ServerConfigTemplateContent = Helpers.GetConfigContent(serverType,
hostCompression ? "http.config" : "NoCompression.config",
hostCompression ? "nginx.conf" : "NoCompression.conf"),
SiteName = "HttpTestSite", // This is configured in the Http.config
TargetFramework = Helpers.GetTargetFramework(runtimeFlavor),
ApplicationType = applicationType,
HostingModel = hostingModel,
AdditionalPublishParameters = additionalPublishParameters
};
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
var httpClientHandler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.None };
Assert.True(httpClientHandler.SupportsAutomaticDecompression);
var httpClient = deploymentResult.CreateHttpClient(httpClientHandler);
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
var response = await RetryHelper.RetryRequest(() =>
{
return httpClient.GetAsync(string.Empty);
}, logger, deploymentResult.HostShutdownToken);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Running", responseText);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
await scenario(httpClient, logger);
}
}
}
private static async Task CheckNoCompressionAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing /NoAppCompression");
var request = new HttpRequestMessage(HttpMethod.Get, "NoAppCompression");
request.Headers.AcceptEncoding.ParseAdd("gzip,deflate");
var response = await client.SendAsync(request);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal(HelloWorldBody, responseText);
Assert.Equal(HelloWorldBody.Length.ToString(), GetContentLength(response));
Assert.Equal(0, response.Content.Headers.ContentEncoding.Count);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static Task CheckHostCompressionAsync(HttpClient client, ILogger logger)
{
return CheckCompressionAsync(client, "NoAppCompression", logger);
}
private static Task CheckAppCompressionAsync(HttpClient client, ILogger logger)
{
return CheckCompressionAsync(client, "AppCompression", logger);
}
private static async Task CheckCompressionAsync(HttpClient client, string url, ILogger logger)
{
// Manage the compression manually because HttpClient removes the Content-Encoding header when decompressing.
logger.LogInformation($"Testing /{url}");
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.AcceptEncoding.ParseAdd("gzip,deflate");
var response = await client.SendAsync(request);
var responseText = await response.Content.ReadAsStringAsync();
try
{
responseText = await ReadCompressedAsStringAsync(response.Content);
Assert.Equal(HelloWorldBody, responseText);
Assert.Equal(1, response.Content.Headers.ContentEncoding.Count);
Assert.Equal("gzip", response.Content.Headers.ContentEncoding.First());
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static string GetContentLength(HttpResponseMessage response)
{
// Don't use response.Content.Headers.ContentLength, it will dynamically calculate the value if it can.
return response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out var values) ? values.FirstOrDefault() : null;
}
private static async Task<string> ReadCompressedAsStringAsync(HttpContent content)
{
using (var stream = await content.ReadAsStreamAsync())
using (var compressStream = new GZipStream(stream, CompressionMode.Decompress))
using (var reader = new StreamReader(compressStream))
{
return await reader.ReadToEndAsync();
}
}
}
}

View File

@ -1,406 +0,0 @@
// 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 System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace ServerComparison.FunctionalTests
{
public class ResponseTests : LoggedTest
{
public ResponseTests(ITestOutputHelper output) : base(output)
{
}
// IIS Express
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable, HostingModel.OutOfProcess, "", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
public Task ResponseFormats_IISExpress_ContentLength(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseFormats(ServerType.IISExpress, runtimeFlavor, RuntimeArchitecture.x64, CheckContentLengthAsync, applicationType, hostingModel: hostingModel, additionalPublishParameters: additionalPublishParameters);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable, HostingModel.OutOfProcess, "", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
public Task ResponseFormats_IISExpress_Chunked(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseFormats(ServerType.IISExpress, runtimeFlavor, RuntimeArchitecture.x64, CheckChunkedAsync, applicationType, hostingModel: hostingModel, additionalPublishParameters: additionalPublishParameters);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable, HostingModel.OutOfProcess, "", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
public Task ResponseFormats_IIS_ManuallyChunk(RuntimeFlavor runtimeFlavor, ApplicationType applicationType, HostingModel hostingModel, string additionalPublishParameters)
{
return ResponseFormats(ServerType.IISExpress, runtimeFlavor, RuntimeArchitecture.x64, CheckManuallyChunkedAsync, applicationType, hostingModel: hostingModel, additionalPublishParameters: additionalPublishParameters);
}
// Weblistener
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_WebListener_ContentLength(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckContentLengthAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_WebListener_Chunked(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckChunkedAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
// IIS will remove the "Connection: close" header https://github.com/aspnet/IISIntegration/issues/7
public Task ResponseFormats_WebListener_Http10ConnectionClose(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckHttp10ConnectionCloseAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)] // https://github.com/aspnet/WebListener/issues/259
// IIS will remove the "Connection: close" header https://github.com/aspnet/IISIntegration/issues/7
public Task ResponseFormats_WebListener_Http11ConnectionClose(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckHttp11ConnectionCloseAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_WebListener_ManuallyChunk(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckManuallyChunkedAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(RuntimeFlavor.Clr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_WebListener_ManuallyChunkAndClose(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.WebListener, runtimeFlavor, RuntimeArchitecture.x64, CheckManuallyChunkedAndCloseAsync, applicationType);
}
// Kestrel
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Kestrel_ContentLength(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, CheckContentLengthAsync, applicationType);
}
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Kestrel_Http10ConnectionClose(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, CheckHttp10ConnectionCloseAsync, applicationType);
}
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Kestrel_Http11ConnectionClose(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, CheckHttp11ConnectionCloseAsync, applicationType);
}
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Kestrel_Chunked(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, CheckChunkedAsync, applicationType);
}
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Kestrel_ManuallyChunk(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, CheckManuallyChunkedAsync, applicationType);
}
[Theory]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Kestrel_ManuallyChunkAndClose(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Kestrel, runtimeFlavor, RuntimeArchitecture.x64, CheckManuallyChunkedAndCloseAsync, applicationType);
}
// Nginx
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Nginx_ContentLength( RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Nginx, runtimeFlavor, RuntimeArchitecture.x64, CheckContentLengthAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Nginx_Chunked(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Nginx, runtimeFlavor, RuntimeArchitecture.x64, CheckChunkedAsync, applicationType);
}
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Windows)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Portable)]
[InlineData(RuntimeFlavor.CoreClr, ApplicationType.Standalone)]
public Task ResponseFormats_Nginx_ManuallyChunk(RuntimeFlavor runtimeFlavor, ApplicationType applicationType)
{
return ResponseFormats(ServerType.Nginx, runtimeFlavor, RuntimeArchitecture.x64, CheckManuallyChunkedAsync, applicationType);
}
private async Task ResponseFormats(ServerType serverType,
RuntimeFlavor runtimeFlavor,
RuntimeArchitecture architecture,
Func<HttpClient, ILogger, Task> scenario,
ApplicationType applicationType,
[CallerMemberName] string testName = null,
HostingModel hostingModel = HostingModel.OutOfProcess,
string additionalPublishParameters = "")
{
testName = $"{testName}_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("ResponseFormats");
var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture)
{
EnvironmentName = "Responses",
ServerConfigTemplateContent = Helpers.GetConfigContent(serverType, "Http.config", "nginx.conf"),
SiteName = "HttpTestSite", // This is configured in the Http.config
TargetFramework = Helpers.GetTargetFramework(runtimeFlavor),
ApplicationType = applicationType,
HostingModel = hostingModel,
AdditionalPublishParameters = additionalPublishParameters
};
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
var response = await RetryHelper.RetryRequest(() =>
{
return deploymentResult.HttpClient.GetAsync(string.Empty);
}, logger, deploymentResult.HostShutdownToken);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Running", responseText);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
await scenario(deploymentResult.HttpClient, logger);
}
}
}
private static async Task CheckContentLengthAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing ContentLength");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "contentlength")
{
Version = new Version(1, 1)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Content Length", responseText);
Assert.Null(response.Headers.TransferEncodingChunked);
Assert.Null(response.Headers.ConnectionClose);
Assert.Equal("14", GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckHttp11ConnectionCloseAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing Http11ConnectionClose");
var response = await client.GetAsync("connectionclose");
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Connnection Close", responseText);
Assert.True(response.Headers.ConnectionClose, "/connectionclose, closed?");
Assert.True(response.Headers.TransferEncodingChunked);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckHttp10ConnectionCloseAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing Http10ConnectionClose");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "connectionclose")
{
Version = new Version(1, 0)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Connnection Close", responseText);
Assert.True(response.Headers.ConnectionClose, "/connectionclose, closed?");
Assert.Null(response.Headers.TransferEncodingChunked);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckChunkedAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing Chunked");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "chunked")
{
Version = new Version(1, 1)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Chunked", responseText);
Assert.True(response.Headers.TransferEncodingChunked, "/chunked, chunked?");
Assert.Null(response.Headers.ConnectionClose);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckManuallyChunkedAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing ManuallyChunked");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "manuallychunked")
{
Version = new Version(1, 1)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Manually Chunked", responseText);
Assert.True(response.Headers.TransferEncodingChunked, "/manuallychunked, chunked?");
Assert.Null(response.Headers.ConnectionClose);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckManuallyChunkedAndCloseAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing ManuallyChunkedAndClose");
var response = await client.GetAsync("manuallychunkedandclose");
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Manually Chunked and Close", responseText);
Assert.True(response.Headers.TransferEncodingChunked, "/manuallychunkedandclose, chunked?");
Assert.True(response.Headers.ConnectionClose, "/manuallychunkedandclose, closed?");
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static string GetContentLength(HttpResponseMessage response)
{
// Don't use response.Content.Headers.ContentLength, it will dynamically calculate the value if it can.
IEnumerable<string> values;
return response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out values) ? values.FirstOrDefault() : null;
}
}
}

View File

@ -1,9 +0,0 @@
<?xml version="1.0"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true"/>
</system.webServer>
</configuration>

View File

@ -1,8 +1,8 @@
<Project>
<Project>
<Import Project="..\Directory.Build.props" />
<PropertyGroup>
<DeveloperBuildTestTfms>netcoreapp2.1;netcoreapp2.0</DeveloperBuildTestTfms>
<DeveloperBuildTestTfms>netcoreapp2.2</DeveloperBuildTestTfms>
<StandardTestTfms>$(DeveloperBuildTestTfms)</StandardTestTfms>
<StandardTestTfms Condition=" '$(DeveloperBuild)' != 'true' AND '$(OS)' == 'Windows_NT' ">$(StandardTestTfms);net461</StandardTestTfms>
</PropertyGroup>

View File

@ -0,0 +1,109 @@
// 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 System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace ServerComparison.FunctionalTests
{
public class HelloWorldTests : LoggedTest
{
public HelloWorldTests(ITestOutputHelper output) : base(output)
{
}
public static TestMatrix TestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.Kestrel, ServerType.Nginx, ServerType.HttpSys)
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
.WithAllApplicationTypes()
.WithAllAncmVersions()
.WithAllHostingModels()
.WithAllArchitectures();
[ConditionalTheory]
[MemberData(nameof(TestVariants))]
public async Task HelloWorld(TestVariant variant)
{
var testName = $"HelloWorld_{variant.Server}_{variant.Tfm}_{variant.Architecture}_{variant.ApplicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("HelloWorld");
var deploymentParameters = new DeploymentParameters(variant)
{
ApplicationPath = Helpers.GetApplicationPath()
};
if (variant.Server == ServerType.Nginx)
{
deploymentParameters.ServerConfigTemplateContent = Helpers.GetNginxConfigContent("nginx.conf");
}
using (var deployer = IISApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
var response = await RetryHelper.RetryRequest(() =>
{
return deploymentResult.HttpClient.GetAsync(string.Empty);
}, logger, deploymentResult.HostShutdownToken);
var responseText = await response.Content.ReadAsStringAsync();
try
{
if (variant.Architecture == RuntimeArchitecture.x64)
{
Assert.Equal("Hello World X64", responseText);
}
else
{
Assert.Equal("Hello World X86", responseText);
}
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
// Make sure it was the right server.
var serverHeader = response.Headers.Server.ToString();
switch (variant.Server)
{
case ServerType.HttpSys:
Assert.Equal("Microsoft-HTTPAPI/2.0", serverHeader);
break;
case ServerType.Nginx:
Assert.StartsWith("nginx/", serverHeader);
break;
case ServerType.Kestrel:
Assert.Equal("Kestrel", serverHeader);
break;
case ServerType.IIS:
case ServerType.IISExpress:
if (variant.HostingModel == HostingModel.OutOfProcess)
{
Assert.Equal("Kestrel", serverHeader);
}
else
{
Assert.StartsWith("Microsoft-IIS/", serverHeader);
}
break;
default:
throw new NotImplementedException(variant.Server.ToString());
}
}
}
}
}
}

View File

@ -9,7 +9,7 @@ namespace ServerComparison.FunctionalTests
{
public class Helpers
{
public static string GetApplicationPath(ApplicationType applicationType)
public static string GetApplicationPath()
{
var applicationBasePath = AppContext.BaseDirectory;
@ -29,41 +29,11 @@ namespace ServerComparison.FunctionalTests
throw new Exception($"Solution root could not be found using {applicationBasePath}");
}
public static string GetConfigContent(ServerType serverType, string iisConfig, string nginxConfig)
public static string GetNginxConfigContent(string nginxConfig)
{
var applicationBasePath = AppContext.BaseDirectory;
string content = null;
if (serverType == ServerType.IISExpress)
{
content = File.ReadAllText(Path.Combine(applicationBasePath, iisConfig));
}
else if (serverType == ServerType.Nginx)
{
content = File.ReadAllText(Path.Combine(applicationBasePath, nginxConfig));
}
var content = File.ReadAllText(Path.Combine(applicationBasePath, nginxConfig));
return content;
}
public static string GetTargetFramework(RuntimeFlavor runtimeFlavor)
{
if (runtimeFlavor == RuntimeFlavor.Clr)
{
return "net461";
}
else if (runtimeFlavor == RuntimeFlavor.CoreClr)
{
#if NETCOREAPP2_0
return "netcoreapp2.0";
#elif NETCOREAPP2_1 || NET461
return "netcoreapp2.1";
#else
#error Target frameworks need to be updated.
#endif
}
throw new ArgumentException($"Unknown RuntimeFlavor '{runtimeFlavor}'");
}
}
}

View File

@ -20,46 +20,28 @@ namespace ServerComparison.FunctionalTests
{
}
public static TestMatrix TestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.HttpSys)
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
.WithAllAncmVersions()
.WithAllHostingModels();
[ConditionalTheory]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
[InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, "net461", RuntimeArchitecture.x64, ApplicationType.Portable, HostingModel.OutOfProcess, "V2", Skip = "Websdk issue with full framework publish. See https://github.com/aspnet/websdk/pull/322")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.1", RuntimeArchitecture.x64, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.1", RuntimeArchitecture.x64, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.1", RuntimeArchitecture.x64, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.1", RuntimeArchitecture.x64, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.0", RuntimeArchitecture.x64, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.0", RuntimeArchitecture.x64, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V2")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.0", RuntimeArchitecture.x64, ApplicationType.Portable, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, "netcoreapp2.0", RuntimeArchitecture.x64, ApplicationType.Standalone, HostingModel.OutOfProcess, "/p:ANCMVersion=V1")]
[InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, "netcoreapp2.0", RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, "netcoreapp2.1", RuntimeArchitecture.x64, ApplicationType.Portable)]
[InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, "netcoreapp2.0", RuntimeArchitecture.x64, ApplicationType.Standalone)]
[InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, "netcoreapp2.1", RuntimeArchitecture.x64, ApplicationType.Standalone)]
public async Task NtlmAuthentication(ServerType serverType,
RuntimeFlavor runtimeFlavor,
string targetFramework,
RuntimeArchitecture architecture,
ApplicationType applicationType,
HostingModel hostingModel = HostingModel.OutOfProcess,
string additionalPublishParameters = "")
[MemberData(nameof(TestVariants))]
public async Task NtlmAuthentication(TestVariant variant)
{
var testName = $"NtlmAuthentication_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}";
var testName = $"NtlmAuthentication_{variant.Server}_{variant.Tfm}_{variant.Architecture}_{variant.ApplicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("NtlmAuthenticationTest");
var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture)
var deploymentParameters = new DeploymentParameters(variant)
{
ApplicationPath = Helpers.GetApplicationPath(),
EnvironmentName = "NtlmAuthentication", // Will pick the Start class named 'StartupNtlmAuthentication'
ServerConfigTemplateContent = Helpers.GetConfigContent(serverType, "NtlmAuthentication.config", nginxConfig: null),
SiteName = "NtlmAuthenticationTestSite", // This is configured in the NtlmAuthentication.config
TargetFramework = targetFramework,
ApplicationType = applicationType,
HostingModel = hostingModel,
AdditionalPublishParameters = additionalPublishParameters
};
using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
using (var deployer = IISApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
var httpClient = deploymentResult.HttpClient;

View File

@ -0,0 +1,234 @@
// 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 System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Server.IntegrationTesting.IIS;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace ServerComparison.FunctionalTests
{
public class ResponseCompressionTests : LoggedTest
{
// NGinx's default min size is 20 bytes
private static readonly string HelloWorldBody = "Hello World;" + new string('a', 20);
public ResponseCompressionTests(ITestOutputHelper output) : base(output)
{
}
public static TestMatrix NoCompressionTestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.Kestrel, ServerType.Nginx, ServerType.HttpSys)
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
.WithAllAncmVersions()
.WithAllHostingModels();
[ConditionalTheory]
[MemberData(nameof(NoCompressionTestVariants))]
public Task ResponseCompression_NoCompression(TestVariant variant)
{
return ResponseCompression(variant, CheckNoCompressionAsync, hostCompression: false);
}
public static TestMatrix HostCompressionTestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.Nginx)
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
.WithAllAncmVersions()
.WithAllHostingModels();
[ConditionalTheory]
[MemberData(nameof(HostCompressionTestVariants))]
public Task ResponseCompression_HostCompression(TestVariant variant)
{
return ResponseCompression(variant, CheckHostCompressionAsync, hostCompression: true);
}
public static TestMatrix AppCompressionTestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.Kestrel, ServerType.HttpSys) // No pass-through compression for nginx
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
.WithAllAncmVersions()
.WithAllHostingModels();
[ConditionalTheory]
[MemberData(nameof(AppCompressionTestVariants))]
public Task ResponseCompression_AppCompression(TestVariant variant)
{
return ResponseCompression(variant, CheckAppCompressionAsync, hostCompression: false);
}
public static TestMatrix HostAndAppCompressionTestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.Kestrel, ServerType.Nginx, ServerType.HttpSys)
.WithTfms(Tfm.NetCoreApp22, Tfm.Net461)
.WithAllAncmVersions()
.WithAllHostingModels();
[ConditionalTheory]
[MemberData(nameof(HostAndAppCompressionTestVariants))]
public Task ResponseCompression_AppAndHostCompression(TestVariant variant)
{
return ResponseCompression(variant, CheckAppCompressionAsync, hostCompression: true);
}
private async Task ResponseCompression(TestVariant variant,
Func<HttpClient, ILogger, Task> scenario,
bool hostCompression,
[CallerMemberName] string testName = null)
{
testName = $"{testName}_{variant.Server}_{variant.Tfm}_{variant.Architecture}_{variant.ApplicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("ResponseCompression");
var deploymentParameters = new DeploymentParameters(variant)
{
ApplicationPath = Helpers.GetApplicationPath(),
EnvironmentName = "ResponseCompression",
};
if (variant.Server == ServerType.Nginx)
{
deploymentParameters.ServerConfigTemplateContent = hostCompression
? Helpers.GetNginxConfigContent("nginx.conf")
: Helpers.GetNginxConfigContent("NoCompression.conf");
}
else if (variant.Server == ServerType.IISExpress && !hostCompression)
{
var iisDeploymentParameters = new IISDeploymentParameters(deploymentParameters);
iisDeploymentParameters.ServerConfigActionList.Add(
(element, _) => {
var compressionElement = element
.RequiredElement("system.webServer")
.RequiredElement("httpCompression");
compressionElement
.RequiredElement("dynamicTypes")
.Elements()
.SkipLast(1)
.Remove();
compressionElement
.RequiredElement("staticTypes")
.Elements()
.SkipLast(1)
.Remove();
// last element in both dynamicTypes and staticTypes disables compression
// <add mimeType="*/*" enabled="false" />
});
deploymentParameters = iisDeploymentParameters;
}
using (var deployer = IISApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
var httpClientHandler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.None };
Assert.True(httpClientHandler.SupportsAutomaticDecompression);
var httpClient = deploymentResult.CreateHttpClient(httpClientHandler);
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
var response = await RetryHelper.RetryRequest(() =>
{
return httpClient.GetAsync(string.Empty);
}, logger, deploymentResult.HostShutdownToken);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Running", responseText);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
await scenario(httpClient, logger);
}
}
}
private static async Task CheckNoCompressionAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing /NoAppCompression");
var request = new HttpRequestMessage(HttpMethod.Get, "NoAppCompression");
request.Headers.AcceptEncoding.ParseAdd("gzip,deflate");
var response = await client.SendAsync(request);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal(HelloWorldBody, responseText);
Assert.Equal(HelloWorldBody.Length.ToString(), GetContentLength(response));
Assert.Equal(0, response.Content.Headers.ContentEncoding.Count);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static Task CheckHostCompressionAsync(HttpClient client, ILogger logger)
{
return CheckCompressionAsync(client, "NoAppCompression", logger);
}
private static Task CheckAppCompressionAsync(HttpClient client, ILogger logger)
{
return CheckCompressionAsync(client, "AppCompression", logger);
}
private static async Task CheckCompressionAsync(HttpClient client, string url, ILogger logger)
{
// Manage the compression manually because HttpClient removes the Content-Encoding header when decompressing.
logger.LogInformation($"Testing /{url}");
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.AcceptEncoding.ParseAdd("gzip,deflate");
var response = await client.SendAsync(request);
var responseText = await response.Content.ReadAsStringAsync();
try
{
responseText = await ReadCompressedAsStringAsync(response.Content);
Assert.Equal(HelloWorldBody, responseText);
Assert.Equal(1, response.Content.Headers.ContentEncoding.Count);
Assert.Equal("gzip", response.Content.Headers.ContentEncoding.First());
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static string GetContentLength(HttpResponseMessage response)
{
// Don't use response.Content.Headers.ContentLength, it will dynamically calculate the value if it can.
return response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out var values) ? values.FirstOrDefault() : null;
}
private static async Task<string> ReadCompressedAsStringAsync(HttpContent content)
{
using (var stream = await content.ReadAsStreamAsync())
using (var compressStream = new GZipStream(stream, CompressionMode.Decompress))
using (var reader = new StreamReader(compressStream))
{
return await reader.ReadToEndAsync();
}
}
}
}

View File

@ -0,0 +1,272 @@
// 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 System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Server.IntegrationTesting;
using Microsoft.AspNetCore.Testing.xunit;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Net.Http.Headers;
using Xunit;
using Xunit.Abstractions;
using Xunit.Sdk;
namespace ServerComparison.FunctionalTests
{
public class ResponseTests : LoggedTest
{
public ResponseTests(ITestOutputHelper output) : base(output)
{
}
public static TestMatrix TestVariants
=> TestMatrix.ForServers(ServerType.IISExpress, ServerType.Kestrel, ServerType.Nginx, ServerType.HttpSys)
.WithTfms(Tfm.NetCoreApp22)
.WithAllAncmVersions()
.WithAllHostingModels();
[ConditionalTheory]
[MemberData(nameof(TestVariants))]
public Task ResponseFormats_ContentLength(TestVariant variant)
{
return ResponseFormats(variant, CheckContentLengthAsync);
}
[ConditionalTheory]
[MemberData(nameof(TestVariants))]
public Task ResponseFormats_Chunked(TestVariant variant)
{
return ResponseFormats(variant, CheckChunkedAsync);
}
[ConditionalTheory]
[MemberData(nameof(TestVariants))]
public Task ResponseFormats_ManuallyChunk(TestVariant variant)
{
return ResponseFormats(variant, CheckManuallyChunkedAsync);
}
public static TestMatrix SelfhostTestVariants
=> TestMatrix.ForServers(ServerType.Kestrel, ServerType.HttpSys)
.WithTfms(Tfm.NetCoreApp22);
// Connection Close tests do not work through reverse proxies
[ConditionalTheory]
[MemberData(nameof(SelfhostTestVariants))]
public Task ResponseFormats_Http10ConnectionClose(TestVariant variant)
{
return ResponseFormats(variant, CheckHttp10ConnectionCloseAsync);
}
[ConditionalTheory]
[MemberData(nameof(SelfhostTestVariants))]
public Task ResponseFormats_Http11ConnectionClose(TestVariant variant)
{
return ResponseFormats(variant, CheckHttp11ConnectionCloseAsync);
}
[ConditionalTheory]
[MemberData(nameof(SelfhostTestVariants))]
public Task ResponseFormats_ManuallyChunkAndClose(TestVariant variant)
{
return ResponseFormats(variant, CheckManuallyChunkedAndCloseAsync);
}
private async Task ResponseFormats(TestVariant variant, Func<HttpClient, ILogger, Task> scenario, [CallerMemberName] string testName = null)
{
testName = $"{testName}_{variant.Server}_{variant.Tfm}_{variant.Architecture}_{variant.ApplicationType}";
using (StartLog(out var loggerFactory, testName))
{
var logger = loggerFactory.CreateLogger("ResponseFormats");
var deploymentParameters = new DeploymentParameters(variant)
{
ApplicationPath = Helpers.GetApplicationPath(),
EnvironmentName = "Responses"
};
if (variant.Server == ServerType.Nginx)
{
deploymentParameters.ServerConfigTemplateContent = Helpers.GetNginxConfigContent("nginx.conf");
}
using (var deployer = IISApplicationDeployerFactory.Create(deploymentParameters, loggerFactory))
{
var deploymentResult = await deployer.DeployAsync();
// Request to base address and check if various parts of the body are rendered & measure the cold startup time.
var response = await RetryHelper.RetryRequest(() =>
{
return deploymentResult.HttpClient.GetAsync(string.Empty);
}, logger, deploymentResult.HostShutdownToken);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Running", responseText);
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
await scenario(deploymentResult.HttpClient, logger);
}
}
}
private static async Task CheckContentLengthAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing ContentLength");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "contentlength")
{
Version = new Version(1, 1)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Content Length", responseText);
Assert.Null(response.Headers.TransferEncodingChunked);
Assert.Null(response.Headers.ConnectionClose);
Assert.Equal("14", GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckHttp11ConnectionCloseAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing Http11ConnectionClose");
var response = await client.GetAsync("connectionclose");
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Connnection Close", responseText);
Assert.True(response.Headers.ConnectionClose, "/connectionclose, closed?");
Assert.True(response.Headers.TransferEncodingChunked);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckHttp10ConnectionCloseAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing Http10ConnectionClose");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "connectionclose")
{
Version = new Version(1, 0)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Connnection Close", responseText);
Assert.True(response.Headers.ConnectionClose, "/connectionclose, closed?");
Assert.Null(response.Headers.TransferEncodingChunked);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckChunkedAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing Chunked");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "chunked")
{
Version = new Version(1, 1)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Chunked", responseText);
Assert.True(response.Headers.TransferEncodingChunked, "/chunked, chunked?");
Assert.Null(response.Headers.ConnectionClose);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckManuallyChunkedAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing ManuallyChunked");
var requestMessage = new HttpRequestMessage(HttpMethod.Get, "manuallychunked")
{
Version = new Version(1, 1)
};
var response = await client.SendAsync(requestMessage);
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Manually Chunked", responseText);
Assert.True(response.Headers.TransferEncodingChunked, "/manuallychunked, chunked?");
Assert.Null(response.Headers.ConnectionClose);
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static async Task CheckManuallyChunkedAndCloseAsync(HttpClient client, ILogger logger)
{
logger.LogInformation("Testing ManuallyChunkedAndClose");
var response = await client.GetAsync("manuallychunkedandclose");
var responseText = await response.Content.ReadAsStringAsync();
try
{
Assert.Equal("Manually Chunked and Close", responseText);
Assert.True(response.Headers.TransferEncodingChunked, "/manuallychunkedandclose, chunked?");
Assert.True(response.Headers.ConnectionClose, "/manuallychunkedandclose, closed?");
Assert.Null(GetContentLength(response));
}
catch (XunitException)
{
logger.LogWarning(response.ToString());
logger.LogWarning(responseText);
throw;
}
}
private static string GetContentLength(HttpResponseMessage response)
{
// Don't use response.Content.Headers.ContentLength, it will dynamically calculate the value if it can.
IEnumerable<string> values;
return response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out values) ? values.FirstOrDefault() : null;
}
}
}

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- Use 2.1 to run the tests. The tests will select their own TFMs for the test application when publishing -->
<TargetFramework>netcoreapp2.1</TargetFramework>
<!-- Use 2.2 to run the tests. The tests will select their own TFMs for the test application when publishing -->
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
@ -11,7 +11,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftNETTestSdkPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting" Version="$(MicrosoftAspNetCoreServerIntegrationTestingPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.IntegrationTesting.IIS" Version="$(MicrosoftAspNetCoreServerIntegrationTestingIISPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="$(MicrosoftExtensionsLoggingPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Testing" Version="$(MicrosoftExtensionsLoggingTestingPackageVersion)" />
<PackageReference Include="Microsoft.Net.Http.Headers" Version="$(MicrosoftNetHttpHeadersPackageVersion)" />

View File

@ -53,8 +53,9 @@ namespace ServerComparison.TestSites
// Check that we are not using IIS inproc before we add Kestrel.
builder.UseKestrel();
}
builder.UseIISIntegration();
builder.UseIIS();
var host = builder.Build();

View File

@ -5,17 +5,15 @@
<RuntimeIdentifiers>win7-x86;win7-x64;linux-x64;osx-x64</RuntimeIdentifiers>
</PropertyGroup>
<ItemGroup Condition="'$(OS)' == 'Windows_NT' AND ('$(ANCMVersion)' == 'V2' Or '$(ANCMVersion)' == '')">
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
<PackageReference Include="Microsoft.AspNetCore.AspNetCoreModule" Version="$(MicrosoftAspNetCoreAspNetCoreModulePackageVersion)" />
</ItemGroup>
<ItemGroup Condition="'$(OS)' == 'Windows_NT' AND ('$(ANCMVersion)' == 'V1')">
<PackageReference Include="Microsoft.AspNetCore.AspNetCoreModuleV1" Version="$(MicrosoftAspNetCoreAspNetCoreModuleV1PackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.AspNetCoreModuleV2" Version="$(MicrosoftAspNetCoreAspNetCoreModuleV2PackageVersion)" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="$(MicrosoftAspNetCoreResponseCompressionPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.HttpSys" Version="$(MicrosoftAspNetCoreServerHttpSysPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.IIS" Version="$(MicrosoftAspNetCoreServerIISPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="$(MicrosoftAspNetCoreServerIISIntegrationPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="$(MicrosoftAspNetCoreServerKestrelPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="$(MicrosoftAspNetCoreWebUtilitiesPackageVersion)" />

View File

@ -1,19 +1,20 @@
// 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.Runtime.InteropServices;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace ServerComparison.TestSites
{
public class StartupHelloWorld
public class Startup
{
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.Run(ctx =>
{
return ctx.Response.WriteAsync("Hello World");
return ctx.Response.WriteAsync("Hello World " + RuntimeInformation.ProcessArchitecture);
});
}
}

View File

@ -0,0 +1,39 @@
<!--
IIS Asp.Net Core Extension Schema
** Please DO NOT edit this file yourself. **
If you want to add configuration sections to the schema, you may place
them in .xml files similar to this one, in this directory. They will be
picked up automatically on startup.
-->
<configSchema>
<sectionSchema name="system.webServer/aspNetCore">
<attribute name="processPath" type="string" expanded="true"/>
<attribute name="arguments" type="string" expanded="true" defaultValue=""/>
<attribute name="startupTimeLimit" type="uint" defaultValue="120" validationType="integerRange" validationParameter="0,3600"/> <!-- in seconds -->
<attribute name="shutdownTimeLimit" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,600"/> <!-- in seconds -->
<attribute name="rapidFailsPerMinute" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,100"/>
<attribute name="requestTimeout" type="timeSpan" defaultValue="00:02:00" validationType="timeSpanRange" validationParameter="0,1296000,60"/>
<attribute name="stdoutLogEnabled" type="bool" defaultValue="false" />
<attribute name="stdoutLogFile" type="string" defaultValue=".\aspnetcore-stdout" expanded="true"/>
<attribute name="processesPerApplication" type="uint" defaultValue="1" validationType="integerRange" validationParameter="1,100"/>
<attribute name="forwardWindowsAuthToken" type="bool" defaultValue="true" />
<attribute name="disableStartUpErrorPage" type="bool" defaultValue="false" />
<attribute name="hostingModel" type="string" />
<element name="recycleOnFileChange">
<collection addElement="file" clearElement="clear">
<attribute name="path" type="string" required="true" validationType="nonEmptyString" expanded="true"/>
</collection>
</element>
<element name="environmentVariables">
<collection addElement="environmentVariable" clearElement="clear" >
<attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
<attribute name="value" type="string" required="true"/>
</collection>
</element>
</sectionSchema>
</configSchema>

View File

@ -0,0 +1,47 @@
<!--
IIS Asp.Net Core Extension Schema
** Please DO NOT edit this file yourself. **
If you want to add configuration sections to the schema, you may place
them in .xml files similar to this one, in this directory. They will be
picked up automatically on startup.
-->
<configSchema>
<sectionSchema name="system.webServer/aspNetCore">
<attribute name="processPath" type="string" expanded="true"/>
<attribute name="arguments" type="string" expanded="true" defaultValue=""/>
<attribute name="startupTimeLimit" type="uint" defaultValue="120" validationType="integerRange" validationParameter="0,3600"/>
<!-- in seconds -->
<attribute name="shutdownTimeLimit" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,600"/>
<!-- in seconds -->
<attribute name="rapidFailsPerMinute" type="uint" defaultValue="10" validationType="integerRange" validationParameter="0,100"/>
<attribute name="requestTimeout" type="timeSpan" defaultValue="00:02:00" validationType="timeSpanRange" validationParameter="0,1296000,1"/>
<attribute name="stdoutLogEnabled" type="bool" defaultValue="false" />
<attribute name="stdoutLogFile" type="string" defaultValue=".\aspnetcore-stdout" expanded="true"/>
<attribute name="processesPerApplication" type="uint" defaultValue="1" validationType="integerRange" validationParameter="1,100"/>
<attribute name="forwardWindowsAuthToken" type="bool" defaultValue="true" />
<attribute name="disableStartUpErrorPage" type="bool" defaultValue="false" />
<attribute name="hostingModel" type="string" />
<element name="recycleOnFileChange">
<collection addElement="file" clearElement="clear">
<attribute name="path" type="string" required="true" validationType="nonEmptyString" expanded="true"/>
</collection>
</element>
<element name="environmentVariables">
<collection addElement="environmentVariable" clearElement="clear" >
<attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
<attribute name="value" type="string" required="true"/>
</collection>
</element>
<element name="handlerSettings">
<collection addElement="handlerSetting" clearElement="clear" >
<attribute name="name" type="string" required="true" validationType="nonEmptyString"/>
<attribute name="value" type="string" required="true"/>
</collection>
</element>
</sectionSchema>
</configSchema>

View File

@ -0,0 +1,72 @@
<#
.DESCRIPTION
Updates aspnetcore_schema.xml to the latest version.
Updates aspnetcore_schema_v2.xml to the latest version.
Requires admin privileges.
#>
[cmdletbinding(SupportsShouldProcess = $true)]
param()
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version 1
$ancmSchemaFiles = @(
"aspnetcore_schema.xml",
"aspnetcore_schema_v2.xml"
)
$ancmSchemaFileLocations = @(
@(Resolve-Path "$PSScriptRoot\aspnetcore_schema.xml"),
@(Resolve-Path "$PSScriptRoot\aspnetcore_schema_v2.xml")
)
[bool]$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")
if (-not $isAdmin -and -not $WhatIfPreference) {
if ($PSCmdlet.ShouldContinue("Continue as an admin?", "This script needs admin privileges to update IIS Express and IIS.")) {
$thisFile = Join-Path $PSScriptRoot $MyInvocation.MyCommand.Name
Start-Process `
-Verb runas `
-FilePath "powershell.exe" `
-ArgumentList $thisFile `
-Wait `
| Out-Null
if (-not $?) {
throw 'Update failed'
}
exit
}
else {
throw 'Requires admin privileges'
}
}
for ($i=0; $i -lt $ancmSchemaFiles.Length; $i++)
{
$schemaFile = $ancmSchemaFiles[$i]
$schemaSource = $ancmSchemaFileLocations[$i]
$destinations = @(
"${env:ProgramFiles(x86)}\IIS Express\config\schema\",
"${env:ProgramFiles}\IIS Express\config\schema\",
"${env:windir}\system32\inetsrv\config\schema\"
)
foreach ($destPath in $destinations) {
$dest = "$destPath\${schemaFile}";
if (!(Test-Path $destPath))
{
Write-Host "$destPath doesn't exist"
continue;
}
if ($PSCmdlet.ShouldProcess($dest, "Replace file")) {
Write-Host "Updated $dest"
Move-Item $dest "${dest}.bak" -ErrorAction Ignore
Copy-Item $schemaSource $dest
}
}
}

View File

@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>2.1.1</VersionPrefix>
<VersionPrefix>2.2.0</VersionPrefix>
<VersionSuffix>rtm</VersionSuffix>
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' == 'rtm' ">$(VersionPrefix)</PackageVersion>
<PackageVersion Condition="'$(IsFinalBuild)' == 'true' AND '$(VersionSuffix)' != 'rtm' ">$(VersionPrefix)-$(VersionSuffix)-final</PackageVersion>