diff --git a/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp b/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp index 09becc9010..28bc775dfa 100644 --- a/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp +++ b/src/AspNetCoreModuleV2/CommonLib/debugutil.cpp @@ -91,7 +91,7 @@ DebugInitializeFromConfig(IHttpServer& pHttpServer, IHttpApplication& pHttpAppli STRU debugValue; RETURN_IF_FAILED(ConfigUtility::FindDebugLevel(pAspNetCoreElement, debugValue)); - SetDebugFlags(debugFile.QueryStr()); + SetDebugFlags(debugValue.QueryStr()); CreateDebugLogFile(debugFile.QueryStr()); diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs index 3fafd7c8f9..afa28dd4e3 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISApplication.cs @@ -197,7 +197,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting () => File.Delete(_apphostConfigPath), e => _logger.LogWarning($"Failed to delete file : {e.Message}")); } - if (File.Exists(_apphostConfigBackupPath)) { RetryFileOperation( diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index 6df58dd736..f1f4922e88 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -34,7 +34,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS } GetLogsFromFile($"{_application.WebSiteName}.txt"); - GetLogsFromFile("web.config"); CleanPublishedOutput(); InvokeUserApplicationCleanup(); @@ -88,9 +87,11 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS var arr = new string[0]; RetryHelper.RetryOperation(() => arr = File.ReadAllLines(Path.Combine(DeploymentParameters.PublishedApplicationRootPath, file)), - (ex) => Logger.LogError("Could not read log file"), + (ex) => Logger.LogWarning("Could not read log file"), 5, 200); + + Logger.LogInformation($"Found debug log file: {file}"); foreach (var line in arr) { Logger.LogInformation(line); diff --git a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs index 1ae8aa5d57..176661189c 100644 --- a/test/Common.FunctionalTests/Inprocess/EventLogTests.cs +++ b/test/Common.FunctionalTests/Inprocess/EventLogTests.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { var deploymentParameters = Helpers.GetBaseDeploymentParameters(publish: true); var deploymentResult = await DeployAsync(deploymentParameters); - await Helpers.AssertStarts(deploymentResult, "/HelloWorld"); + await Helpers.AssertStarts(deploymentResult); StopServer(); diff --git a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs index 6b4b2278a4..53009a969c 100644 --- a/test/Common.FunctionalTests/Inprocess/LoggingTests.cs +++ b/test/Common.FunctionalTests/Inprocess/LoggingTests.cs @@ -69,6 +69,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task StartupMessagesAreLoggedIntoDebugLogFile() { var tempFile = Path.GetTempFileName(); @@ -78,6 +79,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_DEBUG_FILE"] = tempFile; var deploymentResult = await DeployAsync(deploymentParameters); + + Helpers.AddDebugLogToWebConfig(deploymentResult.DeploymentResult.ContentRoot, tempFile); + var response = await deploymentResult.RetryingHttpClient.GetAsync("/"); StopServer(); @@ -93,7 +97,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] - [SkipIIS] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task StartupMessagesLogFileSwitchedWhenLogFilePresentInWebConfig() { var firstTempFile = Path.GetTempFileName(); diff --git a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs index d39ed68c24..667c47327c 100644 --- a/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.cs +++ b/test/Common.FunctionalTests/Inprocess/StartupExceptionTests.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.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; @@ -22,11 +23,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests // However, for IIS, we need a web.config file because the default on generated on publish // doesn't include V2. We can remove the publish flag once IIS supports non-publish running var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite", publish: true); - deploymentParameters.EnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path; + var randomNumberString = new Random(Guid.NewGuid().GetHashCode()).Next(10000000).ToString(); - deploymentParameters.EnvironmentVariables["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString; + + var environmentVariablesInWebConfig = new Dictionary + { + ["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path, + ["ASPNETCORE_INPROCESS_RANDOM_VALUE"] = randomNumberString + }; var deploymentResult = await DeployAsync(deploymentParameters); + Helpers.AddEnvironmentVariablesToWebConfig(deploymentResult.DeploymentResult.ContentRoot, environmentVariablesInWebConfig); var response = await deploymentResult.RetryingHttpClient.GetAsync(path); @@ -45,10 +52,16 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task CheckStdoutWithLargeWrites(string path) { var deploymentParameters = Helpers.GetBaseDeploymentParameters("StartupExceptionWebsite", publish: true); - deploymentParameters.EnvironmentVariables["ASPNETCORE_INPROCESS_STARTUP_VALUE"] = path; + + var environmentVariablesInWebConfig = new Dictionary + { + ["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/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs index e512dd6d83..0480351ce1 100644 --- a/test/Common.FunctionalTests/Utilities/Helpers.cs +++ b/test/Common.FunctionalTests/Utilities/Helpers.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Collections; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -54,6 +56,62 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests 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) { diff --git a/test/Common.FunctionalTests/Utilities/IISCapability.cs b/test/Common.FunctionalTests/Utilities/IISCapability.cs new file mode 100644 index 0000000000..e3a5bf6c4e --- /dev/null +++ b/test/Common.FunctionalTests/Utilities/IISCapability.cs @@ -0,0 +1,16 @@ +// 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; + +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests +{ + [Flags] + public enum IISCapability + { + None = 0, + Websockets = 1, + WindowsAuthentication = 2, + PoolEnvironmentVariables = 4 + } +} diff --git a/test/Common.FunctionalTests/Utilities/SkipIISAttribute.cs b/test/Common.FunctionalTests/Utilities/SkipIISAttribute.cs index da90b513f8..e69de29bb2 100644 --- a/test/Common.FunctionalTests/Utilities/SkipIISAttribute.cs +++ b/test/Common.FunctionalTests/Utilities/SkipIISAttribute.cs @@ -1,17 +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 Microsoft.AspNetCore.Server.IntegrationTesting; -using Microsoft.AspNetCore.Testing.xunit; - -namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests -{ - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] - public sealed class SkipIISAttribute : Attribute, ITestCondition - { - public bool IsMet => DeployerSelector.ServerType == ServerType.IIS; - - public string SkipReason => "Cannot run test on full IIS."; - } -} diff --git a/test/IIS.FunctionalTests/RequiresAttribute.cs b/test/IIS.FunctionalTests/RequiresAttribute.cs deleted file mode 100644 index 6602d1125c..0000000000 --- a/test/IIS.FunctionalTests/RequiresAttribute.cs +++ /dev/null @@ -1,73 +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.Runtime.InteropServices; -using System.Security.Principal; -using System.Xml.Linq; -using Microsoft.AspNetCore.Testing.xunit; - -namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests -{ - [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] - public sealed class RequiresIISAttribute : Attribute, ITestCondition - { - private static readonly bool _isMet; - public static readonly string _skipReason; - - public bool IsMet => _isMet; - public string SkipReason => _skipReason; - - static RequiresIISAttribute() - { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - _skipReason = "IIS tests can only be run on Windows"; - return; - } - - var identity = WindowsIdentity.GetCurrent(); - var principal = new WindowsPrincipal(identity); - if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) - { - _skipReason += "The current console is not running as admin."; - return; - } - - if (!File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "w3wp.exe"))) - { - _skipReason += "The machine does not have IIS installed."; - return; - } - - var ancmConfigPath = Path.Combine(Environment.SystemDirectory, "inetsrv", "config", "schema", "aspnetcore_schema_v2.xml"); - - if (!File.Exists(ancmConfigPath)) - { - _skipReason = "IIS Schema is not installed."; - return; - } - - XDocument ancmConfig; - - try - { - ancmConfig = XDocument.Load(ancmConfigPath); - } - catch - { - _skipReason = "Could not read ANCM schema configuration"; - return; - } - - _isMet = ancmConfig - .Root - .Descendants("attribute") - .Any(n => "hostingModel".Equals(n.Attribute("name")?.Value, StringComparison.Ordinal)); - - _skipReason = _isMet ? null : "IIS schema needs to be upgraded to support ANCM."; - } - } -} diff --git a/test/IIS.FunctionalTests/RequiresIISAttribute.cs b/test/IIS.FunctionalTests/RequiresIISAttribute.cs new file mode 100644 index 0000000000..f55f397cfa --- /dev/null +++ b/test/IIS.FunctionalTests/RequiresIISAttribute.cs @@ -0,0 +1,131 @@ +// 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.Runtime.InteropServices; +using System.Security.Principal; +using System.Xml.Linq; +using Microsoft.AspNetCore.Testing.xunit; +using Microsoft.Win32; + +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests +{ + [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class | AttributeTargets.Method)] + public sealed class RequiresIISAttribute : Attribute, ITestCondition + { + private static readonly bool _isMetStatic; + private static readonly string _skipReasonStatic; + + private readonly bool _isMet; + private readonly string _skipReason; + + private static readonly bool _websocketsAvailable; + private static readonly bool _windowsAuthAvailable; + private static readonly bool _poolEnvironmentVariablesAvailable; + + static RequiresIISAttribute() + { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + _skipReasonStatic = "IIS tests can only be run on Windows"; + return; + } + + var identity = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(identity); + if (!principal.IsInRole(WindowsBuiltInRole.Administrator)) + { + _skipReasonStatic += "The current console is not running as admin."; + return; + } + + if (!File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "w3wp.exe"))) + { + _skipReasonStatic += "The machine does not have IIS installed."; + return; + } + + var ancmConfigPath = Path.Combine(Environment.SystemDirectory, "inetsrv", "config", "schema", "aspnetcore_schema_v2.xml"); + + if (!File.Exists(ancmConfigPath)) + { + _skipReasonStatic = "IIS Schema is not installed."; + return; + } + + XDocument ancmConfig; + + try + { + ancmConfig = XDocument.Load(ancmConfigPath); + } + catch + { + _skipReasonStatic = "Could not read ANCM schema configuration"; + return; + } + + _isMetStatic = ancmConfig + .Root + .Descendants("attribute") + .Any(n => "hostingModel".Equals(n.Attribute("name")?.Value, StringComparison.Ordinal)); + + _skipReasonStatic = _isMetStatic ? null : "IIS schema needs to be upgraded to support ANCM."; + + _websocketsAvailable = File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "iiswsock.dll")); + + _windowsAuthAvailable = File.Exists(Path.Combine(Environment.SystemDirectory, "inetsrv", "authsspi.dll")); + + var iisRegistryKey = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\InetStp", writable: false); + if (iisRegistryKey == null) + { + _poolEnvironmentVariablesAvailable = false; + } + else + { + var majorVersion = (int)iisRegistryKey.GetValue("MajorVersion", -1); + var minorVersion = (int)iisRegistryKey.GetValue("MinorVersion", -1); + var version = new Version(majorVersion, minorVersion); + _poolEnvironmentVariablesAvailable = version >= new Version(10, 0); + } + } + + public RequiresIISAttribute() { } + + public RequiresIISAttribute(IISCapability capabilities) + { + _isMet = _isMetStatic; + _skipReason = _skipReasonStatic; + if (capabilities.HasFlag(IISCapability.Websockets)) + { + _isMet &= _websocketsAvailable; + if (!_websocketsAvailable) + { + _skipReason += "The machine does not have IIS websockets installed."; + } + } + if (capabilities.HasFlag(IISCapability.WindowsAuthentication)) + { + _isMet &= _windowsAuthAvailable; + + if (!_windowsAuthAvailable) + { + _skipReason += "The machine does not have IIS windows authentication installed."; + } + } + if (capabilities.HasFlag(IISCapability.PoolEnvironmentVariables)) + { + _isMet &= _poolEnvironmentVariablesAvailable; + if (!_poolEnvironmentVariablesAvailable) + { + _skipReason += "The machine does allow for setting environment variables on application pools."; + } + } + } + + public bool IsMet => _isMet; + public string SkipReason => _skipReason; + } +} diff --git a/test/IISExpress.FunctionalTests/RequiresIISAttribute.cs b/test/IISExpress.FunctionalTests/RequiresIISAttribute.cs index 15bbb9c26c..24d656332d 100644 --- a/test/IISExpress.FunctionalTests/RequiresIISAttribute.cs +++ b/test/IISExpress.FunctionalTests/RequiresIISAttribute.cs @@ -13,5 +13,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public bool IsMet => IISExpressAncmSchema.SupportsInProcessHosting; public string SkipReason => IISExpressAncmSchema.SkipReason; + + public RequiresIISAttribute() { } + + public RequiresIISAttribute(IISCapability capabilities) + { + // IISCapabilities aren't pretinent to IISExpress + } } }