diff --git a/src/ServerTests/Directory.Build.targets b/src/ServerTests/Directory.Build.targets index 53b3f6e1da..78626b773e 100644 --- a/src/ServerTests/Directory.Build.targets +++ b/src/ServerTests/Directory.Build.targets @@ -1,7 +1,10 @@ - + $(MicrosoftNETCoreApp20PackageVersion) $(MicrosoftNETCoreApp21PackageVersion) + $(MicrosoftNETCoreApp22PackageVersion) $(NETStandardLibrary20PackageVersion) + + 99.9 diff --git a/src/ServerTests/ServerTests.sln b/src/ServerTests/ServerTests.sln index bd58846053..348408541c 100644 --- a/src/ServerTests/ServerTests.sln +++ b/src/ServerTests/ServerTests.sln @@ -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 diff --git a/src/ServerTests/build/dependencies.props b/src/ServerTests/build/dependencies.props index 72cad24822..ff465aacf2 100644 --- a/src/ServerTests/build/dependencies.props +++ b/src/ServerTests/build/dependencies.props @@ -2,38 +2,33 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - - - 2.1.3-rtm-15802 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 0.5.1 - 2.1.2 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.1.1 - 2.0.0 - 2.1.2 - 2.1.1 + + 2.2.0-preview2-20181004.6 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.2.0-preview3-35425 + 2.0.9 + 2.1.3 + 2.2.0-preview3-27001-02 + 2.2.0-preview3-35425 15.6.1 2.0.3 1.4.0 - 3.2.0 + 4.0.0 2.3.1 - 2.4.0-beta.1.build3945 + 2.4.0 - - - - diff --git a/src/ServerTests/build/repo.props b/src/ServerTests/build/repo.props index c8bd413e1e..731c06d415 100644 --- a/src/ServerTests/build/repo.props +++ b/src/ServerTests/build/repo.props @@ -7,12 +7,12 @@ Internal.AspNetCore.Universe.Lineup - 2.1.0-rc1-* + 2.2.0-* https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json - - + + diff --git a/src/ServerTests/install-nginx.sh b/src/ServerTests/install-nginx.sh deleted file mode 100644 index 9564813c2d..0000000000 --- a/src/ServerTests/install-nginx.sh +++ /dev/null @@ -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 diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/HelloWorldTest.cs b/src/ServerTests/test/ServerComparison.FunctionalTests/HelloWorldTest.cs deleted file mode 100644 index 62e1fcfbd8..0000000000 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/HelloWorldTest.cs +++ /dev/null @@ -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; - } - } - } - } - } -} diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/Http.config b/src/ServerTests/test/ServerComparison.FunctionalTests/Http.config deleted file mode 100644 index 8e8b3f2f9d..0000000000 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/Http.config +++ /dev/null @@ -1,1029 +0,0 @@ - - - - - - - - -
-
-
-
-
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
- -
-
- -
-
-
- - -
-
-
-
-
-
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/NoCompression.config b/src/ServerTests/test/ServerComparison.FunctionalTests/NoCompression.config deleted file mode 100644 index c9b9f970be..0000000000 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/NoCompression.config +++ /dev/null @@ -1,1021 +0,0 @@ - - - - - - - - -
-
-
-
-
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
- -
-
- -
-
-
- - -
-
-
-
-
-
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/NtlmAuthentication.config b/src/ServerTests/test/ServerComparison.FunctionalTests/NtlmAuthentication.config deleted file mode 100644 index c35bcf3443..0000000000 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/NtlmAuthentication.config +++ /dev/null @@ -1,1041 +0,0 @@ - - - - - - - - -
-
-
-
-
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
-
- -
-
-
-
-
- -
-
-
- -
-
- -
-
- -
-
-
- - -
-
-
-
-
-
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs b/src/ServerTests/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs deleted file mode 100644 index 301a0b74e6..0000000000 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs +++ /dev/null @@ -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 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 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(); - } - } - } -} diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/ResponseTests.cs b/src/ServerTests/test/ServerComparison.FunctionalTests/ResponseTests.cs deleted file mode 100644 index 62d7fec6e3..0000000000 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/ResponseTests.cs +++ /dev/null @@ -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 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 values; - return response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out values) ? values.FirstOrDefault() : null; - } - } -} diff --git a/src/ServerTests/test/ServerComparison.TestSites/web.config b/src/ServerTests/test/ServerComparison.TestSites/web.config deleted file mode 100644 index 3379e820ea..0000000000 --- a/src/ServerTests/test/ServerComparison.TestSites/web.config +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/ServerTests/test/Directory.Build.props b/src/ServerTests/test/test/Directory.Build.props similarity index 76% rename from src/ServerTests/test/Directory.Build.props rename to src/ServerTests/test/test/Directory.Build.props index 620b803d21..a0100197c9 100644 --- a/src/ServerTests/test/Directory.Build.props +++ b/src/ServerTests/test/test/Directory.Build.props @@ -1,8 +1,8 @@ - + - netcoreapp2.1;netcoreapp2.0 + netcoreapp2.2 $(DeveloperBuildTestTfms) $(StandardTestTfms);net461 diff --git a/src/ServerTests/test/test/ServerComparison.FunctionalTests/HelloWorldTest.cs b/src/ServerTests/test/test/ServerComparison.FunctionalTests/HelloWorldTest.cs new file mode 100644 index 0000000000..4575a7f370 --- /dev/null +++ b/src/ServerTests/test/test/ServerComparison.FunctionalTests/HelloWorldTest.cs @@ -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()); + } + } + } + } + } +} diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/Helpers.cs b/src/ServerTests/test/test/ServerComparison.FunctionalTests/Helpers.cs similarity index 51% rename from src/ServerTests/test/ServerComparison.FunctionalTests/Helpers.cs rename to src/ServerTests/test/test/ServerComparison.FunctionalTests/Helpers.cs index 0c4c4ab89d..5054bd157b 100644 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/Helpers.cs +++ b/src/ServerTests/test/test/ServerComparison.FunctionalTests/Helpers.cs @@ -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}'"); - } } } \ No newline at end of file diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/NoCompression.conf b/src/ServerTests/test/test/ServerComparison.FunctionalTests/NoCompression.conf similarity index 100% rename from src/ServerTests/test/ServerComparison.FunctionalTests/NoCompression.conf rename to src/ServerTests/test/test/ServerComparison.FunctionalTests/NoCompression.conf diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs b/src/ServerTests/test/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs similarity index 53% rename from src/ServerTests/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs rename to src/ServerTests/test/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs index 0aff3407db..7d47162591 100644 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs +++ b/src/ServerTests/test/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs @@ -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; diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/Properties/AssemblyInfo.cs b/src/ServerTests/test/test/ServerComparison.FunctionalTests/Properties/AssemblyInfo.cs similarity index 100% rename from src/ServerTests/test/ServerComparison.FunctionalTests/Properties/AssemblyInfo.cs rename to src/ServerTests/test/test/ServerComparison.FunctionalTests/Properties/AssemblyInfo.cs diff --git a/src/ServerTests/test/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs b/src/ServerTests/test/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs new file mode 100644 index 0000000000..283f8286b2 --- /dev/null +++ b/src/ServerTests/test/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs @@ -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 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 + // + }); + 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 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(); + } + } + } +} diff --git a/src/ServerTests/test/test/ServerComparison.FunctionalTests/ResponseTests.cs b/src/ServerTests/test/test/ServerComparison.FunctionalTests/ResponseTests.cs new file mode 100644 index 0000000000..72ef1f6d48 --- /dev/null +++ b/src/ServerTests/test/test/ServerComparison.FunctionalTests/ResponseTests.cs @@ -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 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 values; + return response.Content.Headers.TryGetValues(HeaderNames.ContentLength, out values) ? values.FirstOrDefault() : null; + } + } +} diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj b/src/ServerTests/test/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj similarity index 83% rename from src/ServerTests/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj rename to src/ServerTests/test/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj index ba0fea38e1..54b15b9c07 100644 --- a/src/ServerTests/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj +++ b/src/ServerTests/test/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj @@ -1,8 +1,8 @@ - + - - netcoreapp2.1 + + netcoreapp2.2 @@ -11,7 +11,7 @@ - + diff --git a/src/ServerTests/test/ServerComparison.FunctionalTests/nginx.conf b/src/ServerTests/test/test/ServerComparison.FunctionalTests/nginx.conf similarity index 100% rename from src/ServerTests/test/ServerComparison.FunctionalTests/nginx.conf rename to src/ServerTests/test/test/ServerComparison.FunctionalTests/nginx.conf diff --git a/src/ServerTests/test/ServerComparison.TestSites/Program.cs b/src/ServerTests/test/test/ServerComparison.TestSites/Program.cs similarity index 98% rename from src/ServerTests/test/ServerComparison.TestSites/Program.cs rename to src/ServerTests/test/test/ServerComparison.TestSites/Program.cs index f6ae1163c1..df87d7d52c 100644 --- a/src/ServerTests/test/ServerComparison.TestSites/Program.cs +++ b/src/ServerTests/test/test/ServerComparison.TestSites/Program.cs @@ -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(); diff --git a/src/ServerTests/test/ServerComparison.TestSites/Properties/launchSettings.json b/src/ServerTests/test/test/ServerComparison.TestSites/Properties/launchSettings.json similarity index 100% rename from src/ServerTests/test/ServerComparison.TestSites/Properties/launchSettings.json rename to src/ServerTests/test/test/ServerComparison.TestSites/Properties/launchSettings.json diff --git a/src/ServerTests/test/ServerComparison.TestSites/ServerComparison.TestSites.csproj b/src/ServerTests/test/test/ServerComparison.TestSites/ServerComparison.TestSites.csproj similarity index 86% rename from src/ServerTests/test/ServerComparison.TestSites/ServerComparison.TestSites.csproj rename to src/ServerTests/test/test/ServerComparison.TestSites/ServerComparison.TestSites.csproj index f3aa4898e5..c58b620932 100644 --- a/src/ServerTests/test/ServerComparison.TestSites/ServerComparison.TestSites.csproj +++ b/src/ServerTests/test/test/ServerComparison.TestSites/ServerComparison.TestSites.csproj @@ -5,17 +5,15 @@ win7-x86;win7-x64;linux-x64;osx-x64 - + - - - - + + diff --git a/src/ServerTests/test/ServerComparison.TestSites/StartupHelloWorld.cs b/src/ServerTests/test/test/ServerComparison.TestSites/Startup.cs similarity index 74% rename from src/ServerTests/test/ServerComparison.TestSites/StartupHelloWorld.cs rename to src/ServerTests/test/test/ServerComparison.TestSites/Startup.cs index f92b8d45c7..bde47802c9 100644 --- a/src/ServerTests/test/ServerComparison.TestSites/StartupHelloWorld.cs +++ b/src/ServerTests/test/test/ServerComparison.TestSites/Startup.cs @@ -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); }); } } diff --git a/src/ServerTests/test/ServerComparison.TestSites/StartupNtlmAuthentication.cs b/src/ServerTests/test/test/ServerComparison.TestSites/StartupNtlmAuthentication.cs similarity index 100% rename from src/ServerTests/test/ServerComparison.TestSites/StartupNtlmAuthentication.cs rename to src/ServerTests/test/test/ServerComparison.TestSites/StartupNtlmAuthentication.cs diff --git a/src/ServerTests/test/ServerComparison.TestSites/StartupResponseCompression.cs b/src/ServerTests/test/test/ServerComparison.TestSites/StartupResponseCompression.cs similarity index 100% rename from src/ServerTests/test/ServerComparison.TestSites/StartupResponseCompression.cs rename to src/ServerTests/test/test/ServerComparison.TestSites/StartupResponseCompression.cs diff --git a/src/ServerTests/test/ServerComparison.TestSites/StartupResponses.cs b/src/ServerTests/test/test/ServerComparison.TestSites/StartupResponses.cs similarity index 100% rename from src/ServerTests/test/ServerComparison.TestSites/StartupResponses.cs rename to src/ServerTests/test/test/ServerComparison.TestSites/StartupResponses.cs diff --git a/src/ServerTests/test/test/aspnetcore_schema.xml b/src/ServerTests/test/test/aspnetcore_schema.xml new file mode 100644 index 0000000000..c1590816b7 --- /dev/null +++ b/src/ServerTests/test/test/aspnetcore_schema.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/ServerTests/test/test/aspnetcore_schema_v2.xml b/src/ServerTests/test/test/aspnetcore_schema_v2.xml new file mode 100644 index 0000000000..d65be07195 --- /dev/null +++ b/src/ServerTests/test/test/aspnetcore_schema_v2.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ServerTests/test/test/update_schema.ps1 b/src/ServerTests/test/test/update_schema.ps1 new file mode 100644 index 0000000000..f3cba7de92 --- /dev/null +++ b/src/ServerTests/test/test/update_schema.ps1 @@ -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 + } + } +} diff --git a/src/ServerTests/version.props b/src/ServerTests/version.props index 669c874829..098795ebd2 100644 --- a/src/ServerTests/version.props +++ b/src/ServerTests/version.props @@ -1,6 +1,6 @@  - 2.1.1 + 2.2.0 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final