From 9409eced0bfed40be60086715440c82f745b1564 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 15:06:34 -0700 Subject: [PATCH 01/10] Reverting version from 2.1.2 back to 2.1.1 As a result of changing the way we apply servicing updates to aspnet core, this repo did not need the version bump because there are no planned product changes in this repo. --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 3d298cd263..6c0ef915f0 100644 --- a/version.props +++ b/version.props @@ -1,6 +1,6 @@  - 2.1.2 + 2.1.1 rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final From a452423998f17559140b5fbfac204847dd89e4e6 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Wed, 11 Jul 2018 18:48:54 -0700 Subject: [PATCH 02/10] Updating dependencies to 2.1.2 and adding a section for pinned variable versions --- build/dependencies.props | 17 ++++++++++++----- korebuild-lock.txt | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 77e173b58c..6895fdc3b0 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -2,9 +2,11 @@ $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - - 2.1.1-rtm-15793 - 2.1.1 + + + + 2.1.3-rtm-15802 + 2.1.2 2.1.1 2.1.1 2.1.1 @@ -13,7 +15,7 @@ 2.1.1 2.1.1 0.5.1 - 2.1.1 + 2.1.2 2.1.1 2.1.0 2.1.1 @@ -28,7 +30,7 @@ 2.1.1 2.1.1 2.0.0 - 2.1.1 + 2.1.2 2.1.1 15.6.1 2.0.3 @@ -43,5 +45,10 @@ 2.3.1 2.4.0-beta.1.build3945 + + + + + diff --git a/korebuild-lock.txt b/korebuild-lock.txt index d2f4947bc8..1dfc352a0a 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.1.1-rtm-15793 -commithash:988313f4b064d6c69fc6f7b845b6384a6af3447a +version:2.1.3-rtm-15802 +commithash:a7c08b45b440a7d2058a0aa1eaa3eb6ba811976a From 4d2e776c41f4ea5f696ff715b3b9e572007b0600 Mon Sep 17 00:00:00 2001 From: Nate McMaster Date: Thu, 12 Jul 2018 11:54:01 -0700 Subject: [PATCH 03/10] Pin version variables to the ASP.NET Core 2.1.2 baseline This reverts our previous policy of cascading versions on all servicing updates. This moves variables into the 'pinned' section, and points them to the latest stable release (versions that were used at the time of the 2.1.2 release). --- build/dependencies.props | 51 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 6895fdc3b0..c90801a573 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,37 +1,15 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) - + 2.1.3-rtm-15802 - 2.1.2 - 2.1.1 - 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.0 - 2.1.1 15.6.82 15.6.82 - 2.1.1 - 2.1.1 - 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 15.6.1 2.0.3 4.5.0 @@ -50,5 +28,28 @@ - + + 2.1.2 + 2.1.1 + 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.0 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + 2.1.1 + From 89fda83bbd58e9b095bc5cc53193b4b424467ab6 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 19 Jul 2018 11:14:07 -0700 Subject: [PATCH 04/10] Move config operations from helpers to functions on the deployment parameters (#1063) --- build/dependencies.props | 4 +- .../IISDeployer.cs | 18 ++- .../IISDeployerBase.cs | 63 +++++++++ .../IISDeploymentParameterExtensions.cs | 80 ++++++++++++ .../IISDeploymentParameters.cs | 123 ++++++++++++++++++ .../IISExpressDeployer.cs | 36 ++--- .../WebConfigHelpers.cs | 50 ------- .../Inprocess/LoggingTests.cs | 28 ++-- .../Inprocess/StartupExceptionTests.cs | 18 +-- .../OutOfProcess/HelloWorldTest.cs | 3 +- .../Utilities/FunctionalTestsBase.cs | 3 +- .../Utilities/Helpers.cs | 112 +--------------- .../Utilities/IISFunctionalTestBase.cs | 36 ----- .../Utilities/IISTestSiteFixture.cs | 3 +- .../InProcess/AuthenticationTests.cs | 3 +- .../InProcess/StartupTests.cs | 43 +++--- .../OutOfProcess/GlobalVersionTests.cs | 15 +-- .../OutOfProcess/HttpsTest.cs | 13 +- .../OutOfProcess/NtlmAuthentationTest.cs | 8 +- .../OutOfProcess/WindowsAuthTests.cs | 5 +- .../UpgradeFeatureDetectionTests.cs | 5 +- 21 files changed, 375 insertions(+), 294 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs create mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs create mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs delete mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs diff --git a/build/dependencies.props b/build/dependencies.props index 37cc74caba..f4a8fd8eff 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,4 +1,4 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) @@ -14,7 +14,7 @@ 2.2.0-preview1-34694 2.2.0-preview1-34694 2.2.0-preview1-34694 - 0.6.0-a-preview1-pk-rem-iis-17083 + 0.6.0-a-preview1-DeploymentParameters-17085 2.2.0-preview1-34694 2.2.0-preview1-34694 2.2.0-preview1-34694 diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index f1f4922e88..bb126a7fa5 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.IO; -using System.Linq; using System.Threading; using System.Threading.Tasks; -using System.Xml.Linq; using Microsoft.AspNetCore.Server.IntegrationTesting.Common; using Microsoft.Extensions.Logging; @@ -14,12 +12,17 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS /// /// Deployer for IIS. /// - public partial class IISDeployer : ApplicationDeployer + public partial class IISDeployer : IISDeployerBase { private IISApplication _application; private CancellationTokenSource _hostShutdownToken = new CancellationTokenSource(); public IISDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory) + : base(new IISDeploymentParameters(deploymentParameters), loggerFactory) + { + } + + public IISDeployer(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory) : base(deploymentParameters, loggerFactory) { } @@ -53,18 +56,19 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS DeploymentParameters.ServerConfigTemplateContent = File.ReadAllText("IIS.config"); } - _application = new IISApplication(DeploymentParameters, Logger); + _application = new IISApplication(IISDeploymentParameters, Logger); // For now, only support using published output DeploymentParameters.PublishApplicationBeforeDeployment = true; + if (DeploymentParameters.PublishApplicationBeforeDeployment) { DotnetPublish(); contentRoot = DeploymentParameters.PublishedApplicationRootPath; + IISDeploymentParameters.AddDebugLogToWebConfig(Path.Combine(contentRoot, $"{_application.WebSiteName}.txt")); + RunWebConfigActions(); } - WebConfigHelpers.AddDebugLogToWebConfig(contentRoot, Path.Combine(contentRoot, $"{_application.WebSiteName}.txt")); - var uri = TestUriHelper.BuildTestUri(ServerType.IIS, DeploymentParameters.ApplicationBaseUriHint); // To prevent modifying the IIS setup concurrently. await _application.StartIIS(uri, contentRoot); @@ -74,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS return new DeploymentResult( LoggerFactory, - DeploymentParameters, + IISDeploymentParameters, applicationBaseUri: uri.ToString(), contentRoot: contentRoot, hostShutdownToken: _hostShutdownToken.Token diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs new file mode 100644 index 0000000000..85e329b824 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs @@ -0,0 +1,63 @@ +// 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.Linq; +using System.Threading.Tasks; +using System.Xml.Linq; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS +{ + public abstract class IISDeployerBase : ApplicationDeployer + { + public IISDeploymentParameters IISDeploymentParameters { get; } + + public IISDeployerBase(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory) + : base(deploymentParameters, loggerFactory) + { + IISDeploymentParameters = deploymentParameters; + } + + public void RunWebConfigActions() + { + if (IISDeploymentParameters == null) + { + return; + } + + if (!DeploymentParameters.PublishApplicationBeforeDeployment) + { + throw new InvalidOperationException("Cannot modify web.config file if no published output."); + } + + var path = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"); + var webconfig = XDocument.Load(path); + var xElement = webconfig.Descendants("system.webServer").Single(); + foreach (var action in IISDeploymentParameters.WebConfigActionList) + { + action.Invoke(xElement); + } + + webconfig.Save(path); + } + + public string RunServerConfigActions(string serverConfigString) + { + if (IISDeploymentParameters == null) + { + return serverConfigString; + } + + var serverConfig = XDocument.Parse(serverConfigString); + var xElement = serverConfig.Descendants("configuration").FirstOrDefault(); + + foreach (var action in IISDeploymentParameters.ServerConfigActionList) + { + action.Invoke(xElement); + } + return xElement.ToString(); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs new file mode 100644 index 0000000000..fb154aeefb --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs @@ -0,0 +1,80 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Linq; + +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS +{ + public static class IISDeploymentParameterExtensions + { + public static void AddDebugLogToWebConfig(this IISDeploymentParameters parameters, string filename) + { + parameters.HandlerSettings["debugLevel"] = "4"; + parameters.HandlerSettings["debugFile"] = filename; + } + + public static void AddServerConfigAction(this IISDeploymentParameters parameters, Action action) + { + parameters.ServerConfigActionList.Add(action); + } + + public static void ModifyWebConfig(this IISDeploymentParameters parameters, Action transform) + { + parameters.WebConfigActionList.Add(transform); + } + + public static void ModifyAspNetCoreSectionInWebConfig(this IISDeploymentParameters parameters, string key, string value) + => ModifyAttributeInWebConfig(parameters, key, value, section: "aspNetCore"); + + + public static void ModifyAttributeInWebConfig(this IISDeploymentParameters parameters, string key, string value, string section) + { + parameters.WebConfigActionList.Add((element) => + { + element.Descendants(section).SingleOrDefault().SetAttributeValue(key, value); + }); + } + + public static void AddHttpsToServerConfig(this IISDeploymentParameters parameters) + { + parameters.ServerConfigActionList.Add( + element => + { + element.Descendants("binding") + .Single() + .SetAttributeValue("protocol", "https"); + + element.Descendants("access") + .Single() + .SetAttributeValue("sslFlags", "Ssl, SslNegotiateCert"); + }); + } + + public static void AddWindowsAuthToServerConfig(this IISDeploymentParameters parameters) + { + parameters.ServerConfigActionList.Add( + element => + { + element.Descendants("windowsAuthentication") + .Single() + .SetAttributeValue("enabled", "true"); + }); + } + + public static void ModifyHandlerSectionInWebConfig(this IISDeploymentParameters parameters, string key, string value) + { + parameters.WebConfigActionList.Add(element => + { + element.Descendants("handlers") + .FirstOrDefault() + .Descendants("add") + .FirstOrDefault() + .SetAttributeValue(key, value); + }); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs new file mode 100644 index 0000000000..9459fd7814 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs @@ -0,0 +1,123 @@ +// 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.Xml.Linq; + +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS +{ + public class IISDeploymentParameters : DeploymentParameters + { + public IISDeploymentParameters() : base() + { + WebConfigActionList = CreateDefaultWebConfigActionList(); + } + + public IISDeploymentParameters(TestVariant variant) + : base(variant) + { + WebConfigActionList = CreateDefaultWebConfigActionList(); + } + + public IISDeploymentParameters( + string applicationPath, + ServerType serverType, + RuntimeFlavor runtimeFlavor, + RuntimeArchitecture runtimeArchitecture) + : base(applicationPath, serverType, runtimeFlavor, runtimeArchitecture) + { + WebConfigActionList = CreateDefaultWebConfigActionList(); + } + + public IISDeploymentParameters(DeploymentParameters parameters) + : base(parameters) + { + WebConfigActionList = CreateDefaultWebConfigActionList(); + + if (parameters is IISDeploymentParameters) + { + var tempParameters = (IISDeploymentParameters)parameters; + WebConfigActionList = tempParameters.WebConfigActionList; + ServerConfigActionList = tempParameters.ServerConfigActionList; + WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables; + HandlerSettings = tempParameters.HandlerSettings; + } + } + + private IList> CreateDefaultWebConfigActionList() + { + return new List>() { AddWebConfigEnvironmentVariables(), AddHandlerSettings() }; + } + + public IList> WebConfigActionList { get; } + + public IList> ServerConfigActionList { get; } = new List>(); + + public IDictionary WebConfigBasedEnvironmentVariables { get; set; } = new Dictionary(); + + public IDictionary HandlerSettings { get; set; } = new Dictionary(); + + private Action AddWebConfigEnvironmentVariables() + { + return xElement => + { + if (WebConfigBasedEnvironmentVariables.Count == 0) + { + return; + } + + var element = xElement.Descendants("environmentVariables").SingleOrDefault(); + if (element == null) + { + element = new XElement("environmentVariables"); + xElement.Descendants("aspNetCore").SingleOrDefault().Add(element); + } + + foreach (var envVar in WebConfigBasedEnvironmentVariables) + { + CreateOrSetElement(element, envVar.Key, envVar.Value, "environmentVariable"); + } + }; + } + + private Action AddHandlerSettings() + { + return xElement => + { + if (HandlerSettings.Count == 0) + { + return; + } + + var element = xElement.Descendants("handlerSettings").SingleOrDefault(); + if (element == null) + { + element = new XElement("handlerSettings"); + xElement.Descendants("aspNetCore").SingleOrDefault().Add(element); + } + + foreach (var handlerSetting in HandlerSettings) + { + CreateOrSetElement(element, handlerSetting.Key, handlerSetting.Value, "handlerSetting"); + } + }; + } + + private static void CreateOrSetElement(XElement rootElement, string name, string value, string elementName) + { + if (rootElement.Descendants() + .Attributes() + .Where(attribute => attribute.Value == name) + .Any()) + { + return; + } + var element = new XElement(elementName); + element.SetAttributeValue("name", name); + element.SetAttributeValue("value", value); + rootElement.Add(element); + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs index 0cd67cc132..ecdd536db5 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs @@ -19,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS /// /// Deployment helper for IISExpress. /// - public class IISExpressDeployer : ApplicationDeployer + public class IISExpressDeployer : IISDeployerBase { private const string IISExpressRunningMessage = "IIS Express is running."; private const string FailedToInitializeBindingsMessage = "Failed to initialize site bindings"; @@ -31,6 +31,11 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS private Process _hostProcess; public IISExpressDeployer(DeploymentParameters deploymentParameters, ILoggerFactory loggerFactory) + : base(new IISDeploymentParameters(deploymentParameters), loggerFactory) + { + } + + public IISExpressDeployer(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory) : base(deploymentParameters, loggerFactory) { } @@ -94,7 +99,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS // Right now this works only for urls like http://localhost:5001/. Does not work for http://localhost:5001/subpath. return new DeploymentResult( LoggerFactory, - DeploymentParameters, + IISDeploymentParameters, applicationBaseUri: actualUri.ToString(), contentRoot: contentRoot, hostShutdownToken: hostExitToken); @@ -272,11 +277,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS if (DeploymentParameters.PublishApplicationBeforeDeployment) { // For published apps, prefer the content in the web.config, but update it. - ModifyAspNetCoreSectionInWebConfig(key: "hostingModel", + IISDeploymentParameters.ModifyAspNetCoreSectionInWebConfig(key: "hostingModel", value: DeploymentParameters.HostingModel == HostingModel.InProcess ? "inprocess" : ""); - ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString()); + IISDeploymentParameters.ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString()); ModifyDotNetExePathInWebConfig(); serverConfig = RemoveRedundantElements(serverConfig); + RunWebConfigActions(); } else { @@ -284,6 +290,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS serverConfig = ReplacePlaceholder(serverConfig, "[HostingModel]", DeploymentParameters.HostingModel.ToString()); serverConfig = ReplacePlaceholder(serverConfig, "[AspNetCoreModule]", DeploymentParameters.AncmVersion.ToString()); } + serverConfig = RunServerConfigActions(serverConfig); DeploymentParameters.ServerConfigLocation = Path.GetTempFileName(); Logger.LogDebug("Saving Config to {configPath}", DeploymentParameters.ServerConfigLocation); @@ -394,29 +401,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { throw new Exception($"Unable to find '{executableName}'.'"); } - ModifyAspNetCoreSectionInWebConfig("processPath", executableName); + IISDeploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", executableName); } } - // Transforms the web.config file to set attributes like hostingModel="inprocess" element - private void ModifyAspNetCoreSectionInWebConfig(string key, string value) - { - var webConfigFile = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"); - var config = XDocument.Load(webConfigFile); - var element = config.Descendants("aspNetCore").FirstOrDefault(); - element.SetAttributeValue(key, value); - config.Save(webConfigFile); - } - - private void ModifyHandlerSectionInWebConfig(string key, string value) - { - var webConfigFile = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"); - var config = XDocument.Load(webConfigFile); - var element = config.Descendants("handlers").FirstOrDefault().Descendants("add").FirstOrDefault(); - element.SetAttributeValue(key, value); - config.Save(webConfigFile); - } - // These elements are duplicated in the web.config if you publish. Remove them from the host.config. private string RemoveRedundantElements(string serverConfig) { diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs deleted file mode 100644 index e5c13225b5..0000000000 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs +++ /dev/null @@ -1,50 +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.IO; -using System.Linq; -using System.Xml.Linq; -using Microsoft.AspNetCore.Server.IntegrationTesting; -using Microsoft.AspNetCore.Testing; - -namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS -{ - public class WebConfigHelpers - { - public static void AddDebugLogToWebConfig(string contentRoot, string filename) - { - var path = Path.Combine(contentRoot, "web.config"); - var webconfig = XDocument.Load(path); - var xElement = webconfig.Descendants("aspNetCore").Single(); - - var element = xElement.Descendants("handlerSettings").SingleOrDefault(); - if (element == null) - { - element = new XElement("handlerSettings"); - xElement.Add(element); - } - - CreateOrSetElement(element, "debugLevel", "4"); - - CreateOrSetElement(element, "debugFile", Path.Combine(contentRoot, filename)); - - webconfig.Save(path); - } - - private static void CreateOrSetElement(XElement rootElement, string name, string value) - { - if (rootElement.Descendants() - .Attributes() - .Where(attribute => attribute.Value == name) - .Any()) - { - return; - } - var element = new XElement("handlerSetting"); - element.SetAttributeValue("name", name); - element.SetAttributeValue("value", value); - rootElement.Add(element); - } - } -} diff --git a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs index 6384fd508e..2b0b0c9ada 100644 --- a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs +++ b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs @@ -21,17 +21,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests [InlineData("CheckLogFile")] public async Task CheckStdoutLoggingToFile(string path) { - var deploymentParameters = Helpers.GetBaseDeploymentParameters(); - deploymentParameters.PublishApplicationBeforeDeployment = true; + var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); + + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogEnabled", "true"); + + var pathToLogs = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogFile", Path.Combine(pathToLogs, "std")); var deploymentResult = await DeployAsync(deploymentParameters); - var pathToLogs = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); try { - Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogEnabled", "true"); - Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogFile", Path.Combine(pathToLogs, "std")); - await Helpers.AssertStarts(deploymentResult, path); StopServer(); @@ -63,10 +63,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogEnabled", "true"); + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogFile", Path.Combine("Q:", "std")); + var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogEnabled", "true"); - Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "stdoutLogFile", Path.Combine("Q:", "std")); await Helpers.AssertStarts(deploymentResult, "HelloWorld"); } @@ -80,11 +81,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = tempFile; + deploymentParameters.AddDebugLogToWebConfig(tempFile); var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.AddDebugLogToWebConfig(deploymentResult.DeploymentResult.ContentRoot, tempFile); - var response = await deploymentResult.RetryingHttpClient.GetAsync("/"); StopServer(); @@ -123,11 +123,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task CheckStdoutLoggingToPipeWithFirstWrite(string path) { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); - - var deploymentResult = await DeployAsync(deploymentParameters); var firstWriteString = path + path; - Helpers.ModifyEnvironmentVariableCollectionInWebConfig(deploymentResult, "ASPNETCORE_INPROCESS_INITIAL_WRITE", firstWriteString); + deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_INITIAL_WRITE"] = firstWriteString; + + var deploymentResult = await DeployAsync(deploymentParameters); await Helpers.AssertStarts(deploymentResult, path); @@ -152,9 +152,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = firstTempFile; + deploymentParameters.AddDebugLogToWebConfig(secondTempFile); var deploymentResult = await DeployAsync(deploymentParameters); - WebConfigHelpers.AddDebugLogToWebConfig(deploymentParameters.PublishedApplicationRootPath, secondTempFile); var response = await deploymentResult.RetryingHttpClient.GetAsync("/"); diff --git a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs index 667c47327c..40d5247e01 100644 --- a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs +++ b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -25,15 +26,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite", publish: true); var randomNumberString = new Random(Guid.NewGuid().GetHashCode()).Next(10000000).ToString(); - - var environmentVariablesInWebConfig = new Dictionary - { - ["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path, - ["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString - }; + deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path; + deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString; var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.AddEnvironmentVariablesToWebConfig(deploymentResult.DeploymentResult.ContentRoot, environmentVariablesInWebConfig); var response = await deploymentResult.RetryingHttpClient.GetAsync(path); @@ -52,16 +48,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task CheckStdoutWithLargeWrites(string path) { var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite", publish: true); - - var environmentVariablesInWebConfig = new Dictionary - { - ["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path - }; + deploymentParameters.WebConfigBasedEnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path; var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.AddEnvironmentVariablesToWebConfig(deploymentResult.DeploymentResult.ContentRoot, environmentVariablesInWebConfig); - var response = await deploymentResult.RetryingHttpClient.GetAsync(path); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); diff --git a/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs b/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs index 876b8e010f..8ae0c7dc89 100644 --- a/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs +++ b/test/Common.FunctionalTests/OutOfProcess/HelloWorldTest.cs @@ -5,6 +5,7 @@ using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { // The default in hosting sets windows auth to true. // Set it to the IISExpress.config file - var deploymentParameters = new DeploymentParameters(variant) + var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath() }; diff --git a/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs b/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs index 4827fcaecc..ed493f79ef 100644 --- a/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs +++ b/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs @@ -3,6 +3,7 @@ using System.IO; using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.Extensions.Logging.Testing; using Xunit.Abstractions; @@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting private ApplicationDeployer _deployer; - protected virtual async Task DeployAsync(DeploymentParameters parameters) + protected virtual async Task DeployAsync(IISDeploymentParameters parameters) { if (!parameters.EnvironmentVariables.ContainsKey(DebugEnvironmentVariable)) { diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs index 1a905714b8..f4348514d1 100644 --- a/test/Common.FunctionalTests/Utilities/Helpers.cs +++ b/test/Common.FunctionalTests/Utilities/Helpers.cs @@ -1,12 +1,14 @@ // 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.Linq; using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing; using Xunit; @@ -22,117 +24,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public static string GetInProcessTestSitesPath() => GetTestWebSitePath("InProcessWebSite"); public static string GetOutOfProcessTestSitesPath() => GetTestWebSitePath("OutOfProcessWebSite"); - - public static void ModifyAspNetCoreSectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value) - => ModifyAttributeInWebConfig(deploymentResult, key, value, section: "aspNetCore"); - - public static void ModifyAttributeInWebConfig(IISDeploymentResult deploymentResult, string key, string value, string section) - { - var webConfigFile = GetWebConfigFile(deploymentResult); - var config = XDocument.Load(webConfigFile); - - var element = config.Descendants(section).Single(); - element.SetAttributeValue(key, value); - - config.Save(webConfigFile); - } - - public static void ModifyEnvironmentVariableCollectionInWebConfig(IISDeploymentResult deploymentResult, string key, string value) - { - var webConfigFile = GetWebConfigFile(deploymentResult); - var config = XDocument.Load(webConfigFile); - - var envVarElement = new XElement("environmentVariable"); - envVarElement.SetAttributeValue("name", key); - envVarElement.SetAttributeValue("value", value); - - config.Descendants("aspNetCore").Single() - .Descendants("environmentVariables").Single() - .Add(envVarElement); - - config.Save(webConfigFile); - } - - public static void ModifyHandlerSectionInWebConfig(IISDeploymentResult deploymentResult, string handlerVersionValue) - { - var webConfigFile = GetWebConfigFile(deploymentResult); - var config = XDocument.Load(webConfigFile); - - var handlerVersionElement = new XElement("handlerSetting"); - handlerVersionElement.SetAttributeValue("name", "handlerVersion"); - handlerVersionElement.SetAttributeValue("value", handlerVersionValue); - - config.Descendants("aspNetCore").Single() - .Add(new XElement("handlerSettings", handlerVersionElement)); - - config.Save(webConfigFile); - } - - public static void AddDebugLogToWebConfig(string contentRoot, string filename) - { - var path = Path.Combine(contentRoot, "web.config"); - var webconfig = XDocument.Load(path); - var xElement = webconfig.Descendants("aspNetCore").Single(); - - var element = xElement.Descendants("handlerSettings").SingleOrDefault(); - if (element == null) - { - element = new XElement("handlerSettings"); - xElement.Add(element); - } - - CreateOrSetElement(element, "debugLevel", "4", "handlerSetting"); - - CreateOrSetElement(element, "debugFile", Path.Combine(contentRoot, filename), "handlerSetting"); - - webconfig.Save(path); - } - - public static void AddEnvironmentVariablesToWebConfig(string contentRoot, IDictionary environmentVariables) - { - var path = Path.Combine(contentRoot, "web.config"); - var webconfig = XDocument.Load(path); - var xElement = webconfig.Descendants("aspNetCore").Single(); - - var element = xElement.Descendants("environmentVariables").SingleOrDefault(); - if (element == null) - { - element = new XElement("environmentVariables"); - xElement.Add(element); - } - - foreach (var envVar in environmentVariables) - { - CreateOrSetElement(element, envVar.Key, envVar.Value, "environmentVariable"); - } - - webconfig.Save(path); - } - - public static void CreateOrSetElement(XElement rootElement, string name, string value, string elementName) - { - if (rootElement.Descendants() - .Attributes() - .Where(attribute => attribute.Value == name) - .Any()) - { - return; - } - var element = new XElement(elementName); - element.SetAttributeValue("name", name); - element.SetAttributeValue("value", value); - rootElement.Add(element); - } - + // Defaults to inprocess specific deployment parameters - public static DeploymentParameters GetBaseDeploymentParameters(string site = null, HostingModel hostingModel = HostingModel.InProcess, bool publish = false) + public static IISDeploymentParameters GetBaseDeploymentParameters(string site = null, HostingModel hostingModel = HostingModel.InProcess, bool publish = false) { if (site == null) { site = hostingModel == HostingModel.InProcess ? "InProcessWebSite" : "OutOfProcessWebSite"; } - return new DeploymentParameters(GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) + return new IISDeploymentParameters(GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) { TargetFramework = Tfm.NetCoreApp22, ApplicationType = ApplicationType.Portable, @@ -142,9 +43,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests }; } - private static string GetWebConfigFile(IISDeploymentResult deploymentResult) - => Path.Combine(deploymentResult.DeploymentResult.ContentRoot, "web.config"); - public static async Task AssertStarts(IISDeploymentResult deploymentResult, string path = "/HelloWorld") { var response = await deploymentResult.RetryingHttpClient.GetAsync(path); diff --git a/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs b/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs index d4c74c551b..a20a5e2e0e 100644 --- a/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs +++ b/test/Common.FunctionalTests/Utilities/IISFunctionalTestBase.cs @@ -1,11 +1,6 @@ // 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.Linq; -using System.Threading.Tasks; -using System.Xml.Linq; -using Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests; using Microsoft.AspNetCore.Server.IntegrationTesting; using Xunit.Abstractions; @@ -16,36 +11,5 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities public IISFunctionalTestBase(ITestOutputHelper output = null) : base(output) { } - - protected string GetServerConfig(Action transform) - { - var doc = XDocument.Load(DeployerSelector.ServerType == ServerType.IIS ? "IIS.config" : "IISExpress.config"); - transform?.Invoke(doc.Root); - return doc.ToString(); - } - - protected string GetHttpsServerConfig() - { - return GetServerConfig( - element => { - element.Descendants("binding") - .Single() - .SetAttributeValue("protocol", "https"); - - element.Descendants("access") - .Single() - .SetAttributeValue("sslFlags", "Ssl, SslNegotiateCert"); - }); - } - - protected string GetWindowsAuthConfig() - { - return GetServerConfig( - element => { - element.Descendants("windowsAuthentication") - .Single() - .SetAttributeValue("enabled", "true"); - }); - } } } diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs index d8fd3342ed..787276a8fa 100644 --- a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs +++ b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Net.Http; using System.Threading; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; @@ -20,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var logging = AssemblyTestLog.ForAssembly(typeof(IISTestSiteFixture).Assembly); - var deploymentParameters = new DeploymentParameters(Helpers.GetInProcessTestSitesPath(), + var deploymentParameters = new IISDeploymentParameters(Helpers.GetInProcessTestSitesPath(), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) diff --git a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs index 31179b1ecf..0281116218 100644 --- a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs @@ -5,6 +5,7 @@ using System.Net; using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; @@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task Authentication_InProcess() { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); - deploymentParameters.ServerConfigTemplateContent = GetWindowsAuthConfig(); + deploymentParameters.AddWindowsAuthToServerConfig(); var deploymentResult = await DeployAsync(deploymentParameters); diff --git a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs index 4de6ceba3d..9c97e78b2f 100644 --- a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs @@ -8,6 +8,7 @@ using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -27,8 +28,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { // Point to dotnet installed in user profile. await AssertStarts( - deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", "%DotnetPath%"), - deploymentParameters => deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation); + deploymentParameters => + { + deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation; + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", "%DotnetPath%"); + } + ); } [ConditionalTheory] @@ -38,11 +43,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task InvalidProcessPath_ExpectServerError(string path) { var deploymentParameters = GetBaseDeploymentParameters(); + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", path); var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", path); - var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld"); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); @@ -54,16 +58,23 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf(".")); await AssertStarts( - deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", dotnetLocationWithoutExtension)); + deploymentParameters => + { + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", dotnetLocationWithoutExtension); + } + ); } [ConditionalFact] public async Task StartsWithDotnetLocationUppercase() { var dotnetLocationWithoutExtension = _dotnetLocation.Substring(0, _dotnetLocation.LastIndexOf(".")).ToUpperInvariant(); - await AssertStarts( - deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", dotnetLocationWithoutExtension)); + deploymentParameters => + { + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", dotnetLocationWithoutExtension); + } + ); } [ConditionalTheory] @@ -72,14 +83,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task StartsWithDotnetOnThePath(string path) { await AssertStarts( - deploymentResult => Helpers.ModifyAspNetCoreSectionInWebConfig(deploymentResult, "processPath", path), - deploymentParameters => deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation)); + deploymentParameters => + { + deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation); + deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", path); + } + ); // Verify that in this scenario where.exe was invoked only once by shim and request handler uses cached value Assert.Equal(1, TestSink.Writes.Count(w => w.Message.Contains("Invoking where.exe to find dotnet.exe"))); } - private async Task AssertStarts(Action postDeploy, Action preDeploy = null) + private async Task AssertStarts(Action preDeploy = null) { var deploymentParameters = GetBaseDeploymentParameters(); @@ -87,8 +102,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var deploymentResult = await DeployAsync(deploymentParameters); - postDeploy?.Invoke(deploymentResult); - var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld"); var responseText = await response.Content.ReadAsStringAsync(); @@ -105,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests [MemberData(nameof(TestVariants))] public async Task HelloWorld(TestVariant variant) { - var deploymentParameters = new DeploymentParameters(variant) + var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetInProcessTestSitesPath(), PublishApplicationBeforeDeployment = true @@ -132,9 +145,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } // Defaults to inprocess specific deployment parameters - public static DeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite") + public static IISDeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite") { - return new DeploymentParameters(Helpers.GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) + return new IISDeploymentParameters(Helpers.GetTestWebSitePath(site), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) { TargetFramework = Tfm.NetCoreApp22, ApplicationType = ApplicationType.Portable, diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index fd53c0ffbb..84be58247c 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -1,16 +1,15 @@ // 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.Linq; using System.Threading.Tasks; using System.Xml.Linq; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; -using Xunit.Abstractions; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { @@ -28,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var deploymentParameters = GetGlobalVersionBaseDeploymentParameters(); deploymentParameters.PublishApplicationBeforeDeployment = false; - deploymentParameters.ServerConfigTemplateContent = GetServerConfig( + deploymentParameters.AddServerConfigAction( element => { var handlerVersionElement = new XElement("handlerSetting"); @@ -52,11 +51,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task GlobalVersion_NewVersionNumber_Fails(string version) { var deploymentParameters = GetGlobalVersionBaseDeploymentParameters(); + deploymentParameters.HandlerSettings["handlerVersion"] = version; var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.ModifyHandlerSectionInWebConfig(deploymentResult, version); - var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest); Assert.False(response.IsSuccessStatusCode); } @@ -68,11 +66,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = GetGlobalVersionBaseDeploymentParameters(); deploymentParameters.AdditionalPublishParameters = $"{_outOfProcessVersionVariable}{version}"; + deploymentParameters.HandlerSettings["handlerVersion"] = version; var deploymentResult = await DeployAsync(deploymentParameters); - Helpers.ModifyHandlerSectionInWebConfig(deploymentResult, version); - var response = await deploymentResult.RetryingHttpClient.GetAsync(_helloWorldRequest); var responseText = await response.Content.ReadAsStringAsync(); Assert.Equal(_helloWorldResponse, responseText); @@ -140,9 +137,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests AssertLoadedVersion(version); } - private DeploymentParameters GetGlobalVersionBaseDeploymentParameters() + private IISDeploymentParameters GetGlobalVersionBaseDeploymentParameters() { - return new DeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) + return new IISDeploymentParameters(Helpers.GetOutOfProcessTestSitesPath(), DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) { TargetFramework = Tfm.NetCoreApp22, ApplicationType = ApplicationType.Portable, diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs b/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs index 543481ee14..ff9996c851 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/HttpsTest.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.Common; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -33,13 +34,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task HttpsHelloWorld(TestVariant variant) { var port = TestPortHelper.GetNextSSLPort(); - var deploymentParameters = new DeploymentParameters(variant) + var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(), - ApplicationBaseUriHint = $"https://localhost:{port}/", - ServerConfigTemplateContent = GetHttpsServerConfig() + ApplicationBaseUriHint = $"https://localhost:{port}/" }; + deploymentParameters.AddHttpsToServerConfig(); + var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler @@ -71,13 +73,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests private async Task HttpsHelloWorldCerts(TestVariant variant, bool sendClientCert) { var port = TestPortHelper.GetNextSSLPort(); - var deploymentParameters = new DeploymentParameters(variant) + var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(), ApplicationBaseUriHint = $"https://localhost:{port}/", - ServerConfigTemplateContent = GetHttpsServerConfig() }; + deploymentParameters.AddHttpsToServerConfig(); + var deploymentResult = await DeployAsync(deploymentParameters); var handler = new HttpClientHandler diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs b/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs index 9aab93a56f..437f019f52 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/NtlmAuthentationTest.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -31,13 +32,14 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests [MemberData(nameof(TestVariants))] public async Task NtlmAuthentication(TestVariant variant) { - var deploymentParameters = new DeploymentParameters(variant) + var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(), - ApplicationBaseUriHint = $"http://localhost:0/", - ServerConfigTemplateContent = GetWindowsAuthConfig() + ApplicationBaseUriHint = $"http://localhost:0/" }; + deploymentParameters.AddWindowsAuthToServerConfig(); + var result = await DeployAsync(deploymentParameters); var response = await result.RetryingHttpClient.GetAsync("/HelloWorld"); diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs index 83d6a8e20a..038f57029d 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/WindowsAuthTests.cs @@ -5,6 +5,7 @@ using System.IO; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -27,11 +28,11 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests [MemberData(nameof(TestVariants))] public async Task WindowsAuthTest(TestVariant variant) { - var deploymentParameters = new DeploymentParameters(variant) + var deploymentParameters = new IISDeploymentParameters(variant) { ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(), - ServerConfigTemplateContent = GetWindowsAuthConfig() }; + deploymentParameters.AddWindowsAuthToServerConfig(); // The default in hosting sets windows auth to true. var deploymentResult = await DeployAsync(deploymentParameters); diff --git a/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs b/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs index dc64262d00..316a87f9b3 100644 --- a/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs +++ b/test/IISExpress.FunctionalTests/UpgradeFeatureDetectionTests.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; using Xunit.Abstractions; @@ -59,7 +60,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests private async Task UpgradeFeatureDetectionDeployer(bool disableWebSocket, string sitePath, string expected, HostingModel hostingModel) { - var deploymentParameters = new DeploymentParameters(sitePath, DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) + var deploymentParameters = new IISDeploymentParameters(sitePath, DeployerSelector.ServerType, RuntimeFlavor.CoreClr, RuntimeArchitecture.x64) { TargetFramework = Tfm.NetCoreApp22, ApplicationType = ApplicationType.Portable, @@ -71,7 +72,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests if (disableWebSocket) { // For IIS, we need to modify the apphost.config file - deploymentParameters.ServerConfigTemplateContent = GetServerConfig( + deploymentParameters.AddServerConfigAction( element => element.Descendants("webSocket") .Single() .SetAttributeValue("enabled", "false")); From 256aed83699aea838635aed65d1ec45f615e4533 Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Thu, 19 Jul 2018 23:20:13 -0700 Subject: [PATCH 05/10] Make IISExpress shutdown gracefully. (#1066) --- build/dependencies.props | 48 ++++++------- .../CommonLib/aspnetcore_msg.mc | 7 ++ src/AspNetCoreModuleV2/CommonLib/resources.h | 1 + .../inprocessapplication.cpp | 8 +++ .../ApplicationDeployerFactory.cs | 2 +- .../IISApplication.cs | 11 +-- .../IISDeployer.cs | 6 +- .../IISDeployerBase.cs | 1 + .../IISDeploymentParameters.cs | 4 ++ .../IISDeploymentResult.cs | 57 +++++++++++++++ .../IISExpressDeployer.cs | 71 +++++++++++++++++-- .../LoggingHandler.cs | 2 +- .../RetryHandler.cs | 2 +- .../TestUriHelper.cs | 0 .../Inprocess/EventLogTests.cs | 13 ++++ .../Inprocess/LoggingTests.cs | 1 - .../Utilities/FunctionalTestsBase.cs | 7 +- .../Utilities/IISDeploymentResult.cs | 42 ----------- test/IIS.Tests/Utilities/TestServer.cs | 1 + .../IISExpress.FunctionalTests.csproj | 1 - .../InProcess/AppOfflineTests.cs | 17 ++--- .../InProcess/AuthenticationTests.cs | 2 +- .../InProcess/ShutdownTests.cs | 25 ++++++- .../OutOfProcess/GlobalVersionTests.cs | 4 +- 24 files changed, 235 insertions(+), 98 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs rename {test/Common.Tests/Utilities => src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS}/LoggingHandler.cs (96%) rename {test/Common.Tests/Utilities => src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS}/RetryHandler.cs (96%) delete mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/TestUriHelper.cs delete mode 100644 test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs diff --git a/build/dependencies.props b/build/dependencies.props index f4a8fd8eff..f66a72c941 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -5,36 +5,36 @@ 0.10.13 2.2.0-preview1-17099 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 0.6.0-a-preview1-DeploymentParameters-17085 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 15.6.82 15.6.82 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 - 2.2.0-preview1-34694 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 + 2.2.0-preview1-34709 2.0.9 2.1.2 2.2.0-preview1-26618-02 - 2.2.0-preview1-34694 + 2.2.0-preview1-34709 15.6.1 11.1.0 2.0.3 diff --git a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc index c15047b235..96172c6e24 100644 --- a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc +++ b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc @@ -224,6 +224,13 @@ Language=English %1 . + +Messageid=1033 +SymbolicName=ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL +Language=English +%1 +. + ; ;#endif // _ASPNETCORE_MODULE_MSG_H_ ; diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h index 2956cce581..861619e5b2 100644 --- a/src/AspNetCoreModuleV2/CommonLib/resources.h +++ b/src/AspNetCoreModuleV2/CommonLib/resources.h @@ -26,6 +26,7 @@ #define ASPNETCORE_EVENT_SENT_SHUTDOWN_HTTP_REQUEST_MSG L"Sent shutdown HTTP message to process '%d' and received http status '%d'." #define ASPNETCORE_EVENT_APP_SHUTDOWN_FAILURE_MSG L"Failed to gracefully shutdown application '%s'." #define ASPNETCORE_EVENT_LOAD_CLR_FALIURE_MSG L"Application '%s' with physical root '%s' failed to load clr and managed application, ErrorCode = '0x%x." +#define ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG L"Application '%s' has shutdown." #define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG L"Only one inprocess application is allowed per IIS application pool. Please assign the application '%s' to a different IIS application pool." #define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)." #define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'." diff --git a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp index baf73ec9c1..b52b08f833 100644 --- a/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp +++ b/src/AspNetCoreModuleV2/InProcessRequestHandler/inprocessapplication.cpp @@ -126,6 +126,14 @@ Finished: // exit(hr); } + else + { + UTILITY::LogEventF(g_hEventLog, + EVENTLOG_INFORMATION_TYPE, + ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL, + ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG, + m_pConfig->QueryConfigPath()->QueryStr()); + } } VOID diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs index aaec90971e..8fddbaede6 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/ApplicationDeployerFactory.cs @@ -33,7 +33,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting switch (deploymentParameters.ServerType) { case ServerType.IISExpress: - return new IIS.IISExpressDeployer(deploymentParameters, loggerFactory); + return new IISExpressDeployer(deploymentParameters, loggerFactory); case ServerType.IIS: return new IISDeployer(deploymentParameters, loggerFactory); default: diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs index d0c0bfb153..c1a26d3181 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting /// internal class IISApplication { - private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(5); + private static readonly TimeSpan _timeout = TimeSpan.FromSeconds(10); private static readonly TimeSpan _retryDelay = TimeSpan.FromMilliseconds(200); private readonly ServerManager _serverManager = new ServerManager(); private readonly DeploymentParameters _deploymentParameters; @@ -32,6 +32,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting "config", "applicationhost.config"); + public Process HostProcess { get; set; } + public IISApplication(DeploymentParameters deploymentParameters, ILogger logger) { _deploymentParameters = deploymentParameters; @@ -63,7 +65,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting } AddTemporaryAppHostConfig(); - ConfigureAppPool(contentRoot); + var apppool = ConfigureAppPool(contentRoot); ConfigureSite(contentRoot, port); @@ -76,7 +78,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting _serverManager.CommitChanges(); - await WaitUntilSiteStarted(); + await WaitUntilSiteStarted(apppool); } } @@ -89,7 +91,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting config.Save(webConfigFile); } - private async Task WaitUntilSiteStarted() + private async Task WaitUntilSiteStarted(ApplicationPool appPool) { var sw = Stopwatch.StartNew(); @@ -98,6 +100,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting try { var site = _serverManager.Sites.FirstOrDefault(s => s.Name.Equals(WebSiteName)); + if (site.State == ObjectState.Started) { _logger.LogInformation($"Site {WebSiteName} has started."); diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index bb126a7fa5..c093ae3065 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -75,13 +75,13 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS // Warm up time for IIS setup. Logger.LogInformation("Successfully finished IIS application directory setup."); - - return new DeploymentResult( + return new IISDeploymentResult( LoggerFactory, IISDeploymentParameters, applicationBaseUri: uri.ToString(), contentRoot: contentRoot, - hostShutdownToken: _hostShutdownToken.Token + hostShutdownToken: _hostShutdownToken.Token, + hostProcess: _application.HostProcess ); } } diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs index 85e329b824..04e8448327 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics; using System.IO; using System.Linq; using System.Threading.Tasks; diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs index 9459fd7814..a22116d557 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameters.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; +using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { @@ -43,6 +44,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS ServerConfigActionList = tempParameters.ServerConfigActionList; WebConfigBasedEnvironmentVariables = tempParameters.WebConfigBasedEnvironmentVariables; HandlerSettings = tempParameters.HandlerSettings; + GracefulShutdown = tempParameters.GracefulShutdown; } } @@ -59,6 +61,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS public IDictionary HandlerSettings { get; set; } = new Dictionary(); + public bool GracefulShutdown { get; set; } + private Action AddWebConfigEnvironmentVariables() { return xElement => diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs new file mode 100644 index 0000000000..4a9d881900 --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentResult.cs @@ -0,0 +1,57 @@ +// 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.Diagnostics; +using System.Net.Http; +using System.Threading; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS +{ + public class IISDeploymentResult : DeploymentResult + { + public ILogger Logger { get; set; } + public Process HostProcess { get; } + + public IISDeploymentResult(ILoggerFactory loggerFactory, + IISDeploymentParameters deploymentParameters, + string applicationBaseUri, + string contentRoot, + CancellationToken hostShutdownToken, + Process hostProcess) + : base(loggerFactory, + deploymentParameters, + applicationBaseUri, + contentRoot, + hostShutdownToken) + { + HostProcess = hostProcess; + Logger = loggerFactory.CreateLogger(deploymentParameters.SiteName); + // SocketsHttpHandler isn't available in netstandard2.0 + RetryingHttpClient = CreateRetryClient(new HttpClientHandler()); + HttpClient = CreateClient(new HttpClientHandler()); + } + + public HttpClient CreateRetryClient(HttpMessageHandler messageHandler) + { + var loggingHandler = new LoggingHandler(messageHandler, Logger); + var retryHandler = new RetryHandler(loggingHandler, Logger); + return new HttpClient(retryHandler) + { + BaseAddress = base.HttpClient.BaseAddress + }; + } + + public HttpClient CreateClient(HttpMessageHandler messageHandler) + { + return new HttpClient(new LoggingHandler(messageHandler, Logger)) + { + BaseAddress = base.HttpClient.BaseAddress + }; + } + + public HttpClient RetryingHttpClient { get; set; } + + public new HttpClient HttpClient { get; set; } + } +} diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs index ecdd536db5..729c5f870f 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; @@ -25,7 +26,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS private const string FailedToInitializeBindingsMessage = "Failed to initialize site bindings"; private const string UnableToStartIISExpressMessage = "Unable to start iisexpress."; private const int MaximumAttempts = 5; - + private readonly TimeSpan ShutdownTimeSpan = TimeSpan.FromSeconds(60); private static readonly Regex UrlDetectorRegex = new Regex(@"^\s*Successfully registered URL ""(?[^""]+)"" for site.*$"); private Process _hostProcess; @@ -97,12 +98,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS Logger.LogInformation("Application ready at URL: {appUrl}", actualUri); // Right now this works only for urls like http://localhost:5001/. Does not work for http://localhost:5001/subpath. - return new DeploymentResult( + + return new IISDeploymentResult( LoggerFactory, IISDeploymentParameters, applicationBaseUri: actualUri.ToString(), contentRoot: contentRoot, - hostShutdownToken: hostExitToken); + hostShutdownToken: hostExitToken, + hostProcess: _hostProcess); } } @@ -352,7 +355,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { using (Logger.BeginScope("Dispose")) { - ShutDownIfAnyHostProcess(_hostProcess); + if (IISDeploymentParameters.GracefulShutdown) + { + GracefullyShutdownProcess(_hostProcess); + } + else + { + ShutDownIfAnyHostProcess(_hostProcess); + } if (!string.IsNullOrEmpty(DeploymentParameters.ServerConfigLocation) && File.Exists(DeploymentParameters.ServerConfigLocation)) @@ -388,6 +398,59 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS } } + private class WindowsNativeMethods + { + [DllImport("user32.dll")] + internal static extern IntPtr GetTopWindow(IntPtr hWnd); + [DllImport("user32.dll")] + internal static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); + [DllImport("user32.dll")] + internal static extern uint GetWindowThreadProcessId(IntPtr hwnd, out uint lpdwProcessId); + [DllImport("user32.dll")] + internal static extern bool PostMessage(HandleRef hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + } + + private static void SendStopMessageToProcess(int pid) + { + for (var ptr = WindowsNativeMethods.GetTopWindow(IntPtr.Zero); ptr != IntPtr.Zero; ptr = WindowsNativeMethods.GetWindow(ptr, 2)) + { + uint num; + WindowsNativeMethods.GetWindowThreadProcessId(ptr, out num); + if (pid == num) + { + var hWnd = new HandleRef(null, ptr); + WindowsNativeMethods.PostMessage(hWnd, 0x12, IntPtr.Zero, IntPtr.Zero); + return; + } + } + } + + private void GracefullyShutdownProcess(Process hostProcess) + { + if (hostProcess != null && !hostProcess.HasExited) + { + // Calling hostProcess.StandardInput.WriteLine("q") with StandardInput redirected + // for the process does not work when stopping IISExpress + // Also, hostProcess.CloseMainWindow() doesn't work either. + // Instead we have to send WM_QUIT to the iisexpress process via pInvokes. + // See: https://stackoverflow.com/questions/4772092/starting-and-stopping-iis-express-programmatically + + SendStopMessageToProcess(hostProcess.Id); + if (!hostProcess.WaitForExit((int)ShutdownTimeSpan.TotalMilliseconds)) + { + throw new InvalidOperationException($"iisexpress Process {hostProcess.Id} failed to gracefully shutdown."); + } + if (hostProcess.ExitCode != 0) + { + Logger.LogWarning($"IISExpress exit code is non-zero after graceful shutdown. Exit code: {hostProcess.ExitCode}"); + } + } + else + { + throw new InvalidOperationException($"iisexpress Process {hostProcess.Id} crashed before shutdown was triggered."); + } + } + private void ModifyDotNetExePathInWebConfig() { // We assume the x64 dotnet.exe is on the path so we need to provide an absolute path for x86 scenarios. diff --git a/test/Common.Tests/Utilities/LoggingHandler.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/LoggingHandler.cs similarity index 96% rename from test/Common.Tests/Utilities/LoggingHandler.cs rename to src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/LoggingHandler.cs index 9559d8106c..241991f62d 100644 --- a/test/Common.Tests/Utilities/LoggingHandler.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/LoggingHandler.cs @@ -4,7 +4,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Server.IntegrationTesting +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { public class LoggingHandler: DelegatingHandler { diff --git a/test/Common.Tests/Utilities/RetryHandler.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/RetryHandler.cs similarity index 96% rename from test/Common.Tests/Utilities/RetryHandler.cs rename to src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/RetryHandler.cs index 00e1174c7a..4282c3afca 100644 --- a/test/Common.Tests/Utilities/RetryHandler.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/RetryHandler.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; -namespace Microsoft.AspNetCore.Server.IntegrationTesting +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { public class RetryHandler : DelegatingHandler { diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/TestUriHelper.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/TestUriHelper.cs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs index 176661189c..67483b0663 100644 --- a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs +++ b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs @@ -20,5 +20,18 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests EventLogHelpers.VerifyEventLogEvent(TestSink, "Application '.+' started the coreclr in-process successfully."); } + + [ConditionalFact] + public async Task CheckShutdownEventLogMessage() + { + var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); + deploymentParameters.GracefulShutdown = true; + var deploymentResult = await DeployAsync(deploymentParameters); + await Helpers.AssertStarts(deploymentResult); + + StopServer(); + + EventLogHelpers.VerifyEventLogEvent(TestSink, "Application '.+' has shutdown."); + } } } diff --git a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs index 2b0b0c9ada..e8e303b429 100644 --- a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs +++ b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs @@ -68,7 +68,6 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var deploymentResult = await DeployAsync(deploymentParameters); - await Helpers.AssertStarts(deploymentResult, "HelloWorld"); } diff --git a/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs b/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs index ed493f79ef..d23b7836e5 100644 --- a/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs +++ b/test/Common.FunctionalTests/Utilities/FunctionalTestsBase.cs @@ -17,7 +17,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting { } - private ApplicationDeployer _deployer; + protected ApplicationDeployer _deployer; protected virtual async Task DeployAsync(IISDeploymentParameters parameters) { @@ -31,11 +31,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting parameters.ServerConfigTemplateContent = parameters.ServerConfigTemplateContent ?? File.ReadAllText("IISExpress.config"); } + _deployer = IISApplicationDeployerFactory.Create(parameters, LoggerFactory); - var result = await _deployer.DeployAsync(); - - return new IISDeploymentResult(result, Logger); + return (IISDeploymentResult)await _deployer.DeployAsync(); } public override void Dispose() diff --git a/test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs b/test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs deleted file mode 100644 index 8e39634f2b..0000000000 --- a/test/Common.FunctionalTests/Utilities/IISDeploymentResult.cs +++ /dev/null @@ -1,42 +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.Net.Http; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AspNetCore.Server.IntegrationTesting -{ - public class IISDeploymentResult - { - public DeploymentResult DeploymentResult { get; } - public ILogger Logger { get; } - - public IISDeploymentResult(DeploymentResult deploymentResult, ILogger logger) - { - DeploymentResult = deploymentResult; - Logger = logger; - - RetryingHttpClient = CreateRetryClient(new SocketsHttpHandler()); - HttpClient = CreateClient(new SocketsHttpHandler()); - } - - public HttpClient CreateRetryClient(HttpMessageHandler messageHandler) - { - return new HttpClient(new RetryHandler(new LoggingHandler(messageHandler, Logger), Logger)) - { - BaseAddress = DeploymentResult.HttpClient.BaseAddress - }; - } - - public HttpClient CreateClient(HttpMessageHandler messageHandler) - { - return new HttpClient(new LoggingHandler(messageHandler, Logger)) - { - BaseAddress = DeploymentResult.HttpClient.BaseAddress - }; - } - - public HttpClient HttpClient { get; set; } - public HttpClient RetryingHttpClient { get; set; } - } -} diff --git a/test/IIS.Tests/Utilities/TestServer.cs b/test/IIS.Tests/Utilities/TestServer.cs index c64fe4fbe9..4adaaff776 100644 --- a/test/IIS.Tests/Utilities/TestServer.cs +++ b/test/IIS.Tests/Utilities/TestServer.cs @@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; diff --git a/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj b/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj index cbd3d05b6b..3ae8fcffe8 100644 --- a/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj +++ b/test/IISExpress.FunctionalTests/IISExpress.FunctionalTests.csproj @@ -29,7 +29,6 @@ - diff --git a/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs b/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs index b7e850cdb8..265907542f 100644 --- a/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/AppOfflineTests.cs @@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Testing.xunit; using Microsoft.Extensions.Logging; using Xunit; +using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess { @@ -26,7 +27,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess { var deploymentResult = await DeployApp(hostingModel); - AddAppOffline(deploymentResult.DeploymentResult.ContentRoot); + AddAppOffline(deploymentResult.ContentRoot); await AssertAppOffline(deploymentResult); } @@ -39,7 +40,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess var expectedResponse = "The app is offline."; var deploymentResult = await DeployApp(hostingModel); - AddAppOffline(deploymentResult.DeploymentResult.ContentRoot, expectedResponse); + AddAppOffline(deploymentResult.ContentRoot, expectedResponse); await AssertAppOffline(deploymentResult, expectedResponse); } @@ -49,7 +50,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess { var deploymentResult = await AssertStarts(HostingModel.InProcess); - AddAppOffline(deploymentResult.DeploymentResult.ContentRoot); + AddAppOffline(deploymentResult.ContentRoot); await AssertStopsProcess(deploymentResult); } @@ -62,9 +63,9 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess // Repeat dropping file and restarting multiple times for (int i = 0; i < 5; i++) { - AddAppOffline(deploymentResult.DeploymentResult.ContentRoot); + AddAppOffline(deploymentResult.ContentRoot); await AssertAppOffline(deploymentResult); - RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot); + RemoveAppOffline(deploymentResult.ContentRoot); await AssertRunning(deploymentResult); } } @@ -76,11 +77,11 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess { var deploymentResult = await DeployApp(hostingModel); - AddAppOffline(deploymentResult.DeploymentResult.ContentRoot); + AddAppOffline(deploymentResult.ContentRoot); await AssertAppOffline(deploymentResult); - RemoveAppOffline(deploymentResult.DeploymentResult.ContentRoot); + RemoveAppOffline(deploymentResult.ContentRoot); await AssertRunning(deploymentResult); } @@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests.Inprocess // dropping app_offline will kill the process } - var hostShutdownToken = deploymentResult.DeploymentResult.HostShutdownToken; + var hostShutdownToken = deploymentResult.HostShutdownToken; Assert.True(hostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout)); Assert.True(hostShutdownToken.IsCancellationRequested); diff --git a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs index 0281116218..5105b753c8 100644 --- a/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/AuthenticationTests.cs @@ -46,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(HttpStatusCode.Forbidden, response.StatusCode); var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true }; - var httpClient = deploymentResult.DeploymentResult.CreateHttpClient(httpClientHandler); + var httpClient = deploymentResult.CreateHttpClient(httpClientHandler); response = await httpClient.GetAsync("/AuthenticationAnonymous"); responseText = await response.Content.ReadAsStringAsync(); diff --git a/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs b/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs index 179c6bd198..b1ab071c5d 100644 --- a/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/ShutdownTests.cs @@ -24,7 +24,30 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var result = await DeployAsync(parameters); var response = await result.RetryingHttpClient.GetAsync("/Shutdown"); - Assert.True(result.DeploymentResult.HostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout)); + Assert.True(result.HostShutdownToken.WaitHandle.WaitOne(TimeoutExtensions.DefaultTimeout)); + } + + [ConditionalFact] + public async Task GracefulShutdown_DoesNotCrashProcess() + { + var parameters = Helpers.GetBaseDeploymentParameters(publish: true); + parameters.GracefulShutdown = true; + var result = await DeployAsync(parameters); + + var response = await result.RetryingHttpClient.GetAsync("/HelloWorld"); + StopServer(); + Assert.True(result.HostProcess.ExitCode == 0); + } + + [ConditionalFact] + public async Task ForcefulShutdown_DoesrashProcess() + { + var parameters = Helpers.GetBaseDeploymentParameters(publish: true); + var result = await DeployAsync(parameters); + + var response = await result.RetryingHttpClient.GetAsync("/HelloWorld"); + StopServer(); + Assert.True(result.HostProcess.ExitCode == 1); } } } diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index 84be58247c..8ad7a70665 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -152,8 +152,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests private string GetANCMRequestHandlerPath(IISDeploymentResult deploymentResult, string version) { - return Path.Combine(deploymentResult.DeploymentResult.ContentRoot, - deploymentResult.DeploymentResult.DeploymentParameters.RuntimeArchitecture.ToString(), + return Path.Combine(deploymentResult.ContentRoot, + deploymentResult.DeploymentParameters.RuntimeArchitecture.ToString(), version, _aspNetCoreDll); } From c3545c18eb6d16431f881461a0e704be9bd9620c Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Fri, 20 Jul 2018 17:32:57 -0700 Subject: [PATCH 06/10] Add api sets to IntegrationTesting.IIS (#1083) --- build/dependencies.props | 1 + .../Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/build/dependencies.props b/build/dependencies.props index f66a72c941..f529c45beb 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -34,6 +34,7 @@ 2.0.9 2.1.2 2.2.0-preview1-26618-02 + 1.0.1 2.2.0-preview1-34709 15.6.1 11.1.0 diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj index 0891a315dc..363de4e34f 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/Microsoft.AspNetCore.Server.IntegrationTesting.IIS.csproj @@ -15,6 +15,7 @@ + From f09c508f7d8f53fc913138adfee4ca3c67c9b2da Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Sun, 22 Jul 2018 12:15:38 -0700 Subject: [PATCH 07/10] Update dependencies.props [auto-updated: dependencies] --- build/dependencies.props | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index f529c45beb..665c81f665 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -1,41 +1,41 @@ - + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 0.10.13 2.2.0-preview1-17099 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 0.6.0-a-preview1-DeploymentParameters-17085 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 0.6.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 15.6.82 15.6.82 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 - 2.2.0-preview1-34709 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 + 2.2.0-preview1-34755 2.0.9 2.1.2 2.2.0-preview1-26618-02 1.0.1 - 2.2.0-preview1-34709 + 2.2.0-preview1-34755 15.6.1 11.1.0 2.0.3 From fba4e3ec4e312cdc2308995b9a55196740181fb4 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 23 Jul 2018 08:57:43 -0700 Subject: [PATCH 08/10] Switch to non-experimental filesystem (#1082) --- src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp | 2 +- .../CommonLib/PollingAppOfflineApplication.cpp | 2 +- src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h | 2 +- src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h | 2 +- src/AspNetCoreModuleV2/CommonLib/stdafx.h | 2 +- src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h | 2 +- test/CommonLibTests/stdafx.h | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp b/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp index 396a69ff31..b2c6b69871 100644 --- a/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/GlobalVersionUtility.cpp @@ -2,7 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. #include -#include +#include #include "GlobalVersionUtility.h" diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp index 3b07cf8645..dff673fee3 100644 --- a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.cpp @@ -3,7 +3,7 @@ #include "PollingAppOfflineApplication.h" -#include +#include #include "SRWExclusiveLock.h" #include "HandleWrapper.h" diff --git a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h index e66f5f46c8..592cdb2dc8 100644 --- a/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h +++ b/src/AspNetCoreModuleV2/CommonLib/PollingAppOfflineApplication.h @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. #pragma once -#include +#include #include "application.h" #include "requesthandler.h" diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h index dfdeb08b3a..1315865803 100644 --- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h +++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.h @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include "stringu.h" diff --git a/src/AspNetCoreModuleV2/CommonLib/stdafx.h b/src/AspNetCoreModuleV2/CommonLib/stdafx.h index d5407df316..b17ae43485 100644 --- a/src/AspNetCoreModuleV2/CommonLib/stdafx.h +++ b/src/AspNetCoreModuleV2/CommonLib/stdafx.h @@ -14,4 +14,4 @@ #include #include #include -#include +#include diff --git a/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h b/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h index fd6382710b..78a02ce72b 100644 --- a/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h +++ b/src/AspNetCoreModuleV2/RequestHandlerLib/stdafx.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "Shlwapi.h" #include diff --git a/test/CommonLibTests/stdafx.h b/test/CommonLibTests/stdafx.h index 33d3008f40..93dffac456 100644 --- a/test/CommonLibTests/stdafx.h +++ b/test/CommonLibTests/stdafx.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include From 538d76cc200e03ab23b9687e6254998f26c5dfca Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 24 Jul 2018 10:51:19 -0700 Subject: [PATCH 09/10] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 64ff041d5c..eac4268e4c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,4 @@ Contributing ====== -Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/dev/CONTRIBUTING.md) in the Home repo. +Information on contributing to this repo is in the [Contributing Guide](https://github.com/aspnet/Home/blob/master/CONTRIBUTING.md) in the Home repo. From 5bd475ef906ba68567be9f7f32439f5118e67bdc Mon Sep 17 00:00:00 2001 From: Justin Kotalik Date: Tue, 24 Jul 2018 13:17:05 -0700 Subject: [PATCH 10/10] Add event logs for some startup failure cases (#1081) --- .../AspNetCore/aspnetcore_shim_config.cpp | 2 ++ .../CommonLib/CommonLib.vcxproj | 1 + .../CommonLib/aspnetcore_msg.mc | 6 ++++ .../CommonLib/hostfxr_utility.cpp | 9 +++-- src/AspNetCoreModuleV2/CommonLib/resources.h | 4 ++- .../IISApplication.cs | 14 -------- .../IISDeployer.cs | 9 +++++ .../IISDeployerBase.cs | 10 ++++++ .../IISDeploymentParameterExtensions.cs | 31 ---------------- .../IISExpressDeployer.cs | 13 ++++--- .../WebConfigHelpers.cs | 35 +++++++++++++++++++ .../Inprocess/EventLogTests.cs | 4 ++- .../Inprocess/LoggingTests.cs | 12 ++++--- .../Inprocess/StartupExceptionTests.cs | 2 -- .../InProcess/StartupTests.cs | 28 ++++++++++++--- 15 files changed, 116 insertions(+), 64 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs diff --git a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp index a857706142..4cb6b222cf 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/aspnetcore_shim_config.cpp @@ -3,6 +3,7 @@ #include "aspnetcore_shim_config.h" +#include "EventLog.h" #include "config_utility.h" #include "hostfxr_utility.h" #include "ahutil.h" @@ -49,6 +50,7 @@ ASPNETCORE_SHIM_CONFIG::Populate( else { // block unknown hosting value + EVENTLOG(g_hEventLog, UNKNOWN_HOSTING_MODEL_ERROR, strHostingModel.QueryStr()); RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED)); } diff --git a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj index 2be58bcc5c..5ff3e0103f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj +++ b/src/AspNetCoreModuleV2/CommonLib/CommonLib.vcxproj @@ -195,6 +195,7 @@ + diff --git a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc index 96172c6e24..477c1a0d0a 100644 --- a/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc +++ b/src/AspNetCoreModuleV2/CommonLib/aspnetcore_msg.mc @@ -231,6 +231,12 @@ Language=English %1 . +Messageid=1034 +SymbolicName=ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR +Language=English +%1 +. + ; ;#endif // _ASPNETCORE_MODULE_MSG_H_ ; diff --git a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp index fd3a65abf8..ab827460bf 100644 --- a/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/hostfxr_utility.cpp @@ -141,7 +141,9 @@ HOSTFXR_UTILITY::GetHostFxrParameters( auto fullProcessPath = GetAbsolutePathToDotnet(applicationPhysicalPath, processPath); if (!fullProcessPath.has_value()) { - return E_FAIL; + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + EVENTLOG(hEventLog, INVALID_PROCESS_PATH, processPath.c_str(), hr); + return hr; } processPath = fullProcessPath.value(); @@ -149,7 +151,8 @@ HOSTFXR_UTILITY::GetHostFxrParameters( auto hostFxrPath = GetAbsolutePathToHostFxr(processPath, hEventLog); if (!hostFxrPath.has_value()) { - return E_FAIL; + hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); + return hr; } RETURN_IF_FAILED(HOSTFXR_UTILITY::ParseHostfxrArguments( @@ -368,6 +371,8 @@ HOSTFXR_UTILITY::GetAbsolutePathToDotnet( // Only do it if no path is specified if (requestedPath.has_parent_path()) { + WLOG_INFOF(L"Absolute path to dotnet.exe was not found at %s", requestedPath.c_str()); + return std::nullopt; } diff --git a/src/AspNetCoreModuleV2/CommonLib/resources.h b/src/AspNetCoreModuleV2/CommonLib/resources.h index 861619e5b2..ae26e9777f 100644 --- a/src/AspNetCoreModuleV2/CommonLib/resources.h +++ b/src/AspNetCoreModuleV2/CommonLib/resources.h @@ -29,6 +29,8 @@ #define ASPNETCORE_EVENT_APP_SHUTDOWN_SUCCESSFUL_MSG L"Application '%s' has shutdown." #define ASPNETCORE_EVENT_DUPLICATED_INPROCESS_APP_MSG L"Only one inprocess application is allowed per IIS application pool. Please assign the application '%s' to a different IIS application pool." #define ASPNETCORE_EVENT_MIXED_HOSTING_MODEL_ERROR_MSG L"Mixed hosting model is not supported. Application '%s' configured with different hostingModel value '%d' other than the one of running application(s)." +#define ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_MSG L"Unknown hosting model '%s'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file." +#define ASPNETCORE_EVENT_UNKNOWN_HOSTING_MODEL_ERROR_LEVEL EVENTLOG_ERROR_TYPE #define ASPNETCORE_EVENT_ADD_APPLICATION_ERROR_MSG L"Failed to start application '%s', ErrorCode '0x%x'." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_STDOUT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Last 4KB characters of captured stdout and stderr logs:\r\n%s" #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXIT_MSG L"Application '%s' with physical root '%s' hit unexpected managed background thread exit, ErrorCode = '0x%x. Please check the stderr logs for more information." @@ -49,7 +51,7 @@ #define ASPNETCORE_EVENT_APPLICATION_EXE_NOT_FOUND_MSG L"Could not find application executable in '%s'. ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_INPROCESS_THREAD_EXCEPTION_MSG L"Application '%s' with physical root '%s' hit unexpected managed exception, ErrorCode = '0x%x. Please check the stderr logs for more information." #define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_LEVEL EVENTLOG_ERROR_TYPE -#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = %s, ErrorCode = '0x%x'." +#define ASPNETCORE_EVENT_INVALID_PROCESS_PATH_MSG L"Invalid or unknown processPath provided in web.config: processPath = '%s', ErrorCode = '0x%x'." #define ASPNETCORE_EVENT_INPROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for in-process application. Please confirm the Microsoft.AspNetCore.Server.IIS package is referenced in your application." #define ASPNETCORE_EVENT_OUT_OF_PROCESS_RH_MISSING_MSG L"Could not find the assembly '%s' for out-of-process application. Please confirm the assembly is installed correctly for IIS or IISExpress." #define ASPNETCORE_EVENT_INPROCESS_START_SUCCESS_MSG L"Application '%s' started the coreclr in-process successfully." diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs index c1a26d3181..b83e7aa4df 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs @@ -71,26 +71,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting ConfigureAppHostConfig(contentRoot); - if (_deploymentParameters.ApplicationType == ApplicationType.Portable) - { - ModifyAspNetCoreSectionInWebConfig("processPath", DotNetCommands.GetDotNetExecutable(_deploymentParameters.RuntimeArchitecture)); - } - _serverManager.CommitChanges(); await WaitUntilSiteStarted(apppool); } } - private void ModifyAspNetCoreSectionInWebConfig(string key, string value) - { - var webConfigFile = Path.Combine(_deploymentParameters.PublishedApplicationRootPath, "web.config"); - var config = XDocument.Load(webConfigFile); - var element = config.Descendants("aspNetCore").FirstOrDefault(); - element.SetAttributeValue(key, value); - config.Save(webConfigFile); - } - private async Task WaitUntilSiteStarted(ApplicationPool appPool) { var sw = Stopwatch.StartNew(); diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index c093ae3065..3f7425fce6 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -61,6 +61,15 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS // For now, only support using published output DeploymentParameters.PublishApplicationBeforeDeployment = true; + + if (DeploymentParameters.ApplicationType == ApplicationType.Portable) + { + DefaultWebConfigActions.Add( + WebConfigHelpers.AddOrModifyAspNetCoreSection( + "processPath", + DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture))); + } + if (DeploymentParameters.PublishApplicationBeforeDeployment) { DotnetPublish(); diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs index 04e8448327..5042a192e3 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployerBase.cs @@ -2,6 +2,7 @@ // 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.Diagnostics; using System.IO; using System.Linq; @@ -15,6 +16,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { public IISDeploymentParameters IISDeploymentParameters { get; } + protected List> DefaultWebConfigActions { get; } = new List>(); + public IISDeployerBase(IISDeploymentParameters deploymentParameters, ILoggerFactory loggerFactory) : base(deploymentParameters, loggerFactory) { @@ -36,6 +39,12 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS var path = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, "web.config"); var webconfig = XDocument.Load(path); var xElement = webconfig.Descendants("system.webServer").Single(); + + foreach (var action in DefaultWebConfigActions) + { + action.Invoke(xElement); + } + foreach (var action in IISDeploymentParameters.WebConfigActionList) { action.Invoke(xElement); @@ -44,6 +53,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS webconfig.Save(path); } + public string RunServerConfigActions(string serverConfigString) { if (IISDeploymentParameters == null) diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs index fb154aeefb..ff2365a82a 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; -using System.IO; using System.Linq; using System.Xml.Linq; @@ -22,23 +20,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS parameters.ServerConfigActionList.Add(action); } - public static void ModifyWebConfig(this IISDeploymentParameters parameters, Action transform) - { - parameters.WebConfigActionList.Add(transform); - } - - public static void ModifyAspNetCoreSectionInWebConfig(this IISDeploymentParameters parameters, string key, string value) - => ModifyAttributeInWebConfig(parameters, key, value, section: "aspNetCore"); - - - public static void ModifyAttributeInWebConfig(this IISDeploymentParameters parameters, string key, string value, string section) - { - parameters.WebConfigActionList.Add((element) => - { - element.Descendants(section).SingleOrDefault().SetAttributeValue(key, value); - }); - } - public static void AddHttpsToServerConfig(this IISDeploymentParameters parameters) { parameters.ServerConfigActionList.Add( @@ -64,17 +45,5 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS .SetAttributeValue("enabled", "true"); }); } - - public static void ModifyHandlerSectionInWebConfig(this IISDeploymentParameters parameters, string key, string value) - { - parameters.WebConfigActionList.Add(element => - { - element.Descendants("handlers") - .FirstOrDefault() - .Descendants("add") - .FirstOrDefault() - .SetAttributeValue(key, value); - }); - } } } diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs index 729c5f870f..0fea5fa391 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISExpressDeployer.cs @@ -280,9 +280,13 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS if (DeploymentParameters.PublishApplicationBeforeDeployment) { // For published apps, prefer the content in the web.config, but update it. - IISDeploymentParameters.ModifyAspNetCoreSectionInWebConfig(key: "hostingModel", - value: DeploymentParameters.HostingModel == HostingModel.InProcess ? "inprocess" : ""); - IISDeploymentParameters.ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString()); + DefaultWebConfigActions.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection( + key: "hostingModel", + value: DeploymentParameters.HostingModel == HostingModel.InProcess ? "inprocess" : "")); + + DefaultWebConfigActions.Add(WebConfigHelpers.AddOrModifyHandlerSection( + key: "modules", + value: DeploymentParameters.AncmVersion.ToString())); ModifyDotNetExePathInWebConfig(); serverConfig = RemoveRedundantElements(serverConfig); RunWebConfigActions(); @@ -464,7 +468,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS { throw new Exception($"Unable to find '{executableName}'.'"); } - IISDeploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", executableName); + DefaultWebConfigActions.Add( + WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", executableName)); } } diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs new file mode 100644 index 0000000000..8d2af5eb1d --- /dev/null +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/WebConfigHelpers.cs @@ -0,0 +1,35 @@ +// 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.Linq; +using System.Xml.Linq; + +namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS +{ + public static class WebConfigHelpers + { + public static Action AddOrModifyAspNetCoreSection(string key, string value) + => AddAction(key, value, section: "aspNetCore"); + + public static Action AddAction(string key, string value, string section) + { + return (element) => + { + element.Descendants(section).SingleOrDefault().SetAttributeValue(key, value); + }; + } + + public static Action AddOrModifyHandlerSection(string key, string value) + { + return element => + { + element.Descendants("handlers") + .FirstOrDefault() + .Descendants("add") + .FirstOrDefault() + .SetAttributeValue(key, value); + }; + } + } +} diff --git a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs index 67483b0663..a2476cea1b 100644 --- a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs +++ b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs @@ -1,4 +1,6 @@ -using System; +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; diff --git a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs index e8e303b429..eb3294a537 100644 --- a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs +++ b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs @@ -23,10 +23,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogEnabled", "true"); + deploymentParameters.WebConfigActionList.Add( + WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogEnabled", "true")); var pathToLogs = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogFile", Path.Combine(pathToLogs, "std")); + deploymentParameters.WebConfigActionList.Add( + WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogFile", Path.Combine(pathToLogs, "std"))); var deploymentResult = await DeployAsync(deploymentParameters); @@ -63,8 +65,10 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogEnabled", "true"); - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("stdoutLogFile", Path.Combine("Q:", "std")); + deploymentParameters.WebConfigActionList.Add( + WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogEnabled", "true")); + deploymentParameters.WebConfigActionList.Add( + WebConfigHelpers.AddOrModifyAspNetCoreSection("stdoutLogFile", Path.Combine("Q:", "std"))); var deploymentResult = await DeployAsync(deploymentParameters); diff --git a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs index 40d5247e01..93683b8a78 100644 --- a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs +++ b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs @@ -2,11 +2,9 @@ // 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.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; -using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing.xunit; using Xunit; diff --git a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs index 9c97e78b2f..36812d3f2e 100644 --- a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs +++ b/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs @@ -31,7 +31,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests deploymentParameters => { deploymentParameters.EnvironmentVariables["DotnetPath"] = _dotnetLocation; - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", "%DotnetPath%"); + deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", "%DotnetPath%")); } ); } @@ -43,13 +43,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task InvalidProcessPath_ExpectServerError(string path) { var deploymentParameters = GetBaseDeploymentParameters(); - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", path); + deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", path)); + var deploymentResult = await DeployAsync(deploymentParameters); var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld"); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + + EventLogHelpers.VerifyEventLogEvent(TestSink, @"Invalid or unknown processPath provided in web\.config: processPath = '.+', ErrorCode = '0x80070002'\."); } [ConditionalFact] @@ -60,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests await AssertStarts( deploymentParameters => { - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", dotnetLocationWithoutExtension); + deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension)); } ); } @@ -72,7 +75,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests await AssertStarts( deploymentParameters => { - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", dotnetLocationWithoutExtension); + deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", dotnetLocationWithoutExtension)); } ); } @@ -86,7 +89,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests deploymentParameters => { deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(_dotnetLocation); - deploymentParameters.ModifyAspNetCoreSectionInWebConfig("processPath", path); + deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("processPath", path)); } ); @@ -144,6 +147,21 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Contains(TestSink.Writes, context => context.Message.Contains("Application is running inside IIS process but is not configured to use IIS server")); } + [ConditionalFact] + public async Task CheckInvalidHostingModelParameter() + { + var deploymentParameters = GetBaseDeploymentParameters(); + deploymentParameters.WebConfigActionList.Add(WebConfigHelpers.AddOrModifyAspNetCoreSection("hostingModel", "bogus")); + + var deploymentResult = await DeployAsync(deploymentParameters); + + var response = await deploymentResult.RetryingHttpClient.GetAsync("HelloWorld"); + + Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); + + EventLogHelpers.VerifyEventLogEvent(TestSink, "Unknown hosting model 'bogus'. Please specify either hostingModel=\"inprocess\" or hostingModel=\"outofprocess\" in the web.config file."); + } + // Defaults to inprocess specific deployment parameters public static IISDeploymentParameters GetBaseDeploymentParameters(string site = "InProcessWebSite") {