diff --git a/ServerTests.sln b/ServerTests.sln index 2cc850dac2..f26151af6f 100644 --- a/ServerTests.sln +++ b/ServerTests.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26228.4 +VisualStudioVersion = 15.0.26228.10 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{49AB8AAA-8160-48DF-A18B-78F51E54E02A}" ProjectSection(SolutionItems) = preProject @@ -13,6 +13,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerComparison.Functional EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ServerComparison.TestSites", "test\ServerComparison.TestSites\ServerComparison.TestSites.csproj", "{030225D8-4EE8-47E5-B692-2A96B3B51A38}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{55694E45-5EDE-46F8-80AA-797DE5F8C5C3}" + ProjectSection(SolutionItems) = preProject + build\common.props = build\common.props + build\dependencies.props = build\dependencies.props + build\repo.props = build\repo.props + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/build/dependencies.props b/build/dependencies.props index 9fa566a6b2..5d612ceb14 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -3,7 +3,7 @@ 1.2.0-* 2.0.0-* 1.1.0-* - 0.3.0-* + 0.4.0-* 1.0.0-* 4.3.0 1.6.1 @@ -11,4 +11,4 @@ 15.0.0 2.2.0 - \ No newline at end of file + diff --git a/test/ServerComparison.FunctionalTests/HelloWorldTest.cs b/test/ServerComparison.FunctionalTests/HelloWorldTest.cs index 6321998800..d5724031af 100644 --- a/test/ServerComparison.FunctionalTests/HelloWorldTest.cs +++ b/test/ServerComparison.FunctionalTests/HelloWorldTest.cs @@ -1,8 +1,9 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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.Net.Http; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Testing.xunit; @@ -14,7 +15,6 @@ using Xunit.Sdk; namespace ServerComparison.FunctionalTests { - // Uses ports ranging 5061 - 5069. public class HelloWorldTests { private readonly ITestOutputHelper _output; @@ -28,59 +28,47 @@ namespace ServerComparison.FunctionalTests [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - //[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, "http://localhost:5061/", ApplicationType.Portable)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5062/", ApplicationType.Portable)] - //[InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x86, "http://localhost:5063/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5064/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5065/", ApplicationType.Standalone)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5066/", ApplicationType.Portable)] - public Task HelloWorld_Windows(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + //[InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, ApplicationType.Portable)] + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + //[InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x86, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task HelloWorld_Windows(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return HelloWorld(serverType, runtimeFlavor, architecture, applicationBaseUrl, applicationType); + return HelloWorld(serverType, runtimeFlavor, architecture, applicationType); } [Theory] - //[InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, "http://localhost:5067/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5068/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5069/", ApplicationType.Standalone)] - public Task HelloWorld_Kestrel(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + //[InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task HelloWorld_Kestrel(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return HelloWorld(serverType, runtimeFlavor, architecture, applicationBaseUrl, applicationType); + return HelloWorld(serverType, runtimeFlavor, architecture, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5070/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5071/", ApplicationType.Standalone)] - public Task HelloWorld_Nginx(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task HelloWorld_Nginx(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return HelloWorld(serverType, runtimeFlavor, architecture, applicationBaseUrl, applicationType); + return HelloWorld(serverType, runtimeFlavor, architecture, applicationType); } - [ConditionalTheory] - [SkipIfEnvironmentVariableNotEnabled("IIS_VARIATIONS_ENABLED")] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - [FrameworkSkipCondition(RuntimeFrameworks.CoreCLR)] - [InlineData(ServerType.IIS, RuntimeFlavor.Clr, RuntimeArchitecture.x86, "http://localhost:5072/", ApplicationType.Portable)] - //[InlineData(ServerType.IIS, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, "http://localhost:5073/", ApplicationType.Portable)] - public Task HelloWorld_IIS_X86(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + public async Task HelloWorld(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType, [CallerMemberName] string testName = null) { - return HelloWorld(serverType, runtimeFlavor, architecture, applicationBaseUrl, applicationType); - } + testName = $"{testName}_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}"; + var loggerFactory = TestLoggingUtilities.SetUpLogging(_output, testName); + var logger = loggerFactory.CreateLogger("TestHarness"); + Console.WriteLine($"Starting test: {testName}"); + logger.LogInformation("Starting test: {testName}", testName); - public async Task HelloWorld(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) - { - var loggerName = string.Format("HelloWorld:{0}:{1}:{2}:{3}", serverType, runtimeFlavor, architecture, applicationType); - Console.WriteLine("Running test for " + loggerName); - var logger = new LoggerFactory() - .AddXunit(_output) - .CreateLogger(loggerName); - using (logger.BeginScope("HelloWorldTest")) + using (logger.BeginScope("HelloWorld")) { var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) { - ApplicationBaseUriHint = applicationBaseUrl, 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 @@ -88,16 +76,16 @@ namespace ServerComparison.FunctionalTests ApplicationType = applicationType }; - if(applicationType == ApplicationType.Standalone) + if (applicationType == ApplicationType.Standalone) { deploymentParameters.AdditionalPublishParameters = " -r " + RuntimeEnvironment.GetRuntimeIdentifier(); } - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory)) { - var deploymentResult = deployer.Deploy(); + var deploymentResult = await deployer.DeployAsync(); var httpClientHandler = new HttpClientHandler(); - var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; + var httpClient = new HttpClient(new LoggingHandler(loggerFactory, httpClientHandler)) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; // Request to base address and check if various parts of the body are rendered & measure the cold startup time. var response = await RetryHelper.RetryRequest(() => @@ -118,6 +106,9 @@ namespace ServerComparison.FunctionalTests } } } + + Console.WriteLine($"Finished test: {testName}"); + logger.LogInformation("Finished test: {testName}", testName); } } } diff --git a/test/ServerComparison.FunctionalTests/Http.config b/test/ServerComparison.FunctionalTests/Http.config index 3668f762c8..8e8b3f2f9d 100644 --- a/test/ServerComparison.FunctionalTests/Http.config +++ b/test/ServerComparison.FunctionalTests/Http.config @@ -5,7 +5,7 @@ For schema documentation, see %IIS_BIN%\config\schema\IIS_schema.xml. - + Please make a backup of this file before making any changes to it. NOTE: The following environment variables are available to be used @@ -25,20 +25,20 @@ The section controls the registration of sections. Section is the basic unit of deployment, locking, searching and containment for configuration settings. - + Every section belongs to one section group. A section group is a container of logically-related sections. - + Sections cannot be nested. Section groups may be nested. - +
- + The recommended way to unlock sections is by using a location tag: diff --git a/test/ServerComparison.FunctionalTests/LoggingHandler.cs b/test/ServerComparison.FunctionalTests/LoggingHandler.cs new file mode 100644 index 0000000000..42027875e0 --- /dev/null +++ b/test/ServerComparison.FunctionalTests/LoggingHandler.cs @@ -0,0 +1,25 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Logging; + +namespace ServerComparison.FunctionalTests +{ + internal class LoggingHandler : DelegatingHandler + { + private ILogger _logger; + + public LoggingHandler(ILoggerFactory loggerFactory, HttpMessageHandler innerHandler) : base(innerHandler) + { + _logger = loggerFactory.CreateLogger(); + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + _logger.LogDebug("Sending {method} {url}", request.Method, request.RequestUri); + var response = await base.SendAsync(request, cancellationToken); + _logger.LogDebug("Received {statusCode} {reasonPhrase} {url}", response.StatusCode, response.ReasonPhrase, request.RequestUri); + return response; + } + } +} \ No newline at end of file diff --git a/test/ServerComparison.FunctionalTests/NoCompression.config b/test/ServerComparison.FunctionalTests/NoCompression.config index a44a5f2a81..c9b9f970be 100644 --- a/test/ServerComparison.FunctionalTests/NoCompression.config +++ b/test/ServerComparison.FunctionalTests/NoCompression.config @@ -5,7 +5,7 @@ For schema documentation, see %IIS_BIN%\config\schema\IIS_schema.xml. - + Please make a backup of this file before making any changes to it. NOTE: The following environment variables are available to be used @@ -25,20 +25,20 @@ The section controls the registration of sections. Section is the basic unit of deployment, locking, searching and containment for configuration settings. - + Every section belongs to one section group. A section group is a container of logically-related sections. - + Sections cannot be nested. Section groups may be nested. - +
- + The recommended way to unlock sections is by using a location tag: diff --git a/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs b/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs index 757a81ddd4..05e520434a 100644 --- a/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs +++ b/test/ServerComparison.FunctionalTests/NtlmAuthenticationTest.cs @@ -5,6 +5,7 @@ using System; 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; @@ -16,7 +17,6 @@ using Xunit.Sdk; namespace ServerComparison.FunctionalTests { - // Uses ports ranging 5050 - 5060. public class NtlmAuthenticationTests { private readonly ITestOutputHelper _output; @@ -30,24 +30,23 @@ namespace ServerComparison.FunctionalTests [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] // TODO: https://github.com/aspnet/IISIntegration/issues/1 - // [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, "http://localhost:5050/", ApplicationType.Portable)] - // [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5051/", ApplicationType.Portable)] - // [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x86, "http://localhost:5052/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5052/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5053/", ApplicationType.Standalone)] - public async Task NtlmAuthentication(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + // [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x86, ApplicationType.Portable)] + // [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + // [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x86, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public async Task NtlmAuthentication(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - var loggerName = string.Format("Ntlm:{0}:{1}:{2}:{3}", serverType, runtimeFlavor, architecture, applicationType); - Console.WriteLine("Running test for " + loggerName); - var logger = new LoggerFactory() - .AddXunit(_output) - .CreateLogger(loggerName); + var testName = $"NtlmAuthentication_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}"; + var loggerFactory = TestLoggingUtilities.SetUpLogging(_output, testName); + var logger = loggerFactory.CreateLogger("TestHarness"); + Console.WriteLine($"Starting test: {testName}"); + logger.LogInformation("Starting test: {testName}", testName); using (logger.BeginScope("NtlmAuthenticationTest")) { var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) { - ApplicationBaseUriHint = applicationBaseUrl, 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 @@ -55,16 +54,16 @@ namespace ServerComparison.FunctionalTests ApplicationType = applicationType }; - if(applicationType == ApplicationType.Standalone) + if (applicationType == ApplicationType.Standalone) { deploymentParameters.AdditionalPublishParameters = " -r " + RuntimeEnvironment.GetRuntimeIdentifier(); } - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory)) { - var deploymentResult = deployer.Deploy(); + var deploymentResult = await deployer.DeployAsync(); var httpClientHandler = new HttpClientHandler(); - var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; + var httpClient = new HttpClient(new LoggingHandler(loggerFactory, httpClientHandler)) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; // Request to base address and check if various parts of the body are rendered & measure the cold startup time. var response = await RetryHelper.RetryRequest(() => @@ -77,16 +76,19 @@ namespace ServerComparison.FunctionalTests { Assert.Equal("Hello World", responseText); + logger.LogInformation("Testing /Anonymous"); response = await httpClient.GetAsync("/Anonymous"); responseText = await response.Content.ReadAsStringAsync(); Assert.Equal("Anonymous?True", responseText); + logger.LogInformation("Testing /Restricted"); response = await httpClient.GetAsync("/Restricted"); responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Contains("NTLM", response.Headers.WwwAuthenticate.ToString()); Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString()); + logger.LogInformation("Testing /RestrictedNTLM"); response = await httpClient.GetAsync("/RestrictedNTLM"); responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); @@ -102,26 +104,32 @@ namespace ServerComparison.FunctionalTests Assert.Contains("Negotiate", response.Headers.WwwAuthenticate.ToString()); } + logger.LogInformation("Testing /Forbidden"); response = await httpClient.GetAsync("/Forbidden"); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + logger.LogInformation("Enabling Default Credentials"); httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true }; httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; + logger.LogInformation("Testing /AutoForbid"); response = await httpClient.GetAsync("/AutoForbid"); responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); + logger.LogInformation("Testing /Restricted"); response = await httpClient.GetAsync("/Restricted"); responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("Negotiate", responseText); + logger.LogInformation("Testing /RestrictedNegotiate"); response = await httpClient.GetAsync("/RestrictedNegotiate"); responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("Negotiate", responseText); + logger.LogInformation("Testing /RestrictedNTLM"); if (serverType == ServerType.WebListener) { response = await httpClient.GetAsync("/RestrictedNTLM"); @@ -147,6 +155,9 @@ namespace ServerComparison.FunctionalTests } } } + + Console.WriteLine($"Finished test: {testName}"); + logger.LogInformation("Finished test: {testName}", testName); } } } diff --git a/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs b/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs index 765e39d5c4..aca273bdaa 100644 --- a/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs +++ b/test/ServerComparison.FunctionalTests/ResponseCompressionTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -8,6 +8,7 @@ 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; @@ -20,7 +21,6 @@ using Xunit.Sdk; namespace ServerComparison.FunctionalTests { - // Uses ports ranging 5100 - 5130. public class ResponseCompressionTests { // NGinx's default min size is 20 bytes @@ -35,108 +35,107 @@ namespace ServerComparison.FunctionalTests [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5100/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5101/", ApplicationType.Portable)] - public Task ResponseCompression_Windows_NoCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseCompression_Windows_NoCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseCompression(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckNoCompressionAsync, applicationType, hostCompression: false); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckNoCompressionAsync, applicationType, hostCompression: false); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5102/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5103/", ApplicationType.Standalone)] - public Task ResponseCompression_Kestrel_NoCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [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, applicationBaseUrl, CheckNoCompressionAsync, applicationType, hostCompression: false); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckNoCompressionAsync, applicationType, hostCompression: false); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5103/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5104/", ApplicationType.Standalone)] - public Task ResponseCompression_Nginx_NoCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [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, applicationBaseUrl, CheckNoCompressionAsync, applicationType, hostCompression: false); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckNoCompressionAsync, applicationType, hostCompression: false); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5105/", ApplicationType.Portable)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5106/", ApplicationType.Standalone)] - public Task ResponseCompression_Windows_HostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseCompression_Windows_HostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseCompression(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckHostCompressionAsync, applicationType, hostCompression: true); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckHostCompressionAsync, applicationType, hostCompression: true); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5107/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5108/", ApplicationType.Standalone)] - public Task ResponseCompression_Nginx_HostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [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, applicationBaseUrl, CheckHostCompressionAsync, applicationType, hostCompression: true); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckHostCompressionAsync, applicationType, hostCompression: true); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5109/", ApplicationType.Standalone)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5110/", ApplicationType.Portable)] - public Task ResponseCompression_Windows_AppCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseCompression_Windows_AppCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseCompression(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckAppCompressionAsync, applicationType, hostCompression: false); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckAppCompressionAsync, applicationType, hostCompression: false); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5111/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5112/", ApplicationType.Standalone)] - public Task ResponseCompression_Kestrel_AppCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [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, applicationBaseUrl, CheckAppCompressionAsync, applicationType, hostCompression: false); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckAppCompressionAsync, applicationType, hostCompression: false); } [ConditionalTheory(Skip = "No pass-through compression https://github.com/aspnet/BasicMiddleware/issues/123")] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5113/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5114/", ApplicationType.Standalone)] - public Task ResponseCompression_Nginx_AppCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [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, applicationBaseUrl, CheckHostCompressionAsync, applicationType, hostCompression: false); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckHostCompressionAsync, applicationType, hostCompression: false); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5115/", ApplicationType.Standalone)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5116/", ApplicationType.Portable)] - public Task ResponseCompression_Windows_AppAndHostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseCompression_Windows_AppAndHostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseCompression(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckAppCompressionAsync, applicationType, hostCompression: true); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckAppCompressionAsync, applicationType, hostCompression: true); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5117/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5118/", ApplicationType.Standalone)] - public Task ResponseCompression_Nginx_AppAndHostCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [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, applicationBaseUrl, CheckAppCompressionAsync, applicationType, hostCompression: true); + return ResponseCompression(serverType, runtimeFlavor, architecture, CheckAppCompressionAsync, applicationType, hostCompression: true); } - public async Task ResponseCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, Func scenario, ApplicationType applicationType, bool hostCompression) + public async Task ResponseCompression(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, Func scenario, ApplicationType applicationType, bool hostCompression, [CallerMemberName] string testName = null) { - var loggerName = string.Format("ResponseCompression:{0}:{1}:{2}:{3}", serverType, runtimeFlavor, architecture, applicationType); - Console.WriteLine("Running test for " + loggerName); - var logger = new LoggerFactory() - .AddXunit(_output) - .CreateLogger(loggerName); + testName = $"{testName}_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}"; + var loggerFactory = TestLoggingUtilities.SetUpLogging(_output, testName); + var logger = loggerFactory.CreateLogger("TestHarness"); + Console.WriteLine($"Starting test: {testName}"); + logger.LogInformation("Starting test: {testName}", testName); - using (logger.BeginScope("ResponseCompressionTest")) + using (logger.BeginScope("ResponseCompression")) { var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) { - ApplicationBaseUriHint = applicationBaseUrl, EnvironmentName = "ResponseCompression", ServerConfigTemplateContent = Helpers.GetConfigContent(serverType, hostCompression ? "http.config" : "NoCompression.config", @@ -151,12 +150,12 @@ namespace ServerComparison.FunctionalTests deploymentParameters.AdditionalPublishParameters = " -r " + RuntimeEnvironment.GetRuntimeIdentifier(); } - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory)) { - var deploymentResult = deployer.Deploy(); + var deploymentResult = await deployer.DeployAsync(); var httpClientHandler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.None }; Assert.True(httpClientHandler.SupportsAutomaticDecompression); - var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; + var httpClient = new HttpClient(new LoggingHandler(loggerFactory, httpClientHandler)) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; // Request to base address and check if various parts of the body are rendered & measure the cold startup time. var response = await RetryHelper.RetryRequest(() => @@ -179,10 +178,14 @@ namespace ServerComparison.FunctionalTests await scenario(httpClient, logger); } } + + Console.WriteLine($"Finished test: {testName}"); + logger.LogInformation("Finished test: {testName}", testName); } 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); @@ -214,6 +217,7 @@ namespace ServerComparison.FunctionalTests 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); diff --git a/test/ServerComparison.FunctionalTests/ResponseTests.cs b/test/ServerComparison.FunctionalTests/ResponseTests.cs index 4f7ee3a943..b69fc9ee69 100644 --- a/test/ServerComparison.FunctionalTests/ResponseTests.cs +++ b/test/ServerComparison.FunctionalTests/ResponseTests.cs @@ -1,10 +1,11 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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; @@ -17,7 +18,6 @@ using Xunit.Sdk; namespace ServerComparison.FunctionalTests { - // Uses ports ranging 5080 - 5099. public class ResponseTests { private readonly ITestOutputHelper _output; @@ -30,151 +30,150 @@ namespace ServerComparison.FunctionalTests [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5080/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5081/", ApplicationType.Portable)] - public Task ResponseFormats_Windows_ContentLength(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseFormats_Windows_ContentLength(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckContentLengthAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckContentLengthAsync, applicationType); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5082/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5083/", ApplicationType.Standalone)] - public Task ResponseFormats_Kestrel_ContentLength(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Kestrel_ContentLength(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckContentLengthAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckContentLengthAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5084/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5085/", ApplicationType.Standalone)] - public Task ResponseFormats_Nginx_ContentLength(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Nginx_ContentLength(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckContentLengthAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckContentLengthAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5087/", ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] // IIS will remove the "Connection: close" header https://github.com/aspnet/IISIntegration/issues/7 - public Task ResponseFormats_Windows_Http10ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + public Task ResponseFormats_Windows_Http10ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckHttp10ConnectionCloseAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckHttp10ConnectionCloseAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5087/", ApplicationType.Portable)] // https://github.com/aspnet/WebListener/issues/259 + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] // https://github.com/aspnet/WebListener/issues/259 // IIS will remove the "Connection: close" header https://github.com/aspnet/IISIntegration/issues/7 - public Task ResponseFormats_Windows_Http11ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + public Task ResponseFormats_Windows_Http11ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckHttp11ConnectionCloseAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckHttp11ConnectionCloseAsync, applicationType); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5088/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5089/", ApplicationType.Standalone)] - public Task ResponseFormats_Kestrel_Http10ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Kestrel_Http10ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckHttp10ConnectionCloseAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckHttp10ConnectionCloseAsync, applicationType); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5088/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5089/", ApplicationType.Standalone)] - public Task ResponseFormats_Kestrel_Http11ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Kestrel_Http11ConnectionClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckHttp11ConnectionCloseAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckHttp11ConnectionCloseAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5090/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5091/", ApplicationType.Portable)] - public Task ResponseFormats_Windows_Chunked(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseFormats_Windows_Chunked(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckChunkedAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckChunkedAsync, applicationType); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5092/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5093/", ApplicationType.Standalone)] - public Task ResponseFormats_Kestrel_Chunked(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Kestrel_Chunked(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckChunkedAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckChunkedAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5094/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5095/", ApplicationType.Standalone)] - public Task ResponseFormats_Nginx_Chunked(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Nginx_Chunked(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckChunkedAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckChunkedAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5096/", ApplicationType.Portable)] - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5097/", ApplicationType.Portable)] - public Task ResponseFormats_Windows_ManuallyChunk(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseFormats_Windows_ManuallyChunk(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckManuallyChunkedAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckManuallyChunkedAsync, applicationType); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5098/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5099/", ApplicationType.Standalone)] - public Task ResponseFormats_Kestrel_ManuallyChunk(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Kestrel_ManuallyChunk(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckManuallyChunkedAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckManuallyChunkedAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Windows)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5100/", ApplicationType.Portable)] - [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5101/", ApplicationType.Standalone)] - public Task ResponseFormats_Nginx_ManuallyChunk(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Nginx, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Nginx_ManuallyChunk(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckManuallyChunkedAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckManuallyChunkedAsync, applicationType); } [ConditionalTheory] [OSSkipCondition(OperatingSystems.Linux)] [OSSkipCondition(OperatingSystems.MacOSX)] - // [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5102/", ApplicationType.Portable)] // https://github.com/aspnet/IISIntegration/issues/7 - [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, "http://localhost:5103/", ApplicationType.Portable)] - public Task ResponseFormats_Windows_ManuallyChunkAndClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + // [InlineData(ServerType.IISExpress, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] // https://github.com/aspnet/IISIntegration/issues/7 + [InlineData(ServerType.WebListener, RuntimeFlavor.Clr, RuntimeArchitecture.x64, ApplicationType.Portable)] + public Task ResponseFormats_Windows_ManuallyChunkAndClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckManuallyChunkedAndCloseAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckManuallyChunkedAndCloseAsync, applicationType); } [Theory] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5104/", ApplicationType.Portable)] - [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, "http://localhost:5104/", ApplicationType.Standalone)] - public Task ResponseFormats_Kestrel_ManuallyChunkAndClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, ApplicationType applicationType) + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Portable)] + [InlineData(ServerType.Kestrel, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64, ApplicationType.Standalone)] + public Task ResponseFormats_Kestrel_ManuallyChunkAndClose(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, ApplicationType applicationType) { - return ResponseFormats(serverType, runtimeFlavor, architecture, applicationBaseUrl, CheckManuallyChunkedAndCloseAsync, applicationType); + return ResponseFormats(serverType, runtimeFlavor, architecture, CheckManuallyChunkedAndCloseAsync, applicationType); } - public async Task ResponseFormats(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, string applicationBaseUrl, Func scenario, ApplicationType applicationType) + public async Task ResponseFormats(ServerType serverType, RuntimeFlavor runtimeFlavor, RuntimeArchitecture architecture, Func scenario, ApplicationType applicationType, [CallerMemberName] string testName = null) { - var loggerName = string.Format("ResponseFormats:{0}:{1}:{2}:{3}", serverType, runtimeFlavor, architecture, applicationType); - Console.WriteLine("Running test for " + loggerName); - var logger = new LoggerFactory() - .AddXunit(_output) - .CreateLogger(loggerName); + testName = $"{testName}_{serverType}_{runtimeFlavor}_{architecture}_{applicationType}"; + var loggerFactory = TestLoggingUtilities.SetUpLogging(_output, testName); + var logger = loggerFactory.CreateLogger("TestHarness"); + Console.WriteLine($"Starting test: {testName}"); + logger.LogInformation("Starting test: {testName}", testName); - using (logger.BeginScope("ResponseFormatsTest")) + using (logger.BeginScope("ResponseFormats")) { var deploymentParameters = new DeploymentParameters(Helpers.GetApplicationPath(applicationType), serverType, runtimeFlavor, architecture) { - ApplicationBaseUriHint = applicationBaseUrl, EnvironmentName = "Responses", ServerConfigTemplateContent = Helpers.GetConfigContent(serverType, "Http.config", "nginx.conf"), SiteName = "HttpTestSite", // This is configured in the Http.config @@ -187,11 +186,11 @@ namespace ServerComparison.FunctionalTests deploymentParameters.AdditionalPublishParameters = " -r " + RuntimeEnvironment.GetRuntimeIdentifier(); } - using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, logger)) + using (var deployer = ApplicationDeployerFactory.Create(deploymentParameters, loggerFactory)) { - var deploymentResult = deployer.Deploy(); + var deploymentResult = await deployer.DeployAsync(); var httpClientHandler = new HttpClientHandler(); - var httpClient = new HttpClient(httpClientHandler) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; + var httpClient = new HttpClient(new LoggingHandler(loggerFactory, httpClientHandler)) { BaseAddress = new Uri(deploymentResult.ApplicationBaseUri) }; // Request to base address and check if various parts of the body are rendered & measure the cold startup time. var response = await RetryHelper.RetryRequest(() => @@ -214,10 +213,14 @@ namespace ServerComparison.FunctionalTests await scenario(httpClient, logger); } } + + Console.WriteLine($"Finished test: {testName}"); + logger.LogInformation("Finished test: {testName}", testName); } private static async Task CheckContentLengthAsync(HttpClient client, ILogger logger) { + logger.LogInformation("Testing ContentLength"); var response = await client.GetAsync("contentlength"); var responseText = await response.Content.ReadAsStringAsync(); try @@ -237,6 +240,7 @@ namespace ServerComparison.FunctionalTests 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 @@ -256,6 +260,7 @@ namespace ServerComparison.FunctionalTests 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) @@ -280,6 +285,7 @@ namespace ServerComparison.FunctionalTests private static async Task CheckChunkedAsync(HttpClient client, ILogger logger) { + logger.LogInformation("Testing Chunked"); var response = await client.GetAsync("chunked"); var responseText = await response.Content.ReadAsStringAsync(); try @@ -299,6 +305,7 @@ namespace ServerComparison.FunctionalTests private static async Task CheckManuallyChunkedAsync(HttpClient client, ILogger logger) { + logger.LogInformation("Testing ManuallyChunked"); var response = await client.GetAsync("manuallychunked"); var responseText = await response.Content.ReadAsStringAsync(); try @@ -318,6 +325,7 @@ namespace ServerComparison.FunctionalTests 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 diff --git a/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj b/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj index 06f4741289..acf0f66f57 100644 --- a/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj +++ b/test/ServerComparison.FunctionalTests/ServerComparison.FunctionalTests.csproj @@ -15,13 +15,15 @@ - + + + diff --git a/test/ServerComparison.FunctionalTests/TestLoggingUtilities.cs b/test/ServerComparison.FunctionalTests/TestLoggingUtilities.cs new file mode 100644 index 0000000000..8196bb92fd --- /dev/null +++ b/test/ServerComparison.FunctionalTests/TestLoggingUtilities.cs @@ -0,0 +1,47 @@ +using System; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using Microsoft.Extensions.Logging; +using Serilog; +using Xunit.Abstractions; + +namespace ServerComparison.FunctionalTests +{ + public static class TestLoggingUtilities + { + public static readonly string TestOutputRoot = Environment.GetEnvironmentVariable("ASPNETCORE_TEST_LOG_DIR"); + + public static ILoggerFactory SetUpLogging(ITestOutputHelper output, [CallerMemberName] string testName = null) + { + var loggerFactory = new LoggerFactory(); + loggerFactory.AddXunit(output, LogLevel.Debug); + + if (!string.IsNullOrEmpty(TestOutputRoot)) + { + var testClass = typeof(TTestClass).GetTypeInfo(); + var testOutputDir = Path.Combine(TestOutputRoot, testClass.Assembly.GetName().Name, testClass.FullName); + if (!Directory.Exists(testOutputDir)) + { + Directory.CreateDirectory(testOutputDir); + } + + var testOutputFile = Path.Combine(testOutputDir, $"{testName}.log"); + + if (File.Exists(testOutputFile)) + { + File.Delete(testOutputFile); + } + + var serilogger = new LoggerConfiguration() + .Enrich.FromLogContext() + .MinimumLevel.Verbose() + .WriteTo.File(testOutputFile, flushToDiskInterval: TimeSpan.FromSeconds(1)) + .CreateLogger(); + loggerFactory.AddSerilog(serilogger); + } + + return loggerFactory; + } + } +} diff --git a/test/ServerComparison.FunctionalTests/nginx.conf b/test/ServerComparison.FunctionalTests/nginx.conf index 1f77013ccc..f9b0bc85c9 100644 --- a/test/ServerComparison.FunctionalTests/nginx.conf +++ b/test/ServerComparison.FunctionalTests/nginx.conf @@ -1,5 +1,4 @@ -error_log [errorlog]; -user [user]; +error_log [errorlog]; worker_processes 4; pid [pidFile];