Enable x86 testing #949

This commit is contained in:
Chris Ross (ASP.NET) 2018-05-18 16:39:14 -07:00
parent 5906740cdb
commit 09d3b32fe5
9 changed files with 204 additions and 65 deletions

View File

@ -65,11 +65,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
throw new DirectoryNotFoundException(string.Format("Application path {0} does not exist.", applicationPath));
}
if (runtimeArchitecture == RuntimeArchitecture.x86 && runtimeFlavor == RuntimeFlavor.CoreClr)
{
throw new NotSupportedException("32 bit deployment is not yet supported for CoreCLR. Don't remove the tests, just disable them for now.");
}
ApplicationPath = applicationPath;
ApplicationName = new DirectoryInfo(ApplicationPath).Name;
ServerType = serverType;

View File

@ -0,0 +1,71 @@
// 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.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Server.IntegrationTesting.Common
{
internal static class DotNetCommands
{
private const string _dotnetFolderName = ".dotnet";
internal static string DotNetHome { get; } = GetDotNetHome();
// Compare to https://github.com/aspnet/BuildTools/blob/314c98e4533217a841ff9767bb38e144eb6c93e4/tools/KoreBuild.Console/Commands/CommandContext.cs#L76
private static string GetDotNetHome()
{
var dotnetHome = Environment.GetEnvironmentVariable("DOTNET_HOME");
var userProfile = Environment.GetEnvironmentVariable("USERPROFILE");
var home = Environment.GetEnvironmentVariable("HOME");
var result = Path.Combine(Directory.GetCurrentDirectory(), _dotnetFolderName);
if (!string.IsNullOrEmpty(dotnetHome))
{
result = dotnetHome;
}
else if (!string.IsNullOrEmpty(userProfile))
{
result = Path.Combine(userProfile, _dotnetFolderName);
}
else if (!string.IsNullOrEmpty(home))
{
result = home;
}
return result;
}
internal static string GetDotNetInstallDir(RuntimeArchitecture arch)
{
var dotnetDir = DotNetHome;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
dotnetDir = Path.Combine(dotnetDir, arch.ToString());
}
return dotnetDir;
}
internal static string GetDotNetExecutable(RuntimeArchitecture arch)
{
var dotnetDir = GetDotNetInstallDir(arch);
var dotnetFile = "dotnet";
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
dotnetFile += ".exe";
}
return Path.Combine(dotnetDir, dotnetFile);
}
internal static bool IsRunningX86OnX64(RuntimeArchitecture arch)
{
return (RuntimeInformation.OSArchitecture == Architecture.X64 || RuntimeInformation.OSArchitecture == Architecture.Arm64)
&& arch == RuntimeArchitecture.x86;
}
}
}

View File

@ -47,11 +47,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
DeploymentParameters.RuntimeFlavor = GetRuntimeFlavor(DeploymentParameters.TargetFramework);
}
if (DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86 && DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr)
{
throw new NotSupportedException("32 bit deployment is not yet supported for CoreCLR. Don't remove the tests, just disable them for now.");
}
if (string.IsNullOrEmpty(DeploymentParameters.ApplicationPath))
{
throw new ArgumentException("ApplicationPath cannot be null.");

View File

@ -35,14 +35,6 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
{
}
public bool Is64BitHost
{
get
{
return Environment.Is64BitOperatingSystem;
}
}
public override async Task<DeploymentResult> DeployAsync()
{
using (Logger.BeginScope("Deployment"))
@ -128,6 +120,7 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
}
ModifyHandlerSectionInWebConfig(key: "modules", value: DeploymentParameters.AncmVersion.ToString());
ModifyDotNetExePathInWebConfig();
var parameters = string.IsNullOrWhiteSpace(DeploymentParameters.ServerConfigLocation) ?
string.Format("/port:{0} /path:\"{1}\" /trace:error", uri.Port, contentRoot) :
@ -228,7 +221,8 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
{
if (serverConfig.Contains(replaceFlag))
{
var ancmFile = Path.Combine(contentRoot, Is64BitHost ? $@"x64\{dllName}" : $@"x86\{dllName}");
var arch = DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x64 ? $@"x64\{dllName}" : $@"x86\{dllName}";
var ancmFile = Path.Combine(contentRoot, arch);
if (!File.Exists(Environment.ExpandEnvironmentVariables(ancmFile)))
{
ancmFile = Path.Combine(contentRoot, dllName);
@ -246,8 +240,14 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
private string GetIISExpressPath()
{
var programFiles = "Program Files";
if (DotNetCommands.IsRunningX86OnX64(DeploymentParameters.RuntimeArchitecture))
{
programFiles = "Program Files (x86)";
}
// Get path to program files
var iisExpressPath = Path.Combine(Environment.GetEnvironmentVariable("SystemDrive") + "\\", "Program Files", "IIS Express", "iisexpress.exe");
var iisExpressPath = Path.Combine(Environment.GetEnvironmentVariable("SystemDrive") + "\\", programFiles, "IIS Express", "iisexpress.exe");
if (!File.Exists(iisExpressPath))
{
@ -297,8 +297,24 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
}
}
// Transforms the web.config file to include the hostingModel="inprocess" element
// and adds the server type = Microsoft.AspNetServer.IIS such that Kestrel isn't added again in ServerTests
private void ModifyDotNetExePathInWebConfig()
{
// We assume the x64 dotnet.exe is on the path so we need to provide an absolute path for x86 scenarios.
// Only do it for scenarios that rely on dotnet.exe (Core, portable, etc.).
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr
&& DeploymentParameters.ApplicationType == ApplicationType.Portable
&& DotNetCommands.IsRunningX86OnX64(DeploymentParameters.RuntimeArchitecture))
{
var executableName = DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture);
if (!File.Exists(executableName))
{
throw new Exception($"Unable to find '{executableName}'.'");
}
ModifyAspNetCoreSectionInWebConfig("processPath", executableName);
}
}
// Transforms the web.config file to set attributes like hostingModel="inprocess" element
private void ModifyAspNetCoreSectionInWebConfig(string key, string value)
{
var webConfigFile = $"{DeploymentParameters.PublishedApplicationRootPath}/web.config";

View File

@ -35,6 +35,13 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
var redirectUri = TestUriHelper.BuildTestUri(ServerType.Nginx);
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr
&& DeploymentParameters.ApplicationType == ApplicationType.Standalone)
{
// Publish is required to get the correct files in the output directory
DeploymentParameters.PublishApplicationBeforeDeployment = true;
}
if (DeploymentParameters.PublishApplicationBeforeDeployment)
{
DotnetPublish();

View File

@ -36,6 +36,20 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
// Start timer
StartTimer();
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr
&& DeploymentParameters.RuntimeArchitecture == RuntimeArchitecture.x86)
{
// Publish is required to rebuild for the right bitness
DeploymentParameters.PublishApplicationBeforeDeployment = true;
}
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr
&& DeploymentParameters.ApplicationType == ApplicationType.Standalone)
{
// Publish is required to get the correct files in the output directory
DeploymentParameters.PublishApplicationBeforeDeployment = true;
}
if (DeploymentParameters.PublishApplicationBeforeDeployment)
{
DotnetPublish();
@ -65,37 +79,42 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
{
using (Logger.BeginScope("StartSelfHost"))
{
string executableName;
string executableArgs = string.Empty;
string workingDirectory = string.Empty;
var executableName = string.Empty;
var executableArgs = string.Empty;
var workingDirectory = string.Empty;
var executableExtension = DeploymentParameters.ApplicationType == ApplicationType.Portable ? ".dll"
: (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "");
if (DeploymentParameters.PublishApplicationBeforeDeployment)
{
workingDirectory = DeploymentParameters.PublishedApplicationRootPath;
var executableExtension =
DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr ? ".exe" :
DeploymentParameters.ApplicationType == ApplicationType.Portable ? ".dll" : "";
var executable = Path.Combine(DeploymentParameters.PublishedApplicationRootPath, DeploymentParameters.ApplicationName + executableExtension);
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr && DeploymentParameters.ApplicationType == ApplicationType.Portable)
{
executableName = "dotnet";
executableArgs = executable;
}
else
{
executableName = executable;
}
}
else
{
workingDirectory = DeploymentParameters.ApplicationPath;
var targetFramework = DeploymentParameters.TargetFramework ?? (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr ? Tfm.Net461 : Tfm.NetCoreApp22);
executableName = DotnetCommandName;
executableArgs = $"run --no-build -c {DeploymentParameters.Configuration} --framework {targetFramework} {DotnetArgumentSeparator}";
// Core+Standalone always publishes. This must be Clr+Standalone or Core+Portable.
// Run from the pre-built bin/{config}/{tfm} directory.
var targetFramework = DeploymentParameters.TargetFramework
?? (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.Clr ? Tfm.Net461 : Tfm.NetCoreApp22);
workingDirectory = Path.Combine(DeploymentParameters.ApplicationPath, "bin", DeploymentParameters.Configuration, targetFramework);
// CurrentDirectory will point to bin/{config}/{tfm}, but the config and static files aren't copied, point to the app base instead.
DeploymentParameters.EnvironmentVariables["ASPNETCORE_CONTENTROOT"] = DeploymentParameters.ApplicationPath;
}
executableArgs += $" --urls {hintUrl} "
+ $" --server {(DeploymentParameters.ServerType == ServerType.HttpSys ? "Microsoft.AspNetCore.Server.HttpSys" : "Microsoft.AspNetCore.Server.Kestrel")}";
var executable = Path.Combine(workingDirectory, DeploymentParameters.ApplicationName + executableExtension);
if (DeploymentParameters.RuntimeFlavor == RuntimeFlavor.CoreClr && DeploymentParameters.ApplicationType == ApplicationType.Portable)
{
executableName = GetDotNetExeForArchitecture();
executableArgs = executable;
}
else
{
executableName = executable;
}
var server = DeploymentParameters.ServerType == ServerType.HttpSys
? "Microsoft.AspNetCore.Server.HttpSys" : "Microsoft.AspNetCore.Server.Kestrel";
executableArgs += $" --urls {hintUrl} --server {server}";
Logger.LogInformation($"Executing {executableName} {executableArgs}");
@ -175,6 +194,22 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
}
}
private string GetDotNetExeForArchitecture()
{
var executableName = DotnetCommandName;
// We expect x64 dotnet.exe to be on the path but we have to go searching for the x86 version.
if (DotNetCommands.IsRunningX86OnX64(DeploymentParameters.RuntimeArchitecture))
{
executableName = DotNetCommands.GetDotNetExecutable(DeploymentParameters.RuntimeArchitecture);
if (!File.Exists(executableName))
{
throw new Exception($"Unable to find '{executableName}'.'");
}
}
return executableName;
}
public override void Dispose()
{
using (Logger.BeginScope("SelfHost.Dispose"))

View File

@ -246,9 +246,15 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
{
foreach (var arch in Architectures)
{
if (!IsArchitectureSupportedOnServer(arch, server))
{
continue;
}
var archSkip = skip ?? SkipIfArchitectureNotSupportedOnCurrentSystem(arch);
if (server == ServerType.IISExpress)
{
VaryByAncmVersion(variants, server, tfm, type, arch, skip);
VaryByAncmVersion(variants, server, tfm, type, arch, archSkip);
}
else
{
@ -258,12 +264,31 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
Tfm = tfm,
ApplicationType = type,
Architecture = arch,
Skip = skip,
Skip = archSkip,
});
}
}
}
private string SkipIfArchitectureNotSupportedOnCurrentSystem(RuntimeArchitecture arch)
{
if (arch == RuntimeArchitecture.x64)
{
// Can't run x64 on a x86 OS.
return (RuntimeInformation.OSArchitecture == Architecture.Arm || RuntimeInformation.OSArchitecture == Architecture.X86)
? $"Cannot run {arch} on your current system." : null;
}
// No x86 runtimes available on MacOS or Linux.
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? null : $"No {arch} available for non-Windows systems.";
}
private bool IsArchitectureSupportedOnServer(RuntimeArchitecture arch, ServerType server)
{
// No x86 Mac/Linux runtime, don't generate a test variation that will always be skipped.
return !(arch == RuntimeArchitecture.x86 && ServerType.Nginx == server);
}
private void VaryByAncmVersion(IList<TestVariant> variants, ServerType server, string tfm, ApplicationType type, RuntimeArchitecture arch, string skip)
{
foreach (var version in AncmVersions)

View File

@ -21,7 +21,13 @@ namespace Microsoft.AspNetCore.Server.IntegrationTesting
public override string ToString()
{
// For debug and test explorer view
return $"Server: {Server}, TFM: {Tfm}, Type: {ApplicationType}, Host: {HostingModel}, ANCM: {AncmVersion}, Arch: {Architecture}";
var description = $"Server: {Server}, TFM: {Tfm}, Type: {ApplicationType}, Arch: {Architecture}";
if (Server == ServerType.IISExpress)
{
var version = AncmVersion == AncmVersion.AspNetCoreModule ? "V1" : "V2";
description += $", ANCM: {version}, Host: {HostingModel}";
}
return description;
}
public void Serialize(IXunitSerializationInfo info)

View File

@ -2,32 +2,21 @@
// 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.Runtime.InteropServices;
using Microsoft.AspNetCore.Testing.xunit;
namespace Microsoft.AspNetCore.Server.IntegrationTesting
{
/// <summary>
/// Skips a 64 bit test if the current Windows OS is 32-bit.
/// Skips a 64 bit test if the current OS is 32-bit.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class SkipOn32BitOSAttribute : Attribute, ITestCondition
{
public bool IsMet
{
get
{
// Directory found only on 64-bit OS.
return Directory.Exists(Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), "SysWOW64"));
}
}
public bool IsMet =>
RuntimeInformation.OSArchitecture == Architecture.Arm64
|| RuntimeInformation.OSArchitecture == Architecture.X64;
public string SkipReason
{
get
{
return "Skipping the x64 test since Windows is 32-bit";
}
}
public string SkipReason => "Skipping the x64 test since Windows is 32-bit";
}
}