File: src\Servers\IIS\IIS\test\Common.FunctionalTests\GlobalVersionTests.cs
Web Access
Project: src\src\Servers\IIS\IIS\test\IIS.FunctionalTests\IIS.FunctionalTests.csproj (IIS.FunctionalTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.IO;
using System.Linq;
using System.Net;
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.InternalTesting;
using Xunit;
 
#if !IIS_FUNCTIONALS
using Microsoft.AspNetCore.Server.IIS.FunctionalTests;
 
#if IISEXPRESS_FUNCTIONALS
namespace Microsoft.AspNetCore.Server.IIS.IISExpress.FunctionalTests;
#elif NEWHANDLER_FUNCTIONALS
namespace Microsoft.AspNetCore.Server.IIS.NewHandler.FunctionalTests;
#elif NEWSHIM_FUNCTIONALS
namespace Microsoft.AspNetCore.Server.IIS.NewShim.FunctionalTests;
#endif

#else
namespace Microsoft.AspNetCore.Server.IIS.FunctionalTests;
#endif
 
[Collection(PublishedSitesCollection.Name)]
[SkipOnHelix("Unsupported queue", Queues = "Windows.Amd64.VS2022.Pre.Open;")]
public class GlobalVersionTests : IISFunctionalTestBase
{
    public GlobalVersionTests(PublishedSitesFixture fixture) : base(fixture)
    {
    }
 
    private const string _handlerVersion20 = "2.0.0";
    private const string _helloWorldRequest = "HelloWorld";
    private const string _helloWorldResponse = "Hello World";
 
    [ConditionalFact]
    public async Task GlobalVersion_DefaultWorks()
    {
        var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
 
        deploymentParameters.HandlerSettings["handlerVersion"] = _handlerVersion20;
 
        var deploymentResult = await DeployAsync(deploymentParameters);
 
        var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest);
        var responseText = await response.Content.ReadAsStringAsync();
        Assert.Equal(_helloWorldResponse, responseText);
    }
 
    [ConditionalFact]
    [RequiresIIS(IISCapability.PoolEnvironmentVariables)]
    [RequiresNewShim]
    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")]
    [InlineData("7.0.0")]
    [InlineData("7.0.0-preview")]
    public async Task GlobalVersion_NewVersionNumber_Fails(string version)
    {
        var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
        deploymentParameters.HandlerSettings["handlerVersion"] = version;
 
        var deploymentResult = await DeployAsync(deploymentParameters);
 
        var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest);
        Assert.False(response.IsSuccessStatusCode);
        var responseString = await response.Content.ReadAsStringAsync();
        Assert.Contains("500.0", responseString);
    }
 
    [ConditionalTheory]
    [InlineData("2.1.0")]
    [InlineData("2.1.0-preview")]
    [InlineData("7.0.0")]
    [InlineData("7.0.0-preview")]
    public async Task GlobalVersion_NewVersionNumber(string version)
    {
        var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
        CopyShimToOutput(deploymentParameters);
        deploymentParameters.HandlerSettings["handlerVersion"] = version;
 
        var deploymentResult = await DeployAsync(deploymentParameters);
 
        var originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
        var newANCMPath = GetANCMRequestHandlerPath(deploymentResult, version);
        Directory.Move(originalANCMPath, newANCMPath);
 
        var response = await deploymentResult.HttpClient.GetAsync(_helloWorldRequest);
        var responseText = await response.Content.ReadAsStringAsync();
        Assert.Equal(_helloWorldResponse, responseText);
        AssertLoadedVersion(version);
    }
 
    [ConditionalTheory]
    [InlineData("2.1.0")]
    [InlineData("2.1.0-preview")]
    [InlineData("7.0.0")]
    [InlineData("7.0.0-preview")]
    public async Task GlobalVersion_MultipleRequestHandlers_PicksHighestOne(string version)
    {
        var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
        CopyShimToOutput(deploymentParameters);
        var deploymentResult = await DeployAsync(deploymentParameters);
 
        var originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
 
        var newANCMPath = GetANCMRequestHandlerPath(deploymentResult, version);
 
        CopyDirectory(originalANCMPath, newANCMPath);
 
        deploymentResult.HttpClient.DefaultRequestHeaders.Add("ANCMRHPath", newANCMPath);
        var response = await deploymentResult.HttpClient.GetAsync("CheckRequestHandlerVersion");
        var responseText = await response.Content.ReadAsStringAsync();
 
        Assert.Equal(_helloWorldResponse, responseText);
        AssertLoadedVersion(version);
    }
 
    [ConditionalTheory]
    [InlineData("2.1.0")]
    [InlineData("2.1.0-preview")]
    [InlineData("7.0.0")]
    [InlineData("7.0.0-preview")]
    public async Task GlobalVersion_MultipleRequestHandlers_UpgradeWorks(string version)
    {
        var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
        CopyShimToOutput(deploymentParameters);
        var deploymentResult = await DeployAsync(deploymentParameters);
 
        var originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
 
        deploymentResult.HttpClient.DefaultRequestHeaders.Add("ANCMRHPath", originalANCMPath);
        var response = await deploymentResult.HttpClient.GetAsync("CheckRequestHandlerVersion");
        var responseText = await response.Content.ReadAsStringAsync();
 
        Assert.Equal(_helloWorldResponse, responseText);
 
        StopServer();
 
        deploymentResult = await DeployAsync(deploymentParameters);
 
        originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
 
        var newANCMPath = GetANCMRequestHandlerPath(deploymentResult, version);
 
        CopyDirectory(originalANCMPath, newANCMPath);
 
        deploymentResult.HttpClient.DefaultRequestHeaders.Add("ANCMRHPath", newANCMPath);
        response = await deploymentResult.HttpClient.GetAsync("CheckRequestHandlerVersion");
        responseText = await response.Content.ReadAsStringAsync();
 
        Assert.Equal(_helloWorldResponse, responseText);
        AssertLoadedVersion(version);
    }
 
    [ConditionalFact]
    public async Task DoesNotCrashWhenNoVersionsAvailable()
    {
        var deploymentParameters = GetGlobalVersionBaseDeploymentParameters();
        CopyShimToOutput(deploymentParameters);
        var deploymentResult = await DeployAsync(deploymentParameters);
 
        var originalANCMPath = GetANCMRequestHandlerPath(deploymentResult, _handlerVersion20);
        Directory.Delete(originalANCMPath, true);
        var response = await deploymentResult.HttpClient.GetAsync("HelloWorld");
 
        Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode);
    }
 
    private IISDeploymentParameters GetGlobalVersionBaseDeploymentParameters()
    {
        return Fixture.GetBaseDeploymentParameters(HostingModel.OutOfProcess);
    }
 
    private void CopyDirectory(string from, string to)
    {
        var toInfo = new DirectoryInfo(to);
        toInfo.Create();
 
        foreach (var file in new DirectoryInfo(from).GetFiles())
        {
            file.CopyTo(Path.Combine(toInfo.FullName, file.Name));
        }
    }
 
    private string GetANCMRequestHandlerPath(IISDeploymentResult deploymentResult, string version)
    {
        return Path.Combine(deploymentResult.ContentRoot,
            deploymentResult.DeploymentParameters.RuntimeArchitecture.ToString(),
            version);
    }
 
    private void AssertLoadedVersion(string version)
    {
        StopServer();
        Assert.Contains(TestSink.Writes, context => context.Message.Contains(version + @"\aspnetcorev2_outofprocess.dll"));
    }
 
    private static void CopyShimToOutput(IISDeploymentParameters parameters)
    {
        parameters.AddServerConfigAction(
            (config, contentRoot) =>
            {
                var moduleNodes = config.DescendantNodesAndSelf()
                    .OfType<XElement>()
                    .Where(element =>
                        element.Name == "add" &&
                        element.Attribute("name")?.Value.StartsWith("AspNetCoreModule", StringComparison.Ordinal) == true &&
                        element.Attribute("image") != null);
 
                var sourceDirectory = new DirectoryInfo(Path.GetDirectoryName(moduleNodes.First().Attribute("image").Value));
                var destinationDirectory = new DirectoryInfo(Path.Combine(contentRoot, sourceDirectory.Name));
                destinationDirectory.Create();
                foreach (var element in moduleNodes)
                {
                    var imageAttribute = element.Attribute("image");
                    imageAttribute.Value = imageAttribute.Value.Replace(sourceDirectory.FullName, destinationDirectory.FullName);
                }
                CopyFiles(sourceDirectory, destinationDirectory);
            });
    }
 
    private static void CopyFiles(DirectoryInfo source, DirectoryInfo target)
    {
        foreach (DirectoryInfo directoryInfo in source.GetDirectories())
        {
            CopyFiles(directoryInfo, target.CreateSubdirectory(directoryInfo.Name));
        }
 
        foreach (FileInfo fileInfo in source.GetFiles())
        {
            var destFileName = Path.Combine(target.FullName, fileInfo.Name);
            fileInfo.CopyTo(destFileName, overwrite: true);
        }
    }
}