From 0b5973e5014f17e7bbdbe57c28b90d2b9b1d2347 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Sat, 13 Oct 2018 10:54:20 -0700 Subject: [PATCH 1/7] Enable auth tests on IIS (#1511) * Enable auth tests on IIS * FB --- .../IISDeploymentParameterExtensions.cs | 46 ++++++++++++++++--- .../BasicAuthTests.cs | 5 +- .../RequiresEnvironmentVariableAttribute.cs | 24 ++++++++++ .../WindowsAuthTests.cs | 0 test/IIS.FunctionalTests/ServicesTests.cs | 6 +-- tools/SetupTestEnvironment.ps1 | 4 +- 6 files changed, 69 insertions(+), 16 deletions(-) rename test/{IISExpress.FunctionalTests => Common.FunctionalTests}/BasicAuthTests.cs (92%) create mode 100644 test/Common.FunctionalTests/Utilities/RequiresEnvironmentVariableAttribute.cs rename test/{IISExpress.FunctionalTests => Common.FunctionalTests}/WindowsAuthTests.cs (100%) diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs index 8534add254..90f76fd8c2 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeploymentParameterExtensions.cs @@ -43,14 +43,22 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS public static void SetWindowsAuth(this IISDeploymentParameters parameters, bool enabled = true) { + parameters.EnsureSection("windowsAuthentication", "system.webServer", "security", "windowsAuthentication"); parameters.EnableModule("WindowsAuthenticationModule", "%IIS_BIN%\\authsspi.dll"); parameters.AddServerConfigAction( element => { - element.Descendants("windowsAuthentication") - .Single() - .SetAttributeValue("enabled", enabled); + var windowsAuthentication = element + .RequiredElement("system.webServer") + .RequiredElement("security") + .RequiredElement("authentication") + .GetOrAdd("windowsAuthentication"); + + windowsAuthentication.SetAttributeValue("enabled", enabled); + var providers = windowsAuthentication.GetOrAdd("providers"); + providers.GetOrAdd("add", "value", "Negotiate"); + providers.GetOrAdd("add", "value", "NTLM"); }); } @@ -59,8 +67,11 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS parameters.AddServerConfigAction( element => { - element.Descendants("anonymousAuthentication") - .Single() + element + .RequiredElement("system.webServer") + .RequiredElement("security") + .RequiredElement("authentication") + .GetOrAdd("anonymousAuthentication") .SetAttributeValue("enabled", enabled); }); } @@ -72,12 +83,33 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS parameters.AddServerConfigAction( element => { - element.Descendants("basicAuthentication") - .Single() + element + .RequiredElement("system.webServer") + .RequiredElement("security") + .RequiredElement("authentication") + .GetOrAdd("basicAuthentication") .SetAttributeValue("enabled", enabled); }); } + public static void EnsureSection(this IISDeploymentParameters parameters, string name, params string[] path) + { + parameters.ServerConfigActionList.Add( + (config, _) => { + + var element = config + .RequiredElement("configSections"); + + foreach (var s in path) + { + element = element.GetOrAdd("sectionGroup", "name", s); + } + + element.GetOrAdd("section", "name", "applicationInitialization") + .SetAttributeValue("overrideModeDefault", "Allow"); + }); + } + public static void EnableLogging(this IISDeploymentParameters deploymentParameters, string path) { deploymentParameters.WebConfigActionList.Add( diff --git a/test/IISExpress.FunctionalTests/BasicAuthTests.cs b/test/Common.FunctionalTests/BasicAuthTests.cs similarity index 92% rename from test/IISExpress.FunctionalTests/BasicAuthTests.cs rename to test/Common.FunctionalTests/BasicAuthTests.cs index 1011b678ed..1c7faf00b4 100644 --- a/test/IISExpress.FunctionalTests/BasicAuthTests.cs +++ b/test/Common.FunctionalTests/BasicAuthTests.cs @@ -32,7 +32,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests .WithAllAncmVersions() .WithAllHostingModels(); - [ConditionalTheory(Skip = "This test is manual. To run it set ASPNETCORE_MODULE_TEST_USER and ASPNETCORE_MODULE_TEST_PASSWORD environment variables to existing user")] + [ConditionalTheory] + [RequiresEnvironmentVariable("ASPNETCORE_MODULE_TEST_USER")] [RequiresIIS(IISCapability.BasicAuthentication)] [MemberData(nameof(TestVariants))] public async Task BasicAuthTest(TestVariant variant) @@ -63,7 +64,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests else { // We expect out-of-proc not allowing basic auth - Assert.Equal("Windows:", responseText); + Assert.Equal("Windows", responseText); } } } diff --git a/test/Common.FunctionalTests/Utilities/RequiresEnvironmentVariableAttribute.cs b/test/Common.FunctionalTests/Utilities/RequiresEnvironmentVariableAttribute.cs new file mode 100644 index 0000000000..d2749db547 --- /dev/null +++ b/test/Common.FunctionalTests/Utilities/RequiresEnvironmentVariableAttribute.cs @@ -0,0 +1,24 @@ +// 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 RequiresEnvironmentVariableAttribute : Attribute, ITestCondition + { + private readonly string _name; + + public RequiresEnvironmentVariableAttribute(string name) + { + _name = name; + } + + public bool IsMet => !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable(_name)); + + public string SkipReason => $"Environment variable {_name} is required to run this test."; + } +} diff --git a/test/IISExpress.FunctionalTests/WindowsAuthTests.cs b/test/Common.FunctionalTests/WindowsAuthTests.cs similarity index 100% rename from test/IISExpress.FunctionalTests/WindowsAuthTests.cs rename to test/Common.FunctionalTests/WindowsAuthTests.cs diff --git a/test/IIS.FunctionalTests/ServicesTests.cs b/test/IIS.FunctionalTests/ServicesTests.cs index 47e53b8d40..875b5b13be 100644 --- a/test/IIS.FunctionalTests/ServicesTests.cs +++ b/test/IIS.FunctionalTests/ServicesTests.cs @@ -78,13 +78,9 @@ namespace IIS.FunctionalTests private static void EnablePreload(IISDeploymentParameters baseDeploymentParameters) { + baseDeploymentParameters.EnsureSection("applicationInitialization", "system.webServer"); baseDeploymentParameters.ServerConfigActionList.Add( (config, _) => { - config - .RequiredElement("configSections") - .GetOrAdd("sectionGroup", "name", "system.webServer") - .GetOrAdd("section", "name", "applicationInitialization") - .SetAttributeValue("overrideModeDefault", "Allow"); config .RequiredElement("system.applicationHost") diff --git a/tools/SetupTestEnvironment.ps1 b/tools/SetupTestEnvironment.ps1 index 625b040e39..3adaf79045 100644 --- a/tools/SetupTestEnvironment.ps1 +++ b/tools/SetupTestEnvironment.ps1 @@ -57,8 +57,8 @@ function Setup-appverif($application) function Shutdown-appverif($application) { - setx APPVERIFIER_ENABLED_CODES "`"`""; - setx APPVERIFIER_LEVEL "`"`""; + setx APPVERIFIER_ENABLED_CODES "NONE"; + setx APPVERIFIER_LEVEL "NONE"; appverif.exe -disable * -for $application } From df51be447e52d8840ae62715d722db0ec9a81256 Mon Sep 17 00:00:00 2001 From: dotnet-maestro-bot Date: Mon, 15 Oct 2018 09:17:19 -0700 Subject: [PATCH 2/7] Update dependencies.props (#1517) [auto-updated: dependencies] --- build/dependencies.props | 54 ++++++++++++++++++++-------------------- korebuild-lock.txt | 4 +-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/build/dependencies.props b/build/dependencies.props index 3ca3dc430a..b4708cadc2 100644 --- a/build/dependencies.props +++ b/build/dependencies.props @@ -4,38 +4,38 @@ 0.10.13 - 2.2.0-preview2-20181011.2 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 0.6.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 + 2.2.0-preview2-20181011.10 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 0.6.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 15.6.82 15.6.82 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 - 2.2.0-preview3-35457 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 + 2.2.0-preview3-35496 2.1.3 2.2.0-preview3-27008-03 1.0.1 - 2.2.0-preview3-35457 + 2.2.0-preview3-35496 15.6.1 11.1.0 2.0.3 diff --git a/korebuild-lock.txt b/korebuild-lock.txt index bda301982e..49afc832d9 100644 --- a/korebuild-lock.txt +++ b/korebuild-lock.txt @@ -1,2 +1,2 @@ -version:2.2.0-preview2-20181011.2 -commithash:09cd1592eb0fbbfa6ef5124120c173bc1d4e353a +version:2.2.0-preview2-20181011.10 +commithash:224e1163a1145b60f324e0b432419ef4ba4880cc From b0deed05be7710d80e28a1ce95ff4e760939644b Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 15 Oct 2018 10:33:14 -0700 Subject: [PATCH 3/7] Add server abort tests (#1510) --- build/launchSettings.json | 11 ++-- build/testsite.props | 2 - .../Properties/launchSettings.json | 7 +- .../AspNetCore/HandlerResolver.cpp | 14 +++- test/Common.FunctionalTests/BasicAuthTests.cs | 1 - .../Inprocess/FixtureLoggedTest.cs | 2 +- .../ServerAbortTests.cs | 65 +++++++++++++++++++ .../Utilities/IISTestSiteCollection.cs | 13 ++++ .../Utilities/IISTestSiteFixture.cs | 28 +++++++- .../OutOfProcess/GlobalVersionTests.cs | 30 +++++++++ .../Properties/launchSettings.json | 11 ++-- .../Properties/launchSettings.json | 11 ++-- .../Properties/launchSettings.json | 11 ++-- .../shared/SharedStartup/Startup.shared.cs | 8 ++- 14 files changed, 182 insertions(+), 32 deletions(-) create mode 100644 test/Common.FunctionalTests/ServerAbortTests.cs diff --git a/build/launchSettings.json b/build/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/build/launchSettings.json +++ b/build/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/build/testsite.props b/build/testsite.props index 861d44a563..1ef6bf81cc 100644 --- a/build/testsite.props +++ b/build/testsite.props @@ -36,8 +36,6 @@ /config:"$(IISExpressAppHostConfig)" /systray:false -h "$(IISAppHostConfig)" - $(AspNetCoreModuleV1ShimDll) - $(AspNetCoreModuleV2ShimDll) aspnetcorev2_inprocess.dll $(userprofile)\.dotnet\$(NativePlatform)\dotnet.exe diff --git a/samples/NativeIISSample/Properties/launchSettings.json b/samples/NativeIISSample/Properties/launchSettings.json index 9c963c0100..f62697de39 100644 --- a/samples/NativeIISSample/Properties/launchSettings.json +++ b/samples/NativeIISSample/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AncmPath)", + "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -31,6 +31,7 @@ "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", "ANCM_PATH": "$(AncmPath)", "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp index 726229cc9e..44210d8b68 100644 --- a/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp +++ b/src/AspNetCoreModuleV2/AspNetCore/HandlerResolver.cpp @@ -16,6 +16,7 @@ #include "WebConfigConfigurationSource.h" #include "ModuleHelpers.h" #include "BaseOutputManager.h" +#include "Environment.h" const PCWSTR HandlerResolver::s_pwzAspnetcoreInProcessRequestHandlerName = L"aspnetcorev2_inprocess.dll"; const PCWSTR HandlerResolver::s_pwzAspnetcoreOutOfProcessRequestHandlerName = L"aspnetcorev2_outofprocess.dll"; @@ -103,12 +104,12 @@ HandlerResolver::LoadRequestHandlerAssembly(const IHttpApplication &pApplication LOG_INFOF(L"Loading request handler: '%ls'", handlerDllPath.c_str()); hRequestHandlerDll = LoadLibrary(handlerDllPath.c_str()); + RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll); if (preventUnload) { // Pin module in memory - GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, pstrHandlerDllName, &hRequestHandlerDll); + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_PIN, handlerDllPath.c_str(), &hRequestHandlerDll); } - RETURN_LAST_ERROR_IF_NULL(hRequestHandlerDll); } auto pfnAspNetCoreCreateApplication = ModuleHelpers::GetKnownProcAddress(hRequestHandlerDll, "CreateApplication"); @@ -150,7 +151,7 @@ HandlerResolver::GetApplicationFactory(const IHttpApplication &pApplication, std m_loadedApplicationHostingModel = options.QueryHostingModel(); m_loadedApplicationId = pApplication.GetApplicationId(); RETURN_IF_FAILED(LoadRequestHandlerAssembly(pApplication, options, pApplicationFactory)); - + return S_OK; } @@ -171,6 +172,13 @@ HandlerResolver::FindNativeAssemblyFromGlobalLocation( { try { + auto handlerPath = Environment::GetEnvironmentVariableValue(L"ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER"); + if (handlerPath.has_value() && std::filesystem::is_regular_file(handlerPath.value())) + { + handlerDllPath = handlerPath.value(); + return S_OK; + } + std::wstring modulePath = GlobalVersionUtility::GetModuleName(m_hModule); modulePath = GlobalVersionUtility::RemoveFileNameFromFolderPath(modulePath); diff --git a/test/Common.FunctionalTests/BasicAuthTests.cs b/test/Common.FunctionalTests/BasicAuthTests.cs index 1c7faf00b4..d8607db21e 100644 --- a/test/Common.FunctionalTests/BasicAuthTests.cs +++ b/test/Common.FunctionalTests/BasicAuthTests.cs @@ -6,7 +6,6 @@ using System.Net.Http; using System.Net.Http.Headers; using System.Text; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Server.IIS.FunctionalTests.Utilities; using Microsoft.AspNetCore.Server.IntegrationTesting; using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; diff --git a/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs b/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs index 4604687991..705af2b213 100644 --- a/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs +++ b/test/Common.FunctionalTests/Inprocess/FixtureLoggedTest.cs @@ -15,7 +15,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { _fixture = fixture; } - + public override void Initialize(MethodInfo methodInfo, object[] testMethodArguments, ITestOutputHelper testOutputHelper) { base.Initialize(methodInfo, testMethodArguments, testOutputHelper); diff --git a/test/Common.FunctionalTests/ServerAbortTests.cs b/test/Common.FunctionalTests/ServerAbortTests.cs new file mode 100644 index 0000000000..8ebd70db12 --- /dev/null +++ b/test/Common.FunctionalTests/ServerAbortTests.cs @@ -0,0 +1,65 @@ +// 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.Net.Http; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Server.IntegrationTesting; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit; + +namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests +{ + public abstract class ServerAbortTests: FixtureLoggedTest + { + private readonly IISTestSiteFixture _fixture; + + [Collection(IISTestSiteCollection.Name)] + public class InProc: ServerAbortTests + { + public InProc(IISTestSiteFixture fixture) : base(fixture) { } + } + + [Collection(OutOfProcessTestSiteCollection.Name)] + public class OutOfProcess: ServerAbortTests + { + public OutOfProcess(OutOfProcessTestSiteFixture fixture) : base(fixture) { } + } + + [Collection(OutOfProcessV1TestSiteCollection.Name)] + public class OutOfProcessV1: ServerAbortTests + { + public OutOfProcessV1(OutOfProcessV1TestSiteFixture fixture) : base(fixture) { } + } + + protected ServerAbortTests(IISTestSiteFixture fixture) : base(fixture) + { + _fixture = fixture; + } + + [ConditionalFact] + public async Task ClosesConnectionOnServerAbort() + { + try + { + var response = await _fixture.Client.GetAsync("/Abort").DefaultTimeout(); + + // 502 is expected for outofproc but not for inproc + if (_fixture.DeploymentResult.DeploymentParameters.HostingModel == HostingModel.OutOfProcess) + { + Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode); + // 0x80072f78 ERROR_HTTP_INVALID_SERVER_RESPONSE The server returned an invalid or unrecognized response + Assert.Contains("0x80072f78", await response.Content.ReadAsStringAsync()); + } + else + { + Assert.True(false, "Should not reach here"); + } + } + catch (HttpRequestException) + { + // Connection reset is expected both for outofproc and inproc + } + } + } +} diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs index 8d53affc98..562d63adbe 100644 --- a/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs +++ b/test/Common.FunctionalTests/Utilities/IISTestSiteCollection.cs @@ -13,4 +13,17 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { public const string Name = nameof(IISTestSiteCollection); } + + [CollectionDefinition(Name)] + public class OutOfProcessTestSiteCollection : ICollectionFixture + { + public const string Name = nameof(OutOfProcessTestSiteCollection); + } + + [CollectionDefinition(Name)] + public class OutOfProcessV1TestSiteCollection : ICollectionFixture + { + public const string Name = nameof(OutOfProcessV1TestSiteCollection); + } + } diff --git a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs index 5628a1acfb..e8cfd8f641 100644 --- a/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs +++ b/test/Common.FunctionalTests/Utilities/IISTestSiteFixture.cs @@ -4,7 +4,6 @@ using System; 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; @@ -12,6 +11,33 @@ using Microsoft.Extensions.Logging.Testing; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests { + public class OutOfProcessTestSiteFixture : IISTestSiteFixture + { + public OutOfProcessTestSiteFixture() : base(Configure) + { + } + + private static void Configure(IISDeploymentParameters deploymentParameters) + { + deploymentParameters.ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(); + deploymentParameters.HostingModel = HostingModel.OutOfProcess; + } + } + + public class OutOfProcessV1TestSiteFixture : IISTestSiteFixture + { + public OutOfProcessV1TestSiteFixture() : base(Configure) + { + } + + private static void Configure(IISDeploymentParameters deploymentParameters) + { + deploymentParameters.ApplicationPath = Helpers.GetOutOfProcessTestSitesPath(); + deploymentParameters.HostingModel = HostingModel.OutOfProcess; + deploymentParameters.AncmVersion = AncmVersion.AspNetCoreModule; + } + } + public class IISTestSiteFixture : IDisposable { private ApplicationDeployer _deployer; diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index c92349ae3a..4757c1d59b 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -1,6 +1,7 @@ // 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.Net; @@ -52,6 +53,35 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests Assert.Equal(_helloWorldResponse, responseText); } + [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] + public async Task GlobalVersion_EnvironmentVariableWorks() + { + var temporaryFile = Path.GetTempFileName(); + try + { + var deploymentParameters = GetGlobalVersionBaseDeploymentParameters(); + CopyShimToOutput(deploymentParameters); + deploymentParameters.PublishApplicationBeforeDeployment = true; + deploymentParameters.EnvironmentVariables["ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER"] = temporaryFile; + + var deploymentResult = await DeployAsync(deploymentParameters); + var requestHandlerPath = Path.Combine(GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20), "aspnetcorev2_outofprocess.dll"); + + File.Delete(temporaryFile); + File.Move(requestHandlerPath, temporaryFile); + + var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest); + var responseText = await response.Content.ReadAsStringAsync(); + Assert.Equal(_helloWorldResponse, responseText); + StopServer(); + } + finally + { + File.Delete(temporaryFile); + } + } + [ConditionalTheory] [InlineData("2.1.0")] [InlineData("2.1.0-preview")] diff --git a/test/WebSites/InProcessWebSite/Properties/launchSettings.json b/test/WebSites/InProcessWebSite/Properties/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/test/WebSites/InProcessWebSite/Properties/launchSettings.json +++ b/test/WebSites/InProcessWebSite/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json b/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json +++ b/test/WebSites/OutOfProcessWebSite/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/test/WebSites/StressTestWebSite/Properties/launchSettings.json b/test/WebSites/StressTestWebSite/Properties/launchSettings.json index 9c963c0100..246b7a0b47 100644 --- a/test/WebSites/StressTestWebSite/Properties/launchSettings.json +++ b/test/WebSites/StressTestWebSite/Properties/launchSettings.json @@ -12,11 +12,11 @@ "commandName": "Executable", "executablePath": "$(IISExpressPath)", "commandLineArgs": "$(IISExpressArguments)", - "nativeDebugging": true, "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(TargetDir)\\$(AncmPath)", - "ANCMV2_PATH": "$(TargetDir)\\$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ANCM_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", @@ -29,8 +29,9 @@ "commandLineArgs": "$(IISArguments)", "environmentVariables": { "IIS_SITE_PATH": "$(MSBuildThisFileDirectory)", - "ANCM_PATH": "$(AncmPath)", - "ANCMV2_PATH": "$(AncmV2Path)", + "ANCM_PATH": "$(AspNetCoreModuleV1ShimDll)", + "ANCMV2_PATH": "$(AspNetCoreModuleV2ShimDll)", + "ASPNETCORE_MODULE_OUTOFPROCESS_HANDLER": "$(AspNetCoreModuleV2OutOfProcessHandlerDll)", "LAUNCHER_ARGS": "$(TargetPath)", "ASPNETCORE_ENVIRONMENT": "Development", "LAUNCHER_PATH": "$(DotNetPath)", diff --git a/test/WebSites/shared/SharedStartup/Startup.shared.cs b/test/WebSites/shared/SharedStartup/Startup.shared.cs index 2c08c93fa6..4035decb02 100644 --- a/test/WebSites/shared/SharedStartup/Startup.shared.cs +++ b/test/WebSites/shared/SharedStartup/Startup.shared.cs @@ -68,10 +68,16 @@ namespace TestSite } finally { - Interlocked.Decrement(ref _waitingRequestCount); + Interlocked.Decrement(ref _waitingRequestCount); } } + public Task Abort(HttpContext context) + { + context.Abort(); + return Task.CompletedTask; + } + public async Task WaitingRequestCount(HttpContext context) { await context.Response.WriteAsync(_waitingRequestCount.ToString()); From 24e2e5ad52d97ac4c83037e8ea26d72b31133bb6 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 15 Oct 2018 11:44:51 -0700 Subject: [PATCH 4/7] Port startup tests to IIS (#1513) --- .../IISDeployer.cs | 24 ++++++++++++------- .../Utilities/AppVerifier.cs | 2 +- .../Utilities/EventLogHelpers.cs | 2 +- .../Utilities/Helpers.cs | 8 ++++++- .../Inprocess}/StartupTests.cs | 7 ++++++ 5 files changed, 32 insertions(+), 11 deletions(-) rename test/{IISExpress.FunctionalTests/InProcess => IIS.FunctionalTests/Inprocess}/StartupTests.cs (98%) diff --git a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs index a2c3360cf4..4f2e525e72 100644 --- a/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs +++ b/src/Microsoft.AspNetCore.Server.IntegrationTesting.IIS/IISDeployer.cs @@ -119,12 +119,18 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS key: "hostingModel", value: DeploymentParameters.HostingModel.ToString()); - if (DeploymentParameters.ApplicationType == ApplicationType.Portable) - { - yield return WebConfigHelpers.AddOrModifyAspNetCoreSection( - "processPath", - DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture)); - } + yield return (element, _) => { + var aspNetCore = element + .Descendants("system.webServer") + .Single() + .GetOrAdd("aspNetCore"); + + // Expand path to dotnet because IIS process would not inherit PATH variable + if (aspNetCore.Attribute("processPath")?.Value.StartsWith("dotnet") == true) + { + aspNetCore.SetAttributeValue("processPath", DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture)); + } + }; yield return WebConfigHelpers.AddOrModifyHandlerSection( key: "modules", @@ -399,8 +405,10 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting.IIS redirectionSection.Attributes["enabled"].Value = false; serverManager.CommitChanges(); - - Directory.Delete(_configPath, true); + if (Directory.Exists(_configPath)) + { + Directory.Delete(_configPath, true); + } }); } } diff --git a/test/Common.FunctionalTests/Utilities/AppVerifier.cs b/test/Common.FunctionalTests/Utilities/AppVerifier.cs index ab059d789d..7984193e29 100644 --- a/test/Common.FunctionalTests/Utilities/AppVerifier.cs +++ b/test/Common.FunctionalTests/Utilities/AppVerifier.cs @@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting if (process.ExitCode != 0) { - throw new InvalidOperationException($"Exit code {process.ExitCode} when running {fileName} {arguments}. Stdout: {process.StandardOutput.ReadToEnd()}"); + throw new InvalidOperationException($"Exit code {process.ExitCode} when running {fileName} {arguments}. Stdout: {process.StandardOutput.ReadToEnd()} Stderr: {process.StandardError.ReadToEnd()}"); } } diff --git a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs index cf977b76f4..78c77fd2ca 100644 --- a/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs +++ b/test/Common.FunctionalTests/Utilities/EventLogHelpers.cs @@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public static string InProcessFailedToStop(IISDeploymentResult deploymentResult, string reason) { - return "Failed to gracefully shutdown application 'MACHINE/WEBROOT/APPHOST/HTTPTESTSITE'."; + return "Failed to gracefully shutdown application 'MACHINE/WEBROOT/APPHOST/.*?'."; } public static string InProcessThreadException(IISDeploymentResult deploymentResult, string reason) diff --git a/test/Common.FunctionalTests/Utilities/Helpers.cs b/test/Common.FunctionalTests/Utilities/Helpers.cs index f3cf2ba70d..4918a12781 100644 --- a/test/Common.FunctionalTests/Utilities/Helpers.cs +++ b/test/Common.FunctionalTests/Utilities/Helpers.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.Server.IntegrationTesting.IIS; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Logging; using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using Xunit; namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests @@ -203,5 +202,12 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var output = JsonConvert.SerializeObject(depsFileContent); File.WriteAllText(path, output); } + + public static void AllowNoLogs(this IISDeploymentResult deploymentResult) + { + File.AppendAllText( + Path.Combine(deploymentResult.DeploymentParameters.PublishedApplicationRootPath, "aspnetcore-debug.log"), + "Running test allowed log file to be empty." + Environment.NewLine); + } } } diff --git a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs b/test/IIS.FunctionalTests/Inprocess/StartupTests.cs similarity index 98% rename from test/IISExpress.FunctionalTests/InProcess/StartupTests.cs rename to test/IIS.FunctionalTests/Inprocess/StartupTests.cs index 037ab8eb2e..880a260582 100644 --- a/test/IISExpress.FunctionalTests/InProcess/StartupTests.cs +++ b/test/IIS.FunctionalTests/Inprocess/StartupTests.cs @@ -120,9 +120,13 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task StartsWithPortableAndBootstraperExe() { var deploymentParameters = _fixture.GetBaseDeploymentParameters(_fixture.InProcessTestSite, publish: true); + // We need the right dotnet on the path in IIS + deploymentParameters.EnvironmentVariables["PATH"] = Path.GetDirectoryName(DotNetCommands.GetDotNetExecutable(deploymentParameters.RuntimeArchitecture)); + // rest publisher as it doesn't support additional parameters deploymentParameters.ApplicationPublisher = null; // ReferenceTestTasks is workaround for https://github.com/dotnet/sdk/issues/2482 @@ -302,6 +306,9 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests var result = await deploymentResult.HttpClient.GetAsync("/HelloWorld"); Assert.Equal(HttpStatusCode.InternalServerError, result.StatusCode); + // Config load errors might not allow us to initialize log file + deploymentResult.AllowNoLogs(); + StopServer(); EventLogHelpers.VerifyEventLogEvents(deploymentResult, From 03084f8937855091578eaf1748f498633b6b5a0e Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Mon, 15 Oct 2018 14:45:30 -0700 Subject: [PATCH 5/7] Port more tests to IIS (#1518) --- .../Inprocess}/ErrorPagesTests.cs | 0 .../OutOfProcess/GlobalVersionTests.cs | 12 +----------- 2 files changed, 1 insertion(+), 11 deletions(-) rename test/{IISExpress.FunctionalTests/InProcess => Common.FunctionalTests/Inprocess}/ErrorPagesTests.cs (100%) rename test/{IISExpress.FunctionalTests => Common.FunctionalTests}/OutOfProcess/GlobalVersionTests.cs (94%) diff --git a/test/IISExpress.FunctionalTests/InProcess/ErrorPagesTests.cs b/test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs similarity index 100% rename from test/IISExpress.FunctionalTests/InProcess/ErrorPagesTests.cs rename to test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs diff --git a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs b/test/Common.FunctionalTests/OutOfProcess/GlobalVersionTests.cs similarity index 94% rename from test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs rename to test/Common.FunctionalTests/OutOfProcess/GlobalVersionTests.cs index 4757c1d59b..cb76b503c5 100644 --- a/test/IISExpress.FunctionalTests/OutOfProcess/GlobalVersionTests.cs +++ b/test/Common.FunctionalTests/OutOfProcess/GlobalVersionTests.cs @@ -33,18 +33,8 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests public async Task GlobalVersion_DefaultWorks() { var deploymentParameters = GetGlobalVersionBaseDeploymentParameters(); - deploymentParameters.PublishApplicationBeforeDeployment = false; - deploymentParameters.AddServerConfigAction( - element => - { - var handlerVersionElement = new XElement("handlerSetting"); - handlerVersionElement.SetAttributeValue("name", "handlerVersion"); - handlerVersionElement.SetAttributeValue("value", _handlerVersion20); - - element.Descendants("aspNetCore").Single() - .Add(new XElement("handlerSettings", handlerVersionElement)); - }); + deploymentParameters.HandlerSettings["handlerVersion"] = _handlerVersion20; var deploymentResult = await DeployAsync(deploymentParameters); From 3ae18fb53975d7287a33e6bef3e5bd16f4998698 Mon Sep 17 00:00:00 2001 From: Pavel Krymets Date: Tue, 16 Oct 2018 09:26:16 -0700 Subject: [PATCH 6/7] Add skip conditions (#1520) --- test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs | 4 ++++ test/IIS.FunctionalTests/Inprocess/StartupTests.cs | 2 ++ 2 files changed, 6 insertions(+) diff --git a/test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs b/test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs index 7669e7034a..6b0e0b93b2 100644 --- a/test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs +++ b/test/Common.FunctionalTests/Inprocess/ErrorPagesTests.cs @@ -23,6 +23,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task IncludesAdditionalErrorPageTextInProcessHandlerLoadFailure() { var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); @@ -37,6 +38,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task IncludesAdditionalErrorPageTextOutOfProcessStartupFailure() { var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true); @@ -51,6 +53,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task IncludesAdditionalErrorPageTextOutOfProcessHandlerLoadFailure() { var deploymentParameters = _fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess, publish: true); @@ -69,6 +72,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests } [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task IncludesAdditionalErrorPageTextInProcessStartupFailure() { var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); diff --git a/test/IIS.FunctionalTests/Inprocess/StartupTests.cs b/test/IIS.FunctionalTests/Inprocess/StartupTests.cs index 880a260582..fd77a400e3 100644 --- a/test/IIS.FunctionalTests/Inprocess/StartupTests.cs +++ b/test/IIS.FunctionalTests/Inprocess/StartupTests.cs @@ -31,6 +31,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests private readonly string _dotnetLocation = DotNetCommands.GetDotNetExecutable(RuntimeArchitecture.x64); [ConditionalFact] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task ExpandEnvironmentVariableInWebConfig() { // Point to dotnet installed in user profile. @@ -90,6 +91,7 @@ namespace Microsoft.AspNetCore.Server.IISIntegration.FunctionalTests [ConditionalTheory] [InlineData("dotnet")] [InlineData("dotnet.EXE")] + [RequiresIIS(IISCapability.PoolEnvironmentVariables)] public async Task StartsWithDotnetOnThePath(string path) { var deploymentParameters = _fixture.GetBaseDeploymentParameters(publish: true); From 9a9a504da348d96968235ac124b125e04fc04594 Mon Sep 17 00:00:00 2001 From: "ASP.NET CI" Date: Tue, 16 Oct 2018 12:48:15 -0700 Subject: [PATCH 7/7] Update package branding for 2.2 RTM --- version.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.props b/version.props index 378470ee63..6ccce8b1c1 100644 --- a/version.props +++ b/version.props @@ -7,7 +7,7 @@ 12 $(DotNetMinorVersion) $(DotNetPatchVersion) - preview3 + rtm $(VersionPrefix) $(VersionPrefix)-$(VersionSuffix)-final t000