diff --git a/scripts/common.lib.ps1 b/scripts/common.lib.ps1 index bd5adaba25..1e44242bd0 100644 --- a/scripts/common.lib.ps1 +++ b/scripts/common.lib.ps1 @@ -60,7 +60,7 @@ function Write-Log { [string] $Level = "Success" ) - + if ($message) { $color = if ("Success" -eq $Level) { "Green" } else { "Red" } @@ -116,7 +116,7 @@ function Install-DotNetCli & $dotnetInstallScript -InstallDir "${dotnetInstallPath}_x86" -Runtime 'dotnet' -Channel '5.0' -Architecture x86 -NoPath -Version '5.0.16' & $dotnetInstallScript -InstallDir "${dotnetInstallPath}_x86" -Runtime 'dotnet' -Channel '6.0' -Architecture x86 -NoPath -Version '6.0.4' & $dotnetInstallScript -InstallDir "${dotnetInstallPath}_x86" -Channel '7.0' -Architecture x86 -NoPath -Version $env:DOTNET_CLI_VERSION - + $env:DOTNET_ROOT= $dotnetInstallPath ${env:DOTNET_ROOT(x86)} = "${dotnetInstallPath}_x86" @@ -260,10 +260,10 @@ public class ProcessOutputter AppendLine(e.Data); if (suppressOutput || e.Data == null) - { + { return; } - + // These handlers can run at the same time, // without lock they sometimes grab the color the other // one set. @@ -278,7 +278,7 @@ public class ProcessOutputter // one extra space before the word, to avoid highlighting // warnaserror and similar parameters that are not actual errors // - // The comparison is not done using the insensitive overload because that + // The comparison is not done using the insensitive overload because that // is too new for PowerShell 5 compiler var lineToLower = line.ToLowerInvariant(); Console.ForegroundColor = lineToLower.Contains(" warning") @@ -387,4 +387,4 @@ function Start-InlineProcess { $process.remove_ErrorDataReceived($errorDataReceived) $process.Dispose() } -} \ No newline at end of file +} diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs index 48f0cd64d8..3b7c9a11bf 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs @@ -52,6 +52,8 @@ public class DotnetTestHostManager : ITestRuntimeProvider2 private const string TestAdapterRegexPattern = @"TestAdapter.dll"; private const string PROCESSOR_ARCHITECTURE = nameof(PROCESSOR_ARCHITECTURE); + private static readonly Version Version6_0 = new(6, 0); + private readonly IDotnetHostHelper _dotnetHostHelper; private readonly IEnvironment _platformEnvironment; private readonly IProcessHelper _processHelper; @@ -469,24 +471,7 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo( // i.e. I've got only private install and no global installation, in this case apphost needs to use env var to locate runtime. if (testHostExeFound) { - string prefix = "VSTEST_WINAPPHOST_"; - string dotnetRootEnvName = $"{prefix}DOTNET_ROOT(x86)"; - var dotnetRoot = _environmentVariableHelper.GetEnvironmentVariable(dotnetRootEnvName); - if (dotnetRoot is null) - { - dotnetRootEnvName = $"{prefix}DOTNET_ROOT"; - dotnetRoot = _environmentVariableHelper.GetEnvironmentVariable(dotnetRootEnvName); - } - - if (dotnetRoot != null) - { - EqtTrace.Verbose($"DotnetTestHostmanager.LaunchTestHostAsync: Found '{dotnetRootEnvName}' in env variables, value '{dotnetRoot}', forwarding to '{dotnetRootEnvName.Replace(prefix, string.Empty)}'"); - startInfo.EnvironmentVariables.Add(dotnetRootEnvName.Replace(prefix, string.Empty), dotnetRoot); - } - else - { - EqtTrace.Verbose($"DotnetTestHostmanager.LaunchTestHostAsync: Prefix '{prefix}*' not found in env variables"); - } + ForwardDotnetRootEnvironmentVariable(startInfo); } startInfo.WorkingDirectory = sourceDirectory; @@ -565,6 +550,53 @@ bool SilentlyForceToX64() } } + internal /* for testing purposes */ void ForwardDotnetRootEnvironmentVariable(TestProcessStartInfo startInfo) + { + const string prefix = "VSTEST_WINAPPHOST_"; + const string dotnetRoot = "DOTNET_ROOT"; + string vstestDotnetRootEnvName = $"{prefix}{dotnetRoot}(x86)"; + + // Check if VSTEST_WINAPPHOST_DOTNET_ROOT(x86) is set, if not then looks for VSTEST_WINAPPHOST_DOTNET_ROOT. + // If none of these variables is set we exit as we have nothing to forward. + var vstestDotnetRootEnvValue = _environmentVariableHelper.GetEnvironmentVariable(vstestDotnetRootEnvName); + if (vstestDotnetRootEnvValue is null) + { + vstestDotnetRootEnvName = $"{prefix}{dotnetRoot}"; + vstestDotnetRootEnvValue = _environmentVariableHelper.GetEnvironmentVariable(vstestDotnetRootEnvName); + + // None of the forwarding environment variables are set so exit. + if (vstestDotnetRootEnvValue is null) + { + EqtTrace.Verbose($"DotnetTestHostmanager.LaunchTestHostAsync: Prefix '{prefix}*' not found in env variables"); + return; + } + } + + // For .NET 6.0 onward, the DOTNET_ROOT* environment variable to set was changed. + // This implementation is based on the logic defined in SDK: + // https://github.com/dotnet/sdk/blob/c3f8d746f4d5cd87f462d711a3caa7a4f6621826/src/Cli/dotnet/commands/dotnet-run/RunCommand.cs#L264-L279 + string dotnetRootEnvName; + if (Version.Parse(_targetFramework.Version) >= Version6_0) + { + dotnetRootEnvName = $"{dotnetRoot}_{_processHelper.GetCurrentProcessArchitecture().ToString().ToUpperInvariant()}"; + + // SDK side of TP is not checking for the .NET6.0+ environment variables so we want to make sure we + // are not overriding user definition. + if (_environmentVariableHelper.GetEnvironmentVariable(dotnetRootEnvName) is string dotnetRootEnvValue) + { + EqtTrace.Verbose($"DotnetTestHostmanager.LaunchTestHostAsync: Found '{vstestDotnetRootEnvName}' in env variables but also found '{dotnetRootEnvName}' with value '{dotnetRootEnvValue}'. Skipping forwarding."); + return; + } + } + else + { + dotnetRootEnvName = vstestDotnetRootEnvName.Replace(prefix, string.Empty); + } + + EqtTrace.Verbose($"DotnetTestHostmanager.LaunchTestHostAsync: Found '{vstestDotnetRootEnvName}' in env variables, value '{vstestDotnetRootEnvValue}', forwarding to '{dotnetRootEnvName}' (target framework is {_targetFramework.Name}, Version={_targetFramework.Version})."); + startInfo.EnvironmentVariables.Add(dotnetRootEnvName, vstestDotnetRootEnvValue); + } + /// public IEnumerable GetTestPlatformExtensions(IEnumerable sources, IEnumerable extensions) { diff --git a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs index 581c26ad93..f43901dbbe 100644 --- a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs +++ b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs @@ -987,6 +987,143 @@ public async Task CleanTestHostAsyncShouldNotThrowIfTestHostIsNotStarted() Assert.IsTrue(isVerified); } + [TestMethod] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT(x86)", "DOTNET_ROOT(x86)")] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT", "DOTNET_ROOT")] + public void ForwardDotnetRootEnvironmentVariableWhenTargetFrameworkIsLessThanNet6SetsCorrectEnvVariable(string envVarName, string expectedForwaredName) + { + // Arrange + const string envVarValue = "c:\\SomePath"; + _mockEnvironmentVariable.Reset(); + _mockEnvironmentVariable.Setup(x => x.GetEnvironmentVariable(envVarName)).Returns(envVarValue); + string runSettingsXml = """ + + + net5.0 + + + """; + _dotnetHostManager.Initialize(_mockMessageLogger.Object, runSettingsXml); + + var startInfo = new TestProcessStartInfo { EnvironmentVariables = new Dictionary() }; + // Sanity check + Assert.AreEqual(0, startInfo.EnvironmentVariables.Count); + + // Act + _dotnetHostManager.ForwardDotnetRootEnvironmentVariable(startInfo); + + // Assert + Assert.AreEqual(1, startInfo.EnvironmentVariables.Count); + Assert.IsTrue(startInfo.EnvironmentVariables.TryGetValue(expectedForwaredName, out var actualEnvVarValue)); + Assert.AreEqual(envVarValue, actualEnvVarValue); + } + + [TestMethod] + [DataRow("DOTNET_ROOT(x86)", "net5.0")] + [DataRow("DOTNET_ROOT(x86)", "net6.0")] + [DataRow("DOTNET_ROOT", "net5.0")] + [DataRow("DOTNET_ROOT", "net6.0")] + [DataRow("DOTNET_ROOT_X86", "net5.0")] + [DataRow("DOTNET_ROOT_X86", "net6.0")] + [DataRow("DOTNET_ROOT_X64", "net5.0")] + [DataRow("DOTNET_ROOT_X64", "net6.0")] + [DataRow("DOTNET_ROOT_ARM64", "net5.0")] + [DataRow("DOTNET_ROOT_ARM64", "net6.0")] + public void ForwardDotnetRootEnvironmentVariableWhenIncorrectEnvVarDoesNothing(string envVarName, string framework) + { + // Arrange + const string envVarValue = "c:\\SomePath"; + _mockEnvironmentVariable.Reset(); + _mockEnvironmentVariable.Setup(x => x.GetEnvironmentVariable(envVarName)).Returns(envVarValue); + string runSettingsXml = $""" + + + {framework} + + + """; + _dotnetHostManager.Initialize(_mockMessageLogger.Object, runSettingsXml); + + var startInfo = new TestProcessStartInfo { EnvironmentVariables = new Dictionary() }; + + // Act + _dotnetHostManager.ForwardDotnetRootEnvironmentVariable(startInfo); + + // Assert + Assert.AreEqual(0, startInfo.EnvironmentVariables.Count); + } + + [TestMethod] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT(x86)", PlatformArchitecture.X86)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT(x86)", PlatformArchitecture.X64)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT", PlatformArchitecture.X86)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT", PlatformArchitecture.X64)] + public void ForwardDotnetRootEnvironmentVariableWhenTargetFrameworkIsGreaterOrEqualsToNet6SetsCorrectEnvVariable(string envVarName, PlatformArchitecture platformArchitecture) + { + // Arrange + const string envVarValue = "c:\\SomePath"; + _mockEnvironmentVariable.Reset(); + _mockEnvironmentVariable.Setup(x => x.GetEnvironmentVariable(envVarName)).Returns(envVarValue); + _mockProcessHelper.Setup(x => x.GetCurrentProcessArchitecture()).Returns(platformArchitecture); + string runSettingsXml = """ + + + net6.0 + + + """; + _dotnetHostManager.Initialize(_mockMessageLogger.Object, runSettingsXml); + + var startInfo = new TestProcessStartInfo { EnvironmentVariables = new Dictionary() }; + // Sanity check + Assert.AreEqual(0, startInfo.EnvironmentVariables.Count); + + // Act + _dotnetHostManager.ForwardDotnetRootEnvironmentVariable(startInfo); + + // Assert + Assert.AreEqual(1, startInfo.EnvironmentVariables.Count); + Assert.IsTrue(startInfo.EnvironmentVariables.TryGetValue($"DOTNET_ROOT_{platformArchitecture.ToString().ToUpperInvariant()}", out var actualEnvVarValue)); + Assert.AreEqual(envVarValue, actualEnvVarValue); + } + + [TestMethod] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT(x86)", PlatformArchitecture.X86)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT(x86)", PlatformArchitecture.X64)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT(x86)", PlatformArchitecture.ARM64)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT", PlatformArchitecture.X86)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT", PlatformArchitecture.X64)] + [DataRow("VSTEST_WINAPPHOST_DOTNET_ROOT", PlatformArchitecture.ARM64)] + public void ForwardDotnetRootEnvironmentVariableWhenTargetFrameworkIsGreaterOrEqualsToNet6DoesNotOverrideEnvVar(string envVarName, PlatformArchitecture platformArchitecture) + { + // Arrange + const string expectedEnvVarValue = "c:\\SomePath"; + const string nonForwardedEnvVarValue = "C:\\SomeOtherPath"; + var expectedForwardedEnvVarName = $"DOTNET_ROOT_{platformArchitecture.ToString().ToUpperInvariant()}"; + _mockEnvironmentVariable.Reset(); + _mockEnvironmentVariable.Setup(x => x.GetEnvironmentVariable(envVarName)).Returns(expectedEnvVarValue); + _mockEnvironmentVariable.Setup(x => x.GetEnvironmentVariable(expectedForwardedEnvVarName)).Returns(nonForwardedEnvVarValue); + _mockProcessHelper.Setup(x => x.GetCurrentProcessArchitecture()).Returns(platformArchitecture); + string runSettingsXml = """ + + + net6.0 + + + """; + _dotnetHostManager.Initialize(_mockMessageLogger.Object, runSettingsXml); + + var startInfo = new TestProcessStartInfo { EnvironmentVariables = new Dictionary() }; + // Sanity check + Assert.AreEqual(0, startInfo.EnvironmentVariables.Count); + + // Act + _dotnetHostManager.ForwardDotnetRootEnvironmentVariable(startInfo); + + // Assert + Assert.AreEqual(0, startInfo.EnvironmentVariables.Count); + } + private void DotnetHostManagerExitCodeTesterHostExited(object? sender, HostProviderEventArgs e) { _errorMessage = e.Data.TrimEnd(Environment.NewLine.ToCharArray()); diff --git a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs index 7ff7338257..7395967239 100644 --- a/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs +++ b/test/Microsoft.TestPlatform.TestUtilities/IntegrationTestBase.cs @@ -193,7 +193,7 @@ public void InvokeVsTest(string arguments, Dictionary? environme /// Invokes our local copy of dotnet that is patched with artifacts from the build with specified arguments. /// /// Arguments provided to vstest.console.exe - public void InvokeDotnetTest(string arguments, Dictionary? environmentVariables = null) + public void InvokeDotnetTest(string arguments, Dictionary? environmentVariables = null, bool useDotnetFromTools = false, string? workingDirectory = null) { var debugEnvironmentVariables = AddDebugEnvironmentVariables(environmentVariables); @@ -208,7 +208,7 @@ public void InvokeDotnetTest(string arguments, Dictionary? envir // https://github.com/dotnet/sdk/blob/main/src/Cli/dotnet/commands/dotnet-test/VSTestForwardingApp.cs#L30-L39 debugEnvironmentVariables["VSTEST_CONSOLE_PATH"] = vstestConsolePath; - ExecutePatchedDotnet("test", arguments, out _standardTestOutput, out _standardTestError, out _runnerExitCode, debugEnvironmentVariables); + ExecutePatchedDotnet("test", arguments, out _standardTestOutput, out _standardTestError, out _runnerExitCode, debugEnvironmentVariables, useDotnetFromTools, workingDirectory); FormatStandardOutCome(); } @@ -762,7 +762,7 @@ protected void ExecuteVsTestConsole(string args, out string stdOut, out string s /// /// private void ExecutePatchedDotnet(string command, string args, out string stdOut, out string stdError, out int exitCode, - Dictionary? environmentVariables = null) + Dictionary? environmentVariables = null, bool useDotnetFromTools = false, string? workingDirectory = null) { if (environmentVariables is null) { @@ -772,8 +772,8 @@ private void ExecutePatchedDotnet(string command, string args, out string stdOut environmentVariables["DOTNET_MULTILEVEL_LOOKUP"] = "0"; var executablePath = IsWindows ? @"dotnet\dotnet.exe" : @"dotnet-linux/dotnet"; - var patchedDotnetPath = Path.Combine(_testEnvironment.TestArtifactsDirectory, executablePath); - ExecuteApplication(patchedDotnetPath, string.Join(" ", command, args), out stdOut, out stdError, out exitCode, environmentVariables); + var patchedDotnetPath = Path.Combine(useDotnetFromTools ? _testEnvironment.ToolsDirectory : _testEnvironment.TestArtifactsDirectory, executablePath); + ExecuteApplication(patchedDotnetPath, string.Join(" ", command, args), out stdOut, out stdError, out exitCode, environmentVariables, workingDirectory); } protected static void ExecuteApplication(string path, string args, out string stdOut, out string stdError, out int exitCode, diff --git a/test/TestAssets/ProjectLaunch32BitsProcess/ProjectLaunch32BitsProcess.csproj b/test/TestAssets/ProjectLaunch32BitsProcess/ProjectLaunch32BitsProcess.csproj new file mode 100644 index 0000000000..0e3ae170ab --- /dev/null +++ b/test/TestAssets/ProjectLaunch32BitsProcess/ProjectLaunch32BitsProcess.csproj @@ -0,0 +1,22 @@ + + + + + + + net5.0;net6.0 + enable + Preview + + + + + + + + + + + + + diff --git a/test/TestAssets/ProjectLaunch32BitsProcess/Test32Bit.cs b/test/TestAssets/ProjectLaunch32BitsProcess/Test32Bit.cs new file mode 100644 index 0000000000..e6bcc1bffe --- /dev/null +++ b/test/TestAssets/ProjectLaunch32BitsProcess/Test32Bit.cs @@ -0,0 +1,68 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Diagnostics; + +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace UnitTest; + +[TestClass] +public class Test32Bit +{ + [TestMethod] + public void TheTest() + { + // Test is based on reproducer from following SDK issue: https://github.com/dotnet/sdk/issues/22647 + // We cannot run the test in an automatic/coded way because we need to have .NET 5 and 6 SDKs installed + // which leads to full disk capacity on CI. + // As this change of behavior is quite important we want to make sure we can rerun such manual test + // later on so we are keeping it here. + // Repro steps: + // 1. Build project + // 2. Set $env:DOTNET_ROOT_ENV_VAR_NAME = "DOTNET_ROOT(x86)" + // 3. Set $env:DOTNET_ROOT_ENV_VAR_VALUE to a 32bits dotnet installation directory for the matching TFM + // (e.g. C:\src\vstest\tools\dotnet_x86) + // 4. Add a global.json pinning the .NET version to 5 or 6 + // 5. Run 'dotnet test ./bin///ProjectLaunch32BitsProcess.dll' + // 6. Test should be succesful + // 7. Repeat steps 2 to 5 with $env:DOTNET_ROOT_ENV_VAR_NAME = "DOTNET_ROOT". Although we are running a + // 32 bits process, the dotnet detection logic is set to fallback to this variable. + // 8. Repeat steps 2 to 5 with $env:DOTNET_ROOT_ENV_VAR_NAME = "DOTNET_ROOT_X86". + // This should work for .NET 6 but fail for .NET 5 (if you don't have a global .NET 5 SDK installed), + // as this new variable is not understood by the .NET 5 detection algorithm. + // Debugging tips: + // Use the following environment variables to understand how is .NET being resolved. + // COREHOST_TRACE = 1 + // COREHOST_TRACEFILE = "C:\fxr.tx" + var process = new Process(); + process.StartInfo = new ProcessStartInfo + { + FileName = "TestProcess32.exe", + RedirectStandardError = true, + RedirectStandardOutput = true, + }; + + var envVarName = Environment.GetEnvironmentVariable("DOTNET_ROOT_ENV_VAR_NAME"); + Assert.IsNotNull(envVarName, "Calling process didn't set DOTNET_ROOT_ENV_VAR_NAME."); + var envVarValue = Environment.GetEnvironmentVariable("DOTNET_ROOT_ENV_VAR_VALUE"); + Assert.IsNotNull(envVarValue, "Calling process didn't set DOTNET_ROOT_ENV_VAR_VALUE."); + // Set the DOTNET_ROOT* env variable so that the 32bits process can locate dotnet + // even if there is no global installation. + process.StartInfo.EnvironmentVariables[envVarName] = envVarValue; + process.StartInfo.EnvironmentVariables["DOTNET_ROOT_ENV_VAR_NAME"] = envVarName; + // Ensure multi-level lookup is disabled so that we don't fallback to machine-wide installation + process.StartInfo.EnvironmentVariables["DOTNET_MULTILEVEL_LOOKUP"] = "0"; + + process.Start(); + var stderr = process.StandardError.ReadToEnd(); + var stdout = process.StandardOutput.ReadToEnd(); + + Console.WriteLine($"32bit stdout: {stdout}"); + Console.WriteLine($"32bit err: {stderr}"); + + Assert.IsTrue(string.IsNullOrEmpty(stderr), + $"There was some error in process run: {stderr}"); + } +} diff --git a/test/TestAssets/TestAssets.sln b/test/TestAssets/TestAssets.sln index 8fae3a203e..32b4fcd42a 100644 --- a/test/TestAssets/TestAssets.sln +++ b/test/TestAssets/TestAssets.sln @@ -124,6 +124,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tools", "Tools\Tools.csproj EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Perfy.TestAdapter", "performance\Perfy.TestAdapter\Perfy.TestAdapter.csproj", "{71BF7EC9-7BEE-4038-8F4E-87032FA4E995}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DOTNET_ROOT", "DOTNET_ROOT", "{C06EFF20-F1EA-42B7-B404-D8AB98AA78C0}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestProcess32", "TestProcess32\TestProcess32.csproj", "{4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectLaunch32BitsProcess", "ProjectLaunch32BitsProcess\ProjectLaunch32BitsProcess.csproj", "{A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -806,6 +812,30 @@ Global {71BF7EC9-7BEE-4038-8F4E-87032FA4E995}.Release|x64.Build.0 = Release|Any CPU {71BF7EC9-7BEE-4038-8F4E-87032FA4E995}.Release|x86.ActiveCfg = Release|Any CPU {71BF7EC9-7BEE-4038-8F4E-87032FA4E995}.Release|x86.Build.0 = Release|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Debug|x64.ActiveCfg = Debug|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Debug|x64.Build.0 = Debug|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Debug|x86.ActiveCfg = Debug|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Debug|x86.Build.0 = Debug|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Release|Any CPU.Build.0 = Release|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Release|x64.ActiveCfg = Release|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Release|x64.Build.0 = Release|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Release|x86.ActiveCfg = Release|Any CPU + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506}.Release|x86.Build.0 = Release|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Debug|x64.ActiveCfg = Debug|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Debug|x64.Build.0 = Debug|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Debug|x86.ActiveCfg = Debug|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Debug|x86.Build.0 = Debug|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Release|Any CPU.Build.0 = Release|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Release|x64.ActiveCfg = Release|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Release|x64.Build.0 = Release|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Release|x86.ActiveCfg = Release|Any CPU + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -826,6 +856,8 @@ Global {10AA955C-B412-41A8-899F-8609AAE19F61} = {2633D125-64A7-456C-AD37-F8A6B56C2403} {E166D337-4033-4209-863F-8F77675EAEE8} = {2633D125-64A7-456C-AD37-F8A6B56C2403} {71BF7EC9-7BEE-4038-8F4E-87032FA4E995} = {0C9CA869-32FD-4A9E-8885-E2E19786C746} + {4FA80E2C-B3D4-4A6B-99D2-12F95F2C0506} = {C06EFF20-F1EA-42B7-B404-D8AB98AA78C0} + {A0F37C16-FB73-4538-8DAF-EBF6EB3251FA} = {C06EFF20-F1EA-42B7-B404-D8AB98AA78C0} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D2334DAA-F7B2-450E-ABA4-FBC185152500} diff --git a/test/TestAssets/TestProcess32/Program.cs b/test/TestAssets/TestProcess32/Program.cs new file mode 100644 index 0000000000..107b3f8908 --- /dev/null +++ b/test/TestAssets/TestProcess32/Program.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +using System; + +if (Environment.Is64BitProcess) +{ + throw new InvalidOperationException("Process is supposed to be 32bits."); +} + +var envVarName = Environment.GetEnvironmentVariable("DOTNET_ROOT_ENV_VAR_NAME"); +if (string.IsNullOrEmpty(envVarName)) +{ + throw new InvalidOperationException("Could not find 'DOTNET_ROOT_ENV_VAR_NAME' which is supposed to tell us which DOTNET_ROOTXXX to look up."); +} + +var dotnetRootPath = Environment.GetEnvironmentVariable(envVarName); +if (string.IsNullOrEmpty(dotnetRootPath)) +{ + throw new InvalidOperationException($"{dotnetRootPath} was not set."); +} + +Console.WriteLine("DOTNET_ROOT(x86)={0}", Environment.GetEnvironmentVariable("DOTNET_ROOT(x86)")); +Console.WriteLine("DOTNET_ROOT={0}", Environment.GetEnvironmentVariable("DOTNET_ROOT")); +Console.WriteLine("DOTNET_ROOT_X86={0}", Environment.GetEnvironmentVariable("DOTNET_ROOT_X86")); +Console.WriteLine("DOTNET_ROOT_X64={0}", Environment.GetEnvironmentVariable("DOTNET_ROOT_X64")); + +if (!typeof(object).Assembly.Location.StartsWith(dotnetRootPath, StringComparison.OrdinalIgnoreCase)) +{ + throw new InvalidOperationException($"{typeof(object).Assembly.Location} was not found in {dotnetRootPath}. .NET was not resolved from the correct path."); +} + +Console.WriteLine("Process and DOTNET_ROOT* were correctly set."); diff --git a/test/TestAssets/TestProcess32/TestProcess32.csproj b/test/TestAssets/TestProcess32/TestProcess32.csproj new file mode 100644 index 0000000000..0a5f4d7e1a --- /dev/null +++ b/test/TestAssets/TestProcess32/TestProcess32.csproj @@ -0,0 +1,10 @@ + + + + x86 + Exe + net5.0;net6.0 + enable + + +