From 71753658e643c8fe3e9b96c22e4e2010b8850c74 Mon Sep 17 00:00:00 2001 From: John Beisner Date: Tue, 8 Jan 2019 08:04:10 -0800 Subject: [PATCH] Multilevel lookup includes a custom SDK installation directory (dotnet/core-setup#4857) Multilevel lookup includes a custom SDK installation directory * Avoid duplicate global dirs. * Define: 'RRF_SUBKEY_WOW6432KEY' if not defined. * Adding tests for MultiLevel Lookup and the SDK Self-Registred dirtectory. * Disable self-registered SDK installation directory for win_arm64; win-arm * Adding true multi-level SDK and Runtime look-up; moving non-multi-level SDK version resoution tests. * Multi-level lookup tests are for Windows only; separating and duplicating SharedFX multi-level and non-multi-level lookup tests. Commit migrated from https://github.com/dotnet/core-setup/commit/2f528e5f158aa41789f7967cf8e8b868a8173d95 --- src/installer/corehost/common/pal.windows.cpp | 83 +- .../TestProjects/HostApiInvokerApp/Program.cs | 11 +- .../GivenThatICareAboutMultilevelSDKLookup.cs | 418 ++++---- .../GivenThatICareAboutMultilevelSharedFxLookup.cs | 913 +++-------------- .../GivenThatICareAboutNativeHostApis.cs | 26 +- .../GivenThatICareAboutSDKLookup.cs | 734 ++++++++++++++ .../GivenThatICareAboutSharedFxLookup.cs | 1062 ++++++++++++++++++++ 7 files changed, 2265 insertions(+), 982 deletions(-) create mode 100644 src/installer/test/HostActivationTests/GivenThatICareAboutSDKLookup.cs create mode 100644 src/installer/test/HostActivationTests/GivenThatICareAboutSharedFxLookup.cs diff --git a/src/installer/corehost/common/pal.windows.cpp b/src/installer/corehost/common/pal.windows.cpp index 87623c2..5b79ee2 100644 --- a/src/installer/corehost/common/pal.windows.cpp +++ b/src/installer/corehost/common/pal.windows.cpp @@ -12,6 +12,9 @@ #include #include +#if !defined(RRF_SUBKEY_WOW6432KEY) +#define RRF_SUBKEY_WOW6432KEY 0x00020000 +#endif bool GetModuleFileNameWrapper(HMODULE hModule, pal::string_t* recv) { @@ -197,18 +200,6 @@ bool pal::get_default_servicing_directory(string_t* recv) return true; } -bool pal::get_global_dotnet_dirs(std::vector* dirs) -{ - pal::string_t dir; - if (!get_default_installation_dir(&dir)) - { - return false; - } - - dirs->push_back(dir); - return true; -} - bool pal::get_default_installation_dir(pal::string_t* recv) { pal::char_t* program_files_dir; @@ -227,7 +218,75 @@ bool pal::get_default_installation_dir(pal::string_t* recv) } append_path(recv, _X("dotnet")); + + return true; +} + +bool get_sdk_self_registered_dir(pal::string_t* recv) +{ +#if !defined(_TARGET_AMD64_) && !defined(_TARGET_X86_) + // Self-registered SDK installation directory is only supported for x64 and x86 architectures. + return false; +#else + recv->clear(); + + // ***Used only for testing*** + pal::string_t environmentOverride; + if (pal::getenv(_X("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR"), &environmentOverride)) + { + recv->assign(environmentOverride); + return true; + } + // *************************** + + DWORD size = 0; + const HKEY hkey = HKEY_LOCAL_MACHINE; + // The registry search occurs in the 32-bit registry in all cases. + const DWORD flags = RRF_RT_REG_SZ | RRF_SUBKEY_WOW6432KEY; + pal::string_t sub_key = pal::string_t(_X("SOFTWARE\\dotnet\\Setup\\InstalledVersions\\")) + get_arch() + pal::string_t(_X("\\sdk")); + pal::char_t* value = _X("InstallLocation"); + + // Determine the size of the buffer + LONG result = ::RegGetValueW(hkey, sub_key.c_str(), value, flags, nullptr, nullptr, &size); + if (result != ERROR_SUCCESS || size == 0) + { + return false; + } + + // Get the key's value + std::vector buffer(size/sizeof(pal::char_t)); + result = ::RegGetValueW(hkey, sub_key.c_str(), value, flags, nullptr, &buffer[0], &size); + if (result != ERROR_SUCCESS) + { + return false; + } + + recv->assign(buffer.data()); + return true; +#endif +} + +bool pal::get_global_dotnet_dirs(std::vector* dirs) +{ + pal::string_t default_dir; + pal::string_t custom_dir; + bool dir_found = false; + if (get_sdk_self_registered_dir(&custom_dir)) + { + dirs->push_back(custom_dir); + dir_found = true; + } + if (get_default_installation_dir(&default_dir)) + { + // Avoid duplicate global dirs. + if (!dir_found || !are_paths_equal_with_normalized_casing(custom_dir, default_dir)) + { + dirs->push_back(default_dir); + dir_found = true; + } + } + return dir_found; } // To determine the OS version, we are going to use RtlGetVersion API diff --git a/src/installer/test/Assets/TestProjects/HostApiInvokerApp/Program.cs b/src/installer/test/Assets/TestProjects/HostApiInvokerApp/Program.cs index d3d6189..332febc 100644 --- a/src/installer/test/Assets/TestProjects/HostApiInvokerApp/Program.cs +++ b/src/installer/test/Assets/TestProjects/HostApiInvokerApp/Program.cs @@ -34,14 +34,17 @@ namespace HostApiInvokerApp // Enable tracing so that test assertion failures are easier to diagnose. Environment.SetEnvironmentVariable("COREHOST_TRACE", "1"); - // If requested, test multilevel lookup using fake ProgramFiles location. + // If requested, test multilevel lookup using fake Global SDK directories: + // 1. using a fake ProgramFiles location + // 2. using a fake SDK Self-Registered location // Note that this has to be set here and not in the calling test process because // %ProgramFiles% gets reset on process creation. - string testMultilevelLookupProgramFiles = Environment.GetEnvironmentVariable( - "TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES"); + string testMultilevelLookupProgramFiles = Environment.GetEnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES"); + string testMultilevelLookupSelfRegistered = Environment.GetEnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED"); - if (testMultilevelLookupProgramFiles != null) + if (testMultilevelLookupProgramFiles != null && testMultilevelLookupSelfRegistered != null) { + Environment.SetEnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", testMultilevelLookupSelfRegistered); Environment.SetEnvironmentVariable("ProgramFiles", testMultilevelLookupProgramFiles); Environment.SetEnvironmentVariable("ProgramFiles(x86)", testMultilevelLookupProgramFiles); Environment.SetEnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1"); diff --git a/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSDKLookup.cs b/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSDKLookup.cs index aae62ba..3d30e22 100644 --- a/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSDKLookup.cs +++ b/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSDKLookup.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using Microsoft.DotNet.InternalAbstractions; using Xunit; @@ -22,13 +23,16 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup private string _currentWorkingDir; private string _userDir; - private string _executableDir; + private string _exeDir; + private string _regDir; private string _cwdSdkBaseDir; private string _userSdkBaseDir; private string _exeSdkBaseDir; + private string _regSdkBaseDir; private string _cwdSelectedMessage; private string _userSelectedMessage; private string _exeSelectedMessage; + private string _regSelectedMessage; private string _sdkDir; private string _multilevelDir; @@ -51,23 +55,26 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup _currentWorkingDir = Path.Combine(_multilevelDir, "cwd"); _userDir = Path.Combine(_multilevelDir, "user"); - _executableDir = Path.Combine(_multilevelDir, "exe"); + _exeDir = Path.Combine(_multilevelDir, "exe"); + _regDir = Path.Combine(_multilevelDir, "reg"); // It's necessary to copy the entire publish folder to the exe dir because // we'll need to build from it. The CopyDirectory method automatically creates the dest dir - SharedFramework.CopyDirectory(builtDotnet, _executableDir); + SharedFramework.CopyDirectory(builtDotnet, _exeDir); - RepoDirectories = new RepoDirectoriesProvider(builtDotnet: _executableDir); + RepoDirectories = new RepoDirectoriesProvider(builtDotnet: _exeDir); // SdkBaseDirs contain all available version folders _cwdSdkBaseDir = Path.Combine(_currentWorkingDir, "sdk"); _userSdkBaseDir = Path.Combine(_userDir, ".dotnet", RepoDirectories.BuildArchitecture, "sdk"); - _exeSdkBaseDir = Path.Combine(_executableDir, "sdk"); + _exeSdkBaseDir = Path.Combine(_exeDir, "sdk"); + _regSdkBaseDir = Path.Combine(_regDir, "sdk"); // Create directories Directory.CreateDirectory(_cwdSdkBaseDir); Directory.CreateDirectory(_userSdkBaseDir); Directory.CreateDirectory(_exeSdkBaseDir); + Directory.CreateDirectory(_regSdkBaseDir); // Restore and build PortableApp from exe dir PreviouslyBuiltAndRestoredPortableTestProjectFixture = new TestProjectFixture("PortableApp", RepoDirectories) @@ -77,7 +84,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup // Set a dummy framework version (9999.0.0) in the exe sharedFx location. We will // always pick the framework from this to avoid interference with the sharedFxLookup - string exeDirDummyFxVersion = Path.Combine(_executableDir, "shared", "Microsoft.NETCore.App", "9999.0.0"); + string exeDirDummyFxVersion = Path.Combine(_exeDir, "shared", "Microsoft.NETCore.App", "9999.0.0"); string builtSharedFxDir = fixture.BuiltDotnet.GreatestVersionSharedFxPath; SharedFramework.CopyDirectory(builtSharedFxDir, exeDirDummyFxVersion); @@ -99,6 +106,7 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup _cwdSelectedMessage = $"Using dotnet SDK dll=[{_cwdSdkBaseDir}"; _userSelectedMessage = $"Using dotnet SDK dll=[{_userSdkBaseDir}"; _exeSelectedMessage = $"Using dotnet SDK dll=[{_exeSdkBaseDir}"; + _regSelectedMessage = $"Using dotnet SDK dll=[{_regSdkBaseDir}"; } public void Dispose() @@ -112,97 +120,103 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup } [Fact] - public void SdkLookup_Global_Json_Single_Digit_Patch_Rollup() + public void SdkMultilevelLookup_Global_Json_Single_Digit_Patch_Rollup() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Multi-level lookup is only supported on Windows. + return; + } + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture .Copy(); var dotnet = fixture.BuiltDotnet; - // Set specified CLI version = 9999.3.4-global-dummy + // Set specified SDK version = 9999.3.4-global-dummy SetGlobalJsonVersion("SingleDigit-global.json"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty // Exe: empty + // Reg: empty // Expected: no compatible version and a specific error messages dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) .Should() .Fail() .And - .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") - .And - .HaveStdErrContaining("It was not possible to find any installed dotnet SDKs") - .And - .NotHaveStdErrContaining("Checking if resolved SDK dir"); + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version"); - // Add some dummy versions + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.4.1", "9999.3.4-dummy"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty // Exe: 9999.4.1, 9999.3.4-dummy + // Reg: empty // Expected: no compatible version and a specific error message dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) .Should() .Fail() .And - .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") - .And - .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version"); - // Add specified CLI version - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.3"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.3.3"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3 + // Exe: 9999.4.1, 9999.3.4-dummy + // Reg: 9999.3.3 // Expected: no compatible version and a specific error message dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) .Should() .Fail() .And - .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") - .And - .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version"); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.4"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4 + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.4 + // Reg: 9999.3.3 // Expected: 9999.3.4 from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -211,61 +225,67 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.4", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.5-dummy"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.3.5-dummy"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4, 9999.3.5-dummy - // Expected: 9999.3.5-dummy from exe dir + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.4 + // Reg: 9999.3.3, 9999.3.5-dummy + // Expected: 9999.3.5-dummy from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.5-dummy", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.3.5-dummy", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.600"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4, 9999.3.5-dummy, 9999.3.600 - // Expected: 9999.3.5-dummy from exe dir + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.4, 9999.3.600 + // Reg: 9999.3.3, 9999.3.5-dummy + // Expected: 9999.3.5-dummy from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.5-dummy", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.3.5-dummy", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.4-global-dummy"); - // Specified CLI version: 9999.3.4-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.4-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4, 9999.3.5-dummy, 9999.3.600, 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.4, 9999.3.600, 9999.3.4-global-dummy + // Reg: 9999.3.3, 9999.3.5-dummy // Expected: 9999.3.4-global-dummy from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -274,11 +294,13 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.4-global-dummy", _dotnetSdkDllMessageTerminator)); - // Verify we have the expected sdk versions + // Verify we have the expected SDK versions dotnet.Exec("--list-sdks") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .Execute() .Should() @@ -300,116 +322,126 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup } [Fact] - public void SdkLookup_Global_Json_Two_Part_Patch_Rollup() + public void SdkMultilevelLookup_Global_Json_Two_Part_Patch_Rollup() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Multi-level lookup is only supported on Windows. + return; + } + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture .Copy(); var dotnet = fixture.BuiltDotnet; - // Set specified CLI version = 9999.3.304-global-dummy + // Set specified SDK version = 9999.3.304-global-dummy SetGlobalJsonVersion("TwoPart-global.json"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty // Exe: empty + // Reg: empty // Expected: no compatible version and a specific error messages dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) .Should() .Fail() .And - .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") - .And - .HaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version"); - // Add some dummy versions - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.57", "9999.3.4-dummy"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.3.57", "9999.3.4-dummy"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.3.57, 9999.3.4-dummy + // Exe: empty + // Reg: 9999.3.57, 9999.3.4-dummy // Expected: no compatible version and a specific error message dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) .Should() .Fail() .And - .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") - .And - .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version"); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.300", "9999.7.304-global-dummy"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy + // Exe: 9999.3.300, 9999.7.304-global-dummy + // Reg: 9999.3.57, 9999.3.4-dummy // Expected: no compatible version and a specific error message dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) .Should() .Fail() .And - .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") - .And - .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version"); - // Add specified CLI version - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.304"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.3.304"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty - // Exe: 99999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304 - // Expected: 9999.3.304 from exe dir + // Exe: 9999.3.300, 9999.7.304-global-dummy + // Reg: 9999.3.57, 9999.3.4-dummy, 9999.3.304 + // Expected: 9999.3.304 from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.304", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.3.304", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.399", "9999.3.399-dummy", "9999.3.400"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304, 9999.3.399, 9999.3.399-dummy, 9999.3.400 + // Exe: 9999.3.300, 9999.7.304-global-dummy, 9999.3.399, 9999.3.399-dummy, 9999.3.400 + // Reg: 9999.3.57, 9999.3.4-dummy, 9999.3.304 // Expected: 9999.3.399 from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -418,19 +450,22 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.399", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.2400, 9999.3.3004"); + AddAvailableSdkVersions(_regSdkBaseDir, "9999.3.2400, 9999.3.3004"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304, 9999.3.399, 9999.3.399-dummy, 9999.3.400, 9999.3.2400, 9999.3.3004 + // Exe: 9999.3.300, 9999.7.304-global-dummy, 9999.3.399, 9999.3.399-dummy, 9999.3.400, 9999.3.2400, 9999.3.3004 + // Reg: 9999.3.57, 9999.3.4-dummy, 9999.3.304, 9999.3.2400, 9999.3.3004 // Expected: 9999.3.399 from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -439,32 +474,36 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.399", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.304-global-dummy"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.3.304-global-dummy"); - // Specified CLI version: 9999.3.304-global-dummy - // CWD: empty + // Specified SDK version: 9999.3.304-global-dummy + // Cwd: empty // User: empty - // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304, 9999.3.399, 9999.3.399-dummy, 9999.3.400, 9999.3.2400, 9999.3.3004, 9999.3.304-global-dummy - // Expected: 9999.3.304-global-dummy from exe dir + // Exe: 9999.3.300, 9999.7.304-global-dummy, 9999.3.399, 9999.3.399-dummy, 9999.3.400, 9999.3.2400, 9999.3.3004 + // Reg: 9999.3.57, 9999.3.4-dummy, 9999.3.304, 9999.3.2400, 9999.3.3004, 9999.3.304-global-dummy + // Expected: 9999.3.304-global-dummy from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.304-global-dummy", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.3.304-global-dummy", _dotnetSdkDllMessageTerminator)); - // Verify we have the expected sdk versions + // Verify we have the expected SDK versions dotnet.Exec("--list-sdks") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .Execute() .Should() @@ -494,49 +533,57 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup } [Fact] - public void SdkLookup_Negative_Version() + public void SdkMultilevelLookup_Precedential_Order() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Multi-level lookup is only supported on Windows. + return; + } + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture .Copy(); var dotnet = fixture.BuiltDotnet; - // Add a negative CLI version - AddAvailableSdkVersions(_exeSdkBaseDir, "-1.-1.-1"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.0.4"); - // Specified CLI version: none - // CWD: empty + // Specified SDK version: none + // Cwd: empty // User: empty - // Exe: -1.-1.-1 - // Expected: no compatible version and a specific error messages + // Exe: empty + // Reg: 9999.0.4 + // Expected: 9999.0.4 from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() - .Execute(fExpectedToFail: true) + .Execute() .Should() - .Fail() - .And - .HaveStdErrContaining("It was not possible to find any installed dotnet SDKs") + .Pass() .And - .HaveStdErrContaining("Did you mean to run dotnet SDK commands? Please install dotnet SDK from"); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.4", _dotnetSdkDllMessageTerminator)); - // Add specified CLI version + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.4"); - // Specified CLI version: none - // CWD: empty + // Specified SDK version: none + // Cwd: empty // User: empty - // Exe: -1.-1.-1, 9999.0.4 + // Exe: 9999.0.4 + // Reg: 9999.0.4 // Expected: 9999.0.4 from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -544,61 +591,60 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .Pass() .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.4", _dotnetSdkDllMessageTerminator)); - - // Verify we have the expected sdk versions - dotnet.Exec("--list-sdks") - .WorkingDirectory(_currentWorkingDir) - .WithUserProfile(_userDir) - .Environment(s_DefaultEnvironment) - .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("9999.0.4"); } - + [Fact] - public void SdkLookup_Must_Pick_The_Highest_Semantic_Version() + public void SdkMultilevelLookup_Must_Pick_The_Highest_Semantic_Version() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Multi-level lookup is only supported on Windows. + return; + } + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture .Copy(); var dotnet = fixture.BuiltDotnet; - // Add dummy versions in the exe dir - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.0", "9999.0.3-dummy"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.0.0", "9999.0.3-dummy"); - // Specified CLI version: none - // CWD: empty + // Specified SDK version: none + // Cwd: empty // User: empty - // Exe: 9999.0.0, 9999.0.3-dummy - // Expected: 9999.0.3-dummy from exe dir + // Exe: empty + // Reg: 9999.0.0, 9999.0.3-dummy + // Expected: 9999.0.3-dummy from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.3-dummy", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.3-dummy", _dotnetSdkDllMessageTerminator)); - // Add dummy versions in the exe dir + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.3"); - // Specified CLI version: none - // CWD: empty + // Specified SDK version: none + // Cwd: empty // User: empty - // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3 + // Exe: 9999.0.3 + // Reg: 9999.0.0, 9999.0.3-dummy // Expected: 9999.0.3 from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -607,60 +653,69 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.3", _dotnetSdkDllMessageTerminator)); - // Add dummy versions + // Add SDK versions AddAvailableSdkVersions(_userSdkBaseDir, "9999.0.200"); AddAvailableSdkVersions(_cwdSdkBaseDir, "10000.0.0"); - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.100"); + AddAvailableSdkVersions(_regSdkBaseDir, "9999.0.100"); - // Specified CLI version: none - // CWD: 10000.0.0 --> should not be picked + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked // User: 9999.0.200 --> should not be picked - // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100 - // Expected: 9999.0.100 from exe dir + // Exe: 9999.0.3 + // Reg: 9999.0.0, 9999.0.3-dummy, 9999.0.100 + // Expected: 9999.0.100 from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.100", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.100", _dotnetSdkDllMessageTerminator)); - // Add a dummy version in the exe dir + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.80"); - // Specified CLI version: none - // CWD: 10000.0.0 --> should not be picked + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked // User: 9999.0.200 --> should not be picked - // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100, 9999.0.80 - // Expected: 9999.0.100 from exe dir + // Exe: 9999.0.3, 9999.0.80 + // Reg: 9999.0.0, 9999.0.3-dummy, 9999.0.100 + // Expected: 9999.0.100 from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.100", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.100", _dotnetSdkDllMessageTerminator)); - // Add a dummy version in the user dir + // Add SDK versions AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.5500000"); - // Specified CLI version: none - // CWD: 10000.0.0 --> should not be picked + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked // User: 9999.0.200 --> should not be picked - // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100, 9999.0.80, 9999.0.5500000 + // Exe: 9999.0.3, 9999.0.80, 9999.0.5500000 + // Reg: 9999.0.0, 9999.0.3-dummy, 9999.0.100 // Expected: 9999.0.5500000 from exe dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -669,31 +724,36 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSDKLookup .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.5500000", _dotnetSdkDllMessageTerminator)); - // Add a dummy version in the user dir - AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.52000000"); + // Add SDK versions + AddAvailableSdkVersions(_regSdkBaseDir, "9999.0.52000000"); - // Specified CLI version: none - // CWD: 10000.0.0 --> should not be picked + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked // User: 9999.0.200 --> should not be picked - // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100, 9999.0.80, 9999.0.5500000, 9999.0.52000000 - // Expected: 9999.0.52000000 from exe dir + // Exe: 9999.0.3, 9999.0.80, 9999.0.5500000 + // Reg: 9999.0.0, 9999.0.3-dummy, 9999.0.100, 9999.0.52000000 + // Expected: 9999.0.52000000 from reg dir dotnet.Exec("help") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.52000000", _dotnetSdkDllMessageTerminator)); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.52000000", _dotnetSdkDllMessageTerminator)); - // Verify we have the expected sdk versions + // Verify we have the expected SDK versions dotnet.Exec("--list-sdks") .WorkingDirectory(_currentWorkingDir) .WithUserProfile(_userDir) .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .Execute() .Should() diff --git a/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSharedFxLookup.cs b/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSharedFxLookup.cs index 919acf1..6bbe939 100644 --- a/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSharedFxLookup.cs +++ b/src/installer/test/HostActivationTests/GivenThatICareAboutMultilevelSharedFxLookup.cs @@ -3,6 +3,7 @@ using Microsoft.DotNet.Cli.Build.Framework; using Newtonsoft.Json.Linq; using System; using System.IO; +using System.Runtime.InteropServices; using Xunit; namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLookup @@ -17,28 +18,28 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku private string _currentWorkingDir; private string _userDir; - private string _executableDir; - private string _globalDir; + private string _exeDir; + private string _regDir; private string _cwdSharedFxBaseDir; private string _cwdSharedUberFxBaseDir; private string _userSharedFxBaseDir; private string _userSharedUberFxBaseDir; private string _exeSharedFxBaseDir; private string _exeSharedUberFxBaseDir; - private string _globalSharedFxBaseDir; - private string _globalSharedUberFxBaseDir; + private string _regSharedFxBaseDir; + private string _regSharedUberFxBaseDir; private string _builtSharedFxDir; private string _builtSharedUberFxDir; private string _cwdSelectedMessage; private string _userSelectedMessage; private string _exeSelectedMessage; - private string _globalSelectedMessage; + private string _regSelectedMessage; private string _cwdFoundUberFxMessage; private string _userFoundUberFxMessage; private string _exeFoundUberFxMessage; - private string _globalFoundUberFxMessage; + private string _regFoundUberFxMessage; private string _sharedFxVersion; private string _multilevelDir; @@ -62,34 +63,34 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku // be used during tests _currentWorkingDir = Path.Combine(_multilevelDir, "cwd"); _userDir = Path.Combine(_multilevelDir, "user"); - _executableDir = Path.Combine(_multilevelDir, "exe"); - _globalDir = Path.Combine(_multilevelDir, "global"); + _exeDir = Path.Combine(_multilevelDir, "exe"); + _regDir = Path.Combine(_multilevelDir, "reg"); - RepoDirectories = new RepoDirectoriesProvider(builtDotnet: _executableDir); + RepoDirectories = new RepoDirectoriesProvider(builtDotnet: _exeDir); // SharedFxBaseDirs contain all available version folders _cwdSharedFxBaseDir = Path.Combine(_currentWorkingDir, "shared", "Microsoft.NETCore.App"); _userSharedFxBaseDir = Path.Combine(_userDir, ".dotnet", RepoDirectories.BuildArchitecture, "shared", "Microsoft.NETCore.App"); - _exeSharedFxBaseDir = Path.Combine(_executableDir, "shared", "Microsoft.NETCore.App"); - _globalSharedFxBaseDir = Path.Combine(_globalDir, "shared", "Microsoft.NETCore.App"); + _exeSharedFxBaseDir = Path.Combine(_exeDir, "shared", "Microsoft.NETCore.App"); + _regSharedFxBaseDir = Path.Combine(_regDir, "shared", "Microsoft.NETCore.App"); _cwdSharedUberFxBaseDir = Path.Combine(_currentWorkingDir, "shared", "Microsoft.UberFramework"); _userSharedUberFxBaseDir = Path.Combine(_userDir, ".dotnet", RepoDirectories.BuildArchitecture, "shared", "Microsoft.UberFramework"); - _exeSharedUberFxBaseDir = Path.Combine(_executableDir, "shared", "Microsoft.UberFramework"); - _globalSharedUberFxBaseDir = Path.Combine(_globalDir, "shared", "Microsoft.UberFramework"); + _exeSharedUberFxBaseDir = Path.Combine(_exeDir, "shared", "Microsoft.UberFramework"); + _regSharedUberFxBaseDir = Path.Combine(_regDir, "shared", "Microsoft.UberFramework"); // Create directories. It's necessary to copy the entire publish folder to the exe dir because // we'll need to build from it. The CopyDirectory method automatically creates the dest dir Directory.CreateDirectory(_cwdSharedFxBaseDir); Directory.CreateDirectory(_userSharedFxBaseDir); - Directory.CreateDirectory(_globalSharedFxBaseDir); + Directory.CreateDirectory(_regSharedFxBaseDir); Directory.CreateDirectory(_cwdSharedUberFxBaseDir); Directory.CreateDirectory(_userSharedUberFxBaseDir); - Directory.CreateDirectory(_globalSharedUberFxBaseDir); - SharedFramework.CopyDirectory(_builtDotnet, _executableDir); + Directory.CreateDirectory(_regSharedUberFxBaseDir); + SharedFramework.CopyDirectory(_builtDotnet, _exeDir); - //Copy dotnet to global directory - File.Copy(Path.Combine(_builtDotnet, $"dotnet{Constants.ExeSuffix}"), Path.Combine(_globalDir, $"dotnet{Constants.ExeSuffix}"), true); + //Copy dotnet to self-registered directory + File.Copy(Path.Combine(_builtDotnet, $"dotnet{Constants.ExeSuffix}"), Path.Combine(_regDir, $"dotnet{Constants.ExeSuffix}"), true); // Restore and build SharedFxLookupPortableApp from exe dir PreviouslyBuiltAndRestoredPortableTestProjectFixture = new TestProjectFixture("SharedFxLookupPortableApp", RepoDirectories) @@ -110,12 +111,12 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku _cwdSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_cwdSharedFxBaseDir}"; _userSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_userSharedFxBaseDir}"; _exeSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_exeSharedFxBaseDir}"; - _globalSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_globalSharedFxBaseDir}"; + _regSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_regSharedFxBaseDir}"; _cwdFoundUberFxMessage = $"Chose FX version [{_cwdSharedUberFxBaseDir}"; _userFoundUberFxMessage = $"Chose FX version [{_userSharedUberFxBaseDir}"; _exeFoundUberFxMessage = $"Chose FX version [{_exeSharedUberFxBaseDir}"; - _globalFoundUberFxMessage = $"Chose FX version [{_globalSharedUberFxBaseDir}"; + _regFoundUberFxMessage = $"Chose FX version [{_regSharedUberFxBaseDir}"; } public void Dispose() @@ -129,8 +130,14 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku } [Fact] - public void SharedFxLookup_Must_Verify_Folders_in_the_Correct_Order() + public void SharedMultilevelFxLookup_Must_Verify_Folders_in_the_Correct_Order() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Multi-level lookup is only supported on Windows. + return; + } + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture .Copy(); @@ -141,95 +148,90 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); - // Add version in the exe dir - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0"); + // Add version in the reg dir + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _regSharedFxBaseDir, "9999.0.0"); // Version: 9999.0.0 + // Cwd: empty // User: empty - // Exe: 9999.0.0 - // Expected: 9999.0.0 from exe dir + // Exe: empty + // Reg: 9999.0.0 + // Expected: 9999.0.0 from reg dir dotnet.Exec(appDll) .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") .WithUserProfile(_userDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(_exeSelectedMessage); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.0")); // Add a dummy version in the user dir SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _userSharedFxBaseDir, "9999.0.0"); // Version: 9999.0.0 + // Cwd: empty // User: 9999.0.0 --> should not be picked - // Exe: 9999.0.0 - // Expected: 9999.0.0 from user dir + // Exe: empty + // Reg: 9999.0.0 + // Expected: 9999.0.0 from reg dir dotnet.Exec(appDll) .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") .WithUserProfile(_userDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(_exeSelectedMessage); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.0")); - // Add a dummy version in the cwd + // Add a dummy version in the cwd dir SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _cwdSharedFxBaseDir, "9999.0.0"); // Version: 9999.0.0 - // CWD: 9999.0.0 --> should not be picked - // User: 9999.0.0 - // Exe: 9999.0.0 - // Expected: 9999.0.0 from user Exe + // Cwd: 9999.0.0 --> should not be picked + // User: 9999.0.0 --> should not be picked + // Exe: empty + // Reg: 9999.0.0 + // Expected: 9999.0.0 from reg dir dotnet.Exec(appDll) .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") .WithUserProfile(_userDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(_exeSelectedMessage); - - // Verify we have the expected runtime versions - dotnet.Exec("--list-runtimes") - .WorkingDirectory(_currentWorkingDir) - .WithUserProfile(_userDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0"); - } - - [Fact] - public void SharedFxLookup_Must_Not_Roll_Forward_If_Framework_Version_Is_Specified_Through_Argument() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.0")); - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - // Add some dummy versions - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0", "9999.0.2", "9999.0.0-dummy2", "9999.0.3", "9999.0.0-dummy3"); + // Add version in the exe dir + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0"); - // Version: 9999.0.0 (through --fx-version arg) - // Exe: 9999.0.2, 9999.0.0-dummy2, 9999.0.0, 9999.0.3, 9999.0.0-dummy3 - // global: empty + // Version: 9999.0.0 + // Cwd: 9999.0.0 --> should not be picked + // User: 9999.0.0 --> should not be picked + // Exe: 9999.0.0 + // Reg: 9999.0.0 // Expected: 9999.0.0 from exe dir - dotnet.Exec("--fx-version", "9999.0.0", appDll) + dotnet.Exec(appDll) .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() @@ -238,167 +240,73 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku .And .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0")); - // Version: 9999.0.0-dummy1 (through --fx-version arg) - // Exe: 9999.0.2, 9999.0.0-dummy2,9999.0.0, 9999.0.3, 9999.0.0-dummy3 - // global: empty - // Expected: no compatible version - dotnet.Exec("--fx-version", "9999.0.0-dummy1", appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("It was not possible to find any compatible framework version"); - // Verify we have the expected runtime versions dotnet.Exec("--list-runtimes") .WorkingDirectory(_currentWorkingDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0-dummy2") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.2") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.3") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0-dummy3"); - } - - [Fact] - public void Roll_Forward_On_No_Candidate_Fx_Must_Happen_If_Compatible_Patch_Version_Is_Not_Available() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - // Set desired version = 9999.0.0 - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); - - // Add some dummy versions in the exe - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "10000.1.1", "10000.1.3"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' enabled with value 2 (major+minor) through env var - // exe: 10000.1.1, 10000.1.3 - // Expected: 10000.1.3 from exe - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "2") - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "10000.1.3")); - - // Add a dummy version in the exe dir - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' enabled with value 2 (major+minor) through env var - // exe: 9999.1.1, 10000.1.1, 10000.1.3 - // Expected: 9999.1.1 from exe - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "2") + .WithUserProfile(_userDir) .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.1.1")) - .And - .HaveStdOutContaining("Framework Version:9999.1.1"); - - // Verify we have the expected runtime versions - dotnet.Exec("--list-runtimes") - .WorkingDirectory(_currentWorkingDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 10000.1.1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 10000.1.3"); + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0"); } [Fact] - public void Roll_Forward_On_No_Candidate_Fx_Minor_And_Disabled() + public void SharedMultilevelFxLookup_Must_Not_Roll_Forward_If_Framework_Version_Is_Specified_Through_Argument() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + // Multi-level lookup is only supported on Windows. + return; + } + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture .Copy(); var dotnet = fixture.BuiltDotnet; var appDll = fixture.TestProject.AppDll; - // Set desired version = 9999.0.0 - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); - - // Add some dummy versions in the exe - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "10000.1.1"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' default value of 1 (minor) - // exe: 10000.1.1 - // Expected: fail with no framework - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("It was not possible to find any compatible framework version"); - - // Add a dummy version in the exe dir - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1"); + // Add some dummy versions + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0", "9999.0.1", "9999.0.0-dummy2", "9999.0.4"); + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _regSharedFxBaseDir, "9999.0.0", "9999.0.2", "9999.0.3", "9999.0.0-dummy3"); - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' default value of 1 (minor) - // exe: 9999.1.1, 10000.1.1 - // Expected: 9999.1.1 from exe - dotnet.Exec(appDll) + // Version: 9999.0.0 (through --fx-version arg) + // Cwd: empty + // User: empty + // Exe: 9999.0.0, 9999.0.1, 9999.0.4, 9999.0.0-dummy2 + // Reg: 9999.0.0, 9999.0.2, 9999.0.3, 9999.0.0-dummy3 + // Expected: 9999.0.1 from exe dir + dotnet.Exec("--fx-version", "9999.0.1", appDll) .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.1.1")) - .And - .HaveStdOutContaining("Framework Version:9999.1.1"); + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.1")); - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' disabled through env var - // exe: 9999.1.1, 10000.1.1 - // Expected: fail with no framework - dotnet.Exec(appDll) + // Version: 9999.0.0-dummy1 (through --fx-version arg) + // Cwd: empty + // User: empty + // Exe: 9999.0.0, 9999.0.1, 9999.0.4, 9999.0.0-dummy2 + // Reg: 9999.0.0, 9999.0.2, 9999.0.3, 9999.0.0-dummy3 + // Expected: no compatible version + dotnet.Exec("--fx-version", "9999.0.0-dummy1", appDll) .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) .EnvironmentVariable("COREHOST_TRACE", "1") - .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "0") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute(fExpectedToFail: true) @@ -407,621 +315,68 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.MultilevelSharedFxLooku .And .HaveStdErrContaining("It was not possible to find any compatible framework version"); - // Verify we have the expected runtime versions - dotnet.Exec("--list-runtimes") - .WorkingDirectory(_currentWorkingDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 10000.1.1"); - } - - [Fact] - public void Roll_Forward_On_No_Candidate_Fx_Production_To_Preview() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - // Set desired version = 9999.0.0 - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); - - // Add preview version in the exe - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1-dummy1"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' default value of 1 (minor) - // exe: 9999.1.1-dummy1 - // Expected: 9999.1.1-dummy1 since there is no production version - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.1.1-dummy1")); - - // Add a production version with higher value - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.2.1"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' default value of 1 (minor) - // exe: 9999.1.1-dummy1, 9999.2.1 - // Expected: 9999.2.1 since we favor production over preview - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.2.1")); - - // Add a preview version with same major.minor as production - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.2.1-dummy1"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' default value of 1 (minor) - // exe: 9999.1.1-dummy1, 9999.2.1, 9999.2.1-dummy1 - // Expected: 9999.2.1 since we favor production over preview - dotnet.Exec(appDll) + // Version: 9999.0.0 (through --fx-version arg) + // Cwd: empty + // User: empty + // Exe: 9999.0.0, 9999.0.1, 9999.0.4, 9999.0.0-dummy2 + // Reg: 9999.0.0, 9999.0.2, 9999.0.3, 9999.0.0-dummy3 + // Expected: 9999.0.2 from reg dir + dotnet.Exec("--fx-version", "9999.0.2", appDll) .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.2.1")); + .HaveStdErrContaining(Path.Combine(_regSelectedMessage, "9999.0.2")); - // Add a preview version with same major.minor as production but higher patch version - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.2.2-dummy1"); - - // Version: 9999.0.0 - // 'Roll forward on no candidate fx' default value of 1 (minor) - // exe: 9999.1.1-dummy1, 9999.2.1, 9999.2.1-dummy1, 9999.2.2-dummy1 - // Expected: 9999.2.1 since we favor production over preview - dotnet.Exec(appDll) + // Version: 9999.0.0 (through --fx-version arg) + // Cwd: empty + // User: empty + // Exe: 9999.0.0, 9999.0.1, 9999.0.4, 9999.0.0-dummy2 + // Reg: 9999.0.0, 9999.0.2, 9999.0.3, 9999.0.0-dummy3 + // Expected: 9999.0.0 from exe dir + dotnet.Exec("--fx-version", "9999.0.0", appDll) .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.2.1")); + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0")); // Verify we have the expected runtime versions dotnet.Exec("--list-runtimes") .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "1") + .EnvironmentVariable("_DOTNET_TEST_SDK_SELF_REGISTERED_DIR", _regDir) .CaptureStdOut() + .CaptureStdErr() .Execute() .Should() .Pass() .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.1-dummy1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.2.1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.2.1-dummy1") + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.2.2-dummy1"); - } - - [Fact] - public void Roll_Forward_On_No_Candidate_Fx_Preview_To_Production() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - // Set desired version = 9999.0.0-dummy1 - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0-dummy1"); - - // Add dummy versions in the exe - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0", "9999.0.1-dummy1"); - - // Version: 9999.0.0-dummy1 - // exe: 9999.0.0, 9999.0.1-dummy1 - // Expected: fail since we don't roll forward unless match on major.minor.patch and never roll forward to production - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0-dummy2") .And - .HaveStdErrContaining("It was not possible to find any compatible framework version"); - - // Add preview versions in the exe with name major.minor.patch - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0-dummy2", "9999.0.0-dummy3"); - - // Version: 9999.0.0-dummy1 - // exe: 9999.0.0-dummy2, 9999.0.0-dummy3, 9999.0.0, 9999.0.1-dummy1 - // Expected: 9999.0.0-dummy2 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.2") .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0-dummy2")) + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.3") .And - .HaveStdOutContaining("Framework Version:9999.0.0-dummy2"); - - // Verify we have the expected runtime versions - dotnet.Exec("--list-runtimes") - .WorkingDirectory(_currentWorkingDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("9999.0.0-dummy2") - .And - .HaveStdOutContaining("9999.0.0-dummy3") - .And - .HaveStdOutContaining("9999.0.0") - .And - .HaveStdOutContaining("9999.0.1-dummy1"); - } - - [Fact] - public void Roll_Forward_On_No_Candidate_Fx_Fails_If_No_Higher_Version_Is_Available() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - // Set desired version = 9999.1.1 - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.1.1"); - - // Add some dummy versions in the exe - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9998.0.1", "9998.1.0", "9999.0.0", "9999.0.1", "9999.1.0"); - - // Version: 9999.1.1 - // exe: 9998.0.1, 9998.1.0, 9999.0.0, 9999.0.1, 9999.1.0 - // Expected: no compatible version - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("It was not possible to find any compatible framework version"); - - // Verify we have the expected runtime versions - dotnet.Exec("--list-runtimes") - .WorkingDirectory(_currentWorkingDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9998.0.1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9998.1.0") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.1") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.0"); - } - - [Fact] - public void Multiple_SharedFxLookup_Independent_Roll_Forward() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); - - // Version: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // Exe: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // Expected: 9999.0.0 - // 7777.0.0 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0")) - .And - .HaveStdOutContaining("Framework Version:9999.0.0") - .And - .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.0")); - - // Add a newer version to verify roll-forward - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.1"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.1"); - - // Version: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // Exe: NetCoreApp 9999.0.0, 9999.0.1 - // UberFramework 7777.0.0, 7777.0.1 - // Expected: 9999.0.1 - // 7777.0.1 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.1")) - .And - .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.1")); - - // Verify we have the expected runtime versions - dotnet.Exec("--list-runtimes") - .WorkingDirectory(_currentWorkingDir) - .WithUserProfile(_userDir) - .CaptureStdOut() - .Execute() - .Should() - .Pass() - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") - .And - .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.1") - .And - .HaveStdOutContaining("Microsoft.UberFramework 7777.0.0") - .And - .HaveStdOutContaining("Microsoft.UberFramework 7777.0.1"); - } - - [Fact] - public void Multiple_SharedFxLookup_Do_Not_Propagate() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); - - // Version: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // 'Roll forward on no candidate fx' disabled through env var - // Exe: NetCoreApp 9999.1.0 - // UberFramework 7777.0.0 - // Expected: no compatible version - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "0") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("It was not possible to find any compatible framework version"); - - // Enable rollForwardOnNoCandidateFx on app's config, which will not be used as the default for Uber's config - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", rollFwdOnNoCandidateFx: 1, useUberFramework: true); - - // Version: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // 'Roll forward on no candidate fx' enabled through config - // Exe: NetCoreApp 9999.1.0 - // UberFramework 7777.0.0 - // Expected: no compatible version - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "0") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("It was not possible to find any compatible framework version"); - } - - [Fact] - public void Multiple_Fx_References_Cant_Roll_Forward_Because_Incompatible_Config() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - - var additionalfxs = new JArray(); - additionalfxs.Add(GetAdditionalFramework("Microsoft.NETCore.App", "9999.1.0", applyPatches: false, rollForwardOnNoCandidateFx: 0)); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true, frameworks: additionalfxs); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0", "9999.5.5"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); - - // Verify that both 9999.1.0 and 9999.5.5 can't be selected with roll-forward disabled - // Version: NetCoreApp 9999.5.5 (in framework section) - // NetCoreApp 9999.1.0 (in frameworks section) - // UberFramework 7777.0.0 - // Exe: NetCoreApp 9999.1.0 rollForwardOnNoCandidateFx:0 applyPatches:false - // NetCoreApp 9999.5.5 - // UberFramework 7777.0.0 - // Expected: no compatible version - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("cannot roll-forward to the previously referenced version '9999.5.5"); - } - - [Fact] - public void Multiple_Fx_References_Can_Roll_Forward_Without_Retry() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - - var additionalfxs = new JArray(); - additionalfxs.Add(GetAdditionalFramework("Microsoft.NETCore.App", "9999.1.1", applyPatches: false, rollForwardOnNoCandidateFx: 1)); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true, frameworks: additionalfxs); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0", "9999.5.5"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); - - // Version: NetCoreApp 9999.5.5 (in framework section) - // NetCoreApp 9999.1.0 (in frameworks section) - // UberFramework 7777.0.0 - // Exe: NetCoreApp 9999.1.0 rollForwardOnNoCandidateFx:1 applyPatches:false - // NetCoreApp 9999.5.5 - // UberFramework 7777.0.0 - // Expected: 9999.5.5 - // 7777.0.0 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.5.5")) - .And - .HaveStdOutContaining("Framework Version:9999.5.5") - .And - .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.0")) - .And - .NotHaveStdErrContaining("Restarting all framework resolution"); - } - - [Fact] - public void Multiple_Fx_References_Can_Roll_Forward_With_Retry() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - - var additionalfxs = new JArray(); - additionalfxs.Add(GetAdditionalFramework("Microsoft.UberFramework", "7777.0.0", null, null)); - // Specify Uber as additional fx so we find NetCoreApp 9999.1.1 and then need to do a re-try for 9999.5.5 - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.1.1", null, null, frameworks: additionalfxs); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1", "9999.5.5"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); - - // Version: NetCoreApp 9999.1.1 (in framework section) - // UberFramework 7777.0.0 (in frameworks section) - // NetCoreApp 9999.5.5 (in uber's config) - // Exe: NetCoreApp 9999.1.1 - // NetCoreApp 9999.5.5 - // UberFramework 7777.0.0 - // Expected: 9999.5.5 - // 7777.0.0 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.5.5")) - .And - .HaveStdOutContaining("Framework Version:9999.5.5") - .And - .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.0")) - .And - .HaveStdErrContaining("Restarting all framework resolution because the previously resolved framework 'Microsoft.NETCore.App', version '9999.1.1' must be re-resolved with the new version '9999.5.5'"); - } - - [Fact] - public void Multiple_Fx_References_Cant_Roll_Forward_Because_Disabled_Through_CommandLine() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - - var additionalfxs = new JArray(); - additionalfxs.Add(GetAdditionalFramework("Microsoft.NETCore.App", "9999.1.1", applyPatches: false, rollForwardOnNoCandidateFx: 1)); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true, frameworks: additionalfxs); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0", "9999.5.5"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); - - // Version: NetCoreApp 9999.5.5 (in framework section) - // NetCoreApp 9999.1.0 (in frameworks section) - // UberFramework 7777.0.0 - // Exe: NetCoreApp 9999.1.0 rollForwardOnNoCandidateFx:1 applyPatches:false - // NetCoreApp 9999.5.5 - // UberFramework 7777.0.0 - // --roll-forward-on-no-candidate-fx=0 should override config settings - // Expected: 9999.5.5 - // 7777.0.0 - - dotnet.Exec( - "exec", - "--roll-forward-on-no-candidate-fx", "0", - appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute(fExpectedToFail: true) - .Should() - .Fail() - .And - .HaveStdErrContaining("cannot roll-forward to the previously referenced version '9999.5.5"); - } - - [Fact] - public void Multiple_SharedFxLookup_NetCoreApp_MinorRollForward_Wins_Over_UberFx() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); - - // Modify the Uber values - SharedFramework.CreateUberFrameworkArtifacts(_builtSharedFxDir, _builtSharedUberFxDir, "0.0.0.1", "0.0.0.2"); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); - - string uberFile = Path.Combine(_exeSharedUberFxBaseDir, "7777.0.0", "System.Collections.Immutable.dll"); - string netCoreAppFile = Path.Combine(_exeSharedFxBaseDir, "9999.1.0", "System.Collections.Immutable.dll"); - // The System.Collections.Immutable.dll is located in the UberFramework and NetCoreApp - // Version: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // 'Roll forward on no candidate fx' enabled through config - // Exe: NetCoreApp 9999.1.0 - // UberFramework 7777.0.0 - // Expected: 9999.1.0 - // 7777.0.0 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining($"Replacing deps entry [{uberFile}, AssemblyVersion:0.0.0.1, FileVersion:0.0.0.2] with [{netCoreAppFile}"); - } - - [Fact] - public void Multiple_SharedFxLookup_Uber_Wins_Over_NetCoreApp_On_PatchRollForward() - { - var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture - .Copy(); - - var dotnet = fixture.BuiltDotnet; - var appDll = fixture.TestProject.AppDll; - - string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); - SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); - - // Add versions in the exe folders - SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.1"); - SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); - - // The System.Collections.Immutable.dll is located in the UberFramework and NetCoreApp - // Version: NetCoreApp 9999.0.0 - // UberFramework 7777.0.0 - // 'Roll forward on no candidate fx' enabled through config - // Exe: NetCoreApp 9999.0.1 - // UberFramework 7777.0.0 - // Expected: 9999.0.1 - // 7777.0.0 - dotnet.Exec(appDll) - .WorkingDirectory(_currentWorkingDir) - .EnvironmentVariable("COREHOST_TRACE", "1") - .CaptureStdOut() - .CaptureStdErr() - .Execute() - .Should() - .Pass() - .And - .HaveStdErrContaining(Path.Combine("7777.0.0", "System.Collections.Immutable.dll")) - .And - .NotHaveStdErrContaining(Path.Combine("9999.1.0", "System.Collections.Immutable.dll")); + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0-dummy3"); } static private JObject GetAdditionalFramework(string fxName, string fxVersion, bool? applyPatches, int? rollForwardOnNoCandidateFx) diff --git a/src/installer/test/HostActivationTests/GivenThatICareAboutNativeHostApis.cs b/src/installer/test/HostActivationTests/GivenThatICareAboutNativeHostApis.cs index d108df5..dd6c1f0 100644 --- a/src/installer/test/HostActivationTests/GivenThatICareAboutNativeHostApis.cs +++ b/src/installer/test/HostActivationTests/GivenThatICareAboutNativeHostApis.cs @@ -149,11 +149,14 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHostApis public string AppDll => _fixture.TestProject.AppDll; public string ExeDir => Path.Combine(_fixture.TestProject.ProjectDirectory, "ed"); public string ProgramFiles => Path.Combine(ExeDir, "pf"); + public string SelfRegistered => Path.Combine(ExeDir, "sr"); public string WorkingDir => Path.Combine(_fixture.TestProject.ProjectDirectory, "wd"); - public string GlobalSdkDir => Path.Combine(ProgramFiles, "dotnet", "sdk"); + public string ProgramFilesGlobalSdkDir => Path.Combine(ProgramFiles, "dotnet", "sdk"); + public string SelfRegisteredGlobalSdkDir => Path.Combine(SelfRegistered, "sdk"); public string LocalSdkDir => Path.Combine(ExeDir, "sdk"); public string GlobalJson => Path.Combine(WorkingDir, "global.json"); - public string[] GlobalSdks = new[] { "4.5.6", "1.2.3", "2.3.4-preview" }; + public string[] ProgramFilesGlobalSdks = new[] { "4.5.6", "1.2.3", "2.3.4-preview" }; + public string[] SelfRegisteredGlobalSdks = new[] { "3.0.0", "15.1.4-preview", "5.6.7" }; public string[] LocalSdks = new[] { "0.1.2", "5.6.7-preview", "1.2.3" }; public SdkResolutionFixture(SharedTestState state) @@ -166,11 +169,14 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHostApis // on a given machine from impacting the test. File.WriteAllText(GlobalJson, "{}"); - foreach (string sdk in GlobalSdks) + foreach (string sdk in ProgramFilesGlobalSdks) { - Directory.CreateDirectory(Path.Combine(GlobalSdkDir, sdk)); + Directory.CreateDirectory(Path.Combine(ProgramFilesGlobalSdkDir, sdk)); + } + foreach (string sdk in SelfRegisteredGlobalSdks) + { + Directory.CreateDirectory(Path.Combine(SelfRegisteredGlobalSdkDir, sdk)); } - foreach (string sdk in LocalSdks) { Directory.CreateDirectory(Path.Combine(LocalSdkDir, sdk)); @@ -194,15 +200,19 @@ namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.NativeHostApis string expectedList = string.Join(';', new[] { Path.Combine(f.LocalSdkDir, "0.1.2"), - Path.Combine(f.GlobalSdkDir, "1.2.3"), + Path.Combine(f.ProgramFilesGlobalSdkDir, "1.2.3"), Path.Combine(f.LocalSdkDir, "1.2.3"), - Path.Combine(f.GlobalSdkDir, "2.3.4-preview"), - Path.Combine(f.GlobalSdkDir, "4.5.6"), + Path.Combine(f.ProgramFilesGlobalSdkDir, "2.3.4-preview"), + Path.Combine(f.SelfRegisteredGlobalSdkDir, "3.0.0"), + Path.Combine(f.ProgramFilesGlobalSdkDir, "4.5.6"), Path.Combine(f.LocalSdkDir, "5.6.7-preview"), + Path.Combine(f.SelfRegisteredGlobalSdkDir, "5.6.7"), + Path.Combine(f.SelfRegisteredGlobalSdkDir, "15.1.4-preview"), }); f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_available_sdks", f.ExeDir }) .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles) + .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered) .CaptureStdOut() .CaptureStdErr() .Execute() diff --git a/src/installer/test/HostActivationTests/GivenThatICareAboutSDKLookup.cs b/src/installer/test/HostActivationTests/GivenThatICareAboutSDKLookup.cs new file mode 100644 index 0000000..65b2aaf --- /dev/null +++ b/src/installer/test/HostActivationTests/GivenThatICareAboutSDKLookup.cs @@ -0,0 +1,734 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Microsoft.DotNet.InternalAbstractions; +using Xunit; + +namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.SDKLookup +{ + public class GivenThatICareAboutSDKLookup : IDisposable + { + private static IDictionary s_DefaultEnvironment = new Dictionary() + { + {"COREHOST_TRACE", "1" }, + // The SDK being used may be crossgen'd for a different architecture than we are building for. + // Turn off ready to run, so an x64 crossgen'd SDK can be loaded in an x86 process. + {"COMPlus_ReadyToRun", "0" }, + }; + + private RepoDirectoriesProvider RepoDirectories; + private TestProjectFixture PreviouslyBuiltAndRestoredPortableTestProjectFixture; + + private string _currentWorkingDir; + private string _userDir; + private string _executableDir; + private string _cwdSdkBaseDir; + private string _userSdkBaseDir; + private string _exeSdkBaseDir; + private string _cwdSelectedMessage; + private string _userSelectedMessage; + private string _exeSelectedMessage; + private string _sdkDir; + private string _baseDir; + + private const string _dotnetSdkDllMessageTerminator = "dotnet.dll]"; + + public GivenThatICareAboutSDKLookup() + { + // From the artifacts dir, it's possible to find where the sharedFrameworkPublish folder is. We need + // to locate it because we'll copy its contents into other folders + string artifactsDir = Environment.GetEnvironmentVariable("TEST_ARTIFACTS"); + string builtDotnet = Path.Combine(artifactsDir, "sharedFrameworkPublish"); + + // The dotnetSDKLookup dir will contain some folders and files that will be + // necessary to perform the tests + string baseDir = Path.Combine(artifactsDir, "dotnetSDKLookup"); + _baseDir = SharedFramework.CalculateUniqueTestDirectory(baseDir); + + // The three tested locations will be the cwd, the user folder and the exe dir. cwd and user are no longer supported. + // All dirs will be placed inside the base folder + + _currentWorkingDir = Path.Combine(_baseDir, "cwd"); + _userDir = Path.Combine(_baseDir, "user"); + _executableDir = Path.Combine(_baseDir, "exe"); + + // It's necessary to copy the entire publish folder to the exe dir because + // we'll need to build from it. The CopyDirectory method automatically creates the dest dir + SharedFramework.CopyDirectory(builtDotnet, _executableDir); + + RepoDirectories = new RepoDirectoriesProvider(builtDotnet: _executableDir); + + // SdkBaseDirs contain all available version folders + _cwdSdkBaseDir = Path.Combine(_currentWorkingDir, "sdk"); + _userSdkBaseDir = Path.Combine(_userDir, ".dotnet", RepoDirectories.BuildArchitecture, "sdk"); + _exeSdkBaseDir = Path.Combine(_executableDir, "sdk"); + + // Create directories + Directory.CreateDirectory(_cwdSdkBaseDir); + Directory.CreateDirectory(_userSdkBaseDir); + Directory.CreateDirectory(_exeSdkBaseDir); + + // Restore and build PortableApp from exe dir + PreviouslyBuiltAndRestoredPortableTestProjectFixture = new TestProjectFixture("PortableApp", RepoDirectories) + .EnsureRestored(RepoDirectories.CorehostPackages) + .BuildProject(); + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture; + + // Set a dummy framework version (9999.0.0) in the exe sharedFx location. We will + // always pick the framework from this to avoid interference with the sharedFxLookup + string exeDirDummyFxVersion = Path.Combine(_executableDir, "shared", "Microsoft.NETCore.App", "9999.0.0"); + string builtSharedFxDir = fixture.BuiltDotnet.GreatestVersionSharedFxPath; + SharedFramework.CopyDirectory(builtSharedFxDir, exeDirDummyFxVersion); + + // The actual SDK version can be obtained from the built fixture. We'll use it to + // locate the sdkDir from which we can get the files contained in the version folder + string sdkBaseDir = Path.Combine(fixture.SdkDotnet.BinPath, "sdk"); + + var sdkVersionDirs = Directory.EnumerateDirectories(sdkBaseDir) + .Select(p => Path.GetFileName(p)); + + string greatestVersionSdk = sdkVersionDirs + .Where(p => !string.Equals(p, "NuGetFallbackFolder", StringComparison.OrdinalIgnoreCase)) + .OrderByDescending(p => p.ToLower()) + .First(); + + _sdkDir = Path.Combine(sdkBaseDir, greatestVersionSdk); + + // Trace messages used to identify from which folder the SDK was picked + _cwdSelectedMessage = $"Using dotnet SDK dll=[{_cwdSdkBaseDir}"; + _userSelectedMessage = $"Using dotnet SDK dll=[{_userSdkBaseDir}"; + _exeSelectedMessage = $"Using dotnet SDK dll=[{_exeSdkBaseDir}"; + } + + public void Dispose() + { + PreviouslyBuiltAndRestoredPortableTestProjectFixture.Dispose(); + + if (!TestProject.PreserveTestRuns()) + { + Directory.Delete(_baseDir, true); + } + } + + [Fact] + public void SdkLookup_Global_Json_Single_Digit_Patch_Rollup() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + + // Set specified SDK version = 9999.3.4-global-dummy + SetGlobalJsonVersion("SingleDigit-global.json"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: empty + // Expected: no compatible version and a specific error messages + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") + .And + .HaveStdErrContaining("It was not possible to find any installed dotnet SDKs") + .And + .NotHaveStdErrContaining("Checking if resolved SDK dir"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.4.1", "9999.3.4-dummy"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy + // Expected: no compatible version and a specific error message + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") + .And + .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.3"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3 + // Expected: no compatible version and a specific error message + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") + .And + .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.4"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4 + // Expected: 9999.3.4 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.4", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.5-dummy"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4, 9999.3.5-dummy + // Expected: 9999.3.5-dummy from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.5-dummy", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.600"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4, 9999.3.5-dummy, 9999.3.600 + // Expected: 9999.3.5-dummy from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.5-dummy", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.4-global-dummy"); + + // Specified SDK version: 9999.3.4-global-dummy + // Exe: 9999.4.1, 9999.3.4-dummy, 9999.3.3, 9999.3.4, 9999.3.5-dummy, 9999.3.600, 9999.3.4-global-dummy + // Expected: 9999.3.4-global-dummy from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.4-global-dummy", _dotnetSdkDllMessageTerminator)); + + // Verify we have the expected SDK versions + dotnet.Exec("--list-sdks") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("9999.3.4-dummy") + .And + .HaveStdOutContaining("9999.3.4-global-dummy") + .And + .HaveStdOutContaining("9999.4.1") + .And + .HaveStdOutContaining("9999.3.3") + .And + .HaveStdOutContaining("9999.3.4") + .And + .HaveStdOutContaining("9999.3.600") + .And + .HaveStdOutContaining("9999.3.5-dummy"); + } + + [Fact] + public void SdkLookup_Global_Json_Two_Part_Patch_Rollup() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + + // Set specified SDK version = 9999.3.304-global-dummy + SetGlobalJsonVersion("TwoPart-global.json"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: empty + // Expected: no compatible version and a specific error messages + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") + .And + .HaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.57", "9999.3.4-dummy"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: 9999.3.57, 9999.3.4-dummy + // Expected: no compatible version and a specific error message + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") + .And + .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.300", "9999.7.304-global-dummy"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy + // Expected: no compatible version and a specific error message + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("A compatible installed dotnet SDK for global.json version") + .And + .NotHaveStdErrContaining("It was not possible to find any installed dotnet SDKs"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.304"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: 99999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304 + // Expected: 9999.3.304 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.304", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.399", "9999.3.399-dummy", "9999.3.400"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304, 9999.3.399, 9999.3.399-dummy, 9999.3.400 + // Expected: 9999.3.399 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.399", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.2400, 9999.3.3004"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304, 9999.3.399, 9999.3.399-dummy, 9999.3.400, 9999.3.2400, 9999.3.3004 + // Expected: 9999.3.399 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.399", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.3.304-global-dummy"); + + // Specified SDK version: 9999.3.304-global-dummy + // Exe: 9999.3.57, 9999.3.4-dummy, 9999.3.300, 9999.7.304-global-dummy, 9999.3.304, 9999.3.399, 9999.3.399-dummy, 9999.3.400, 9999.3.2400, 9999.3.3004, 9999.3.304-global-dummy + // Expected: 9999.3.304-global-dummy from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.3.304-global-dummy", _dotnetSdkDllMessageTerminator)); + + // Verify we have the expected SDK versions + dotnet.Exec("--list-sdks") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("9999.3.57") + .And + .HaveStdOutContaining("9999.3.4-dummy") + .And + .HaveStdOutContaining("9999.3.300") + .And + .HaveStdOutContaining("9999.7.304-global-dummy") + .And + .HaveStdOutContaining("9999.3.399") + .And + .HaveStdOutContaining("9999.3.399-dummy") + .And + .HaveStdOutContaining("9999.3.400") + .And + .HaveStdOutContaining("9999.3.2400") + .And + .HaveStdOutContaining("9999.3.3004") + .And + .HaveStdOutContaining("9999.3.304") + .And + .HaveStdOutContaining("9999.3.304-global-dummy"); + } + + [Fact] + public void SdkLookup_Negative_Version() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + + // Add a negative SDK version + AddAvailableSdkVersions(_exeSdkBaseDir, "-1.-1.-1"); + + // Specified SDK version: none + // Exe: -1.-1.-1 + // Expected: no compatible version and a specific error messages + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any installed dotnet SDKs") + .And + .HaveStdErrContaining("Did you mean to run dotnet SDK commands? Please install dotnet SDK from"); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.4"); + + // Specified SDK version: none + // Exe: -1.-1.-1, 9999.0.4 + // Expected: 9999.0.4 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.4", _dotnetSdkDllMessageTerminator)); + + // Verify we have the expected SDK versions + dotnet.Exec("--list-sdks") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("9999.0.4"); + } + + [Fact] + public void SdkLookup_Must_Pick_The_Highest_Semantic_Version() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.0", "9999.0.3-dummy"); + + // Specified SDK version: none + // Cwd: empty + // User: empty + // Exe: 9999.0.0, 9999.0.3-dummy + // Expected: 9999.0.3-dummy from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.3-dummy", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.3"); + + // Specified SDK version: none + // Cwd: empty + // User: empty + // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3 + // Expected: 9999.0.3 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.3", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_userSdkBaseDir, "9999.0.200"); + AddAvailableSdkVersions(_cwdSdkBaseDir, "10000.0.0"); + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.100"); + + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked + // User: 9999.0.200 --> should not be picked + // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100 + // Expected: 9999.0.100 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.100", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.80"); + + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked + // User: 9999.0.200 --> should not be picked + // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100, 9999.0.80 + // Expected: 9999.0.100 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.100", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.5500000"); + + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked + // User: 9999.0.200 --> should not be picked + // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100, 9999.0.80, 9999.0.5500000 + // Expected: 9999.0.5500000 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.5500000", _dotnetSdkDllMessageTerminator)); + + // Add SDK versions + AddAvailableSdkVersions(_exeSdkBaseDir, "9999.0.52000000"); + + // Specified SDK version: none + // Cwd: 10000.0.0 --> should not be picked + // User: 9999.0.200 --> should not be picked + // Exe: 9999.0.0, 9999.0.3-dummy, 9999.0.3, 9999.0.100, 9999.0.80, 9999.0.5500000, 9999.0.52000000 + // Expected: 9999.0.52000000 from exe dir + dotnet.Exec("help") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.52000000", _dotnetSdkDllMessageTerminator)); + + // Verify we have the expected SDK versions + dotnet.Exec("--list-sdks") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .Environment(s_DefaultEnvironment) + .EnvironmentVariable("DOTNET_MULTILEVEL_LOOKUP", "0") + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("9999.0.0") + .And + .HaveStdOutContaining("9999.0.3-dummy") + .And + .HaveStdOutContaining("9999.0.3") + .And + .HaveStdOutContaining("9999.0.100") + .And + .HaveStdOutContaining("9999.0.80") + .And + .HaveStdOutContaining("9999.0.5500000") + .And + .HaveStdOutContaining("9999.0.52000000"); + } + + // This method adds a list of new sdk version folders in the specified + // sdkBaseDir. The files are copied from the _sdkDir. Also, the dotnet.runtimeconfig.json + // file is overwritten in order to use a dummy framework version (9999.0.0) + // Remarks: + // - If the sdkBaseDir does not exist, then a DirectoryNotFoundException + // is thrown. + // - If a specified version folder already exists, then it is deleted and replaced + // with the contents of the _builtSharedFxDir. + private void AddAvailableSdkVersions(string sdkBaseDir, params string[] availableVersions) + { + DirectoryInfo sdkBaseDirInfo = new DirectoryInfo(sdkBaseDir); + + if (!sdkBaseDirInfo.Exists) + { + throw new DirectoryNotFoundException(); + } + + string dummyRuntimeConfig = Path.Combine(RepoDirectories.RepoRoot, "src", "test", "Assets", "TestUtils", + "SDKLookup", "dotnet.runtimeconfig.json"); + + foreach (string version in availableVersions) + { + string newSdkDir = Path.Combine(sdkBaseDir, version); + SharedFramework.CopyDirectory(_sdkDir, newSdkDir); + + string runtimeConfig = Path.Combine(newSdkDir, "dotnet.runtimeconfig.json"); + File.Copy(dummyRuntimeConfig, runtimeConfig, true); + } + } + + // Put a global.json file in the cwd in order to specify a CLI + public void SetGlobalJsonVersion(string globalJsonFileName) + { + string destFile = Path.Combine(_currentWorkingDir, "global.json"); + string srcFile = Path.Combine(RepoDirectories.RepoRoot, "src", "test", "Assets", "TestUtils", + "SDKLookup", globalJsonFileName); + + File.Copy(srcFile, destFile, true); + } + } +} diff --git a/src/installer/test/HostActivationTests/GivenThatICareAboutSharedFxLookup.cs b/src/installer/test/HostActivationTests/GivenThatICareAboutSharedFxLookup.cs new file mode 100644 index 0000000..9f75c64 --- /dev/null +++ b/src/installer/test/HostActivationTests/GivenThatICareAboutSharedFxLookup.cs @@ -0,0 +1,1062 @@ +using Microsoft.DotNet.InternalAbstractions; +using Microsoft.DotNet.Cli.Build.Framework; +using Newtonsoft.Json.Linq; +using System; +using System.IO; +using Xunit; + +namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.SharedFxLookup +{ + public partial class GivenThatICareAboutSharedFxLookup : IDisposable + { + private const string SystemCollectionsImmutableFileVersion = "88.2.3.4"; + private const string SystemCollectionsImmutableAssemblyVersion = "88.0.1.2"; + + private RepoDirectoriesProvider RepoDirectories; + private TestProjectFixture PreviouslyBuiltAndRestoredPortableTestProjectFixture; + + private string _currentWorkingDir; + private string _userDir; + private string _executableDir; + private string _globalDir; + private string _cwdSharedFxBaseDir; + private string _cwdSharedUberFxBaseDir; + private string _userSharedFxBaseDir; + private string _userSharedUberFxBaseDir; + private string _exeSharedFxBaseDir; + private string _exeSharedUberFxBaseDir; + private string _globalSharedFxBaseDir; + private string _globalSharedUberFxBaseDir; + private string _builtSharedFxDir; + private string _builtSharedUberFxDir; + + private string _cwdSelectedMessage; + private string _userSelectedMessage; + private string _exeSelectedMessage; + private string _globalSelectedMessage; + + private string _cwdFoundUberFxMessage; + private string _userFoundUberFxMessage; + private string _exeFoundUberFxMessage; + private string _globalFoundUberFxMessage; + + private string _sharedFxVersion; + private string _baseDir; + private string _builtDotnet; + private string _hostPolicyDllName; + + public GivenThatICareAboutSharedFxLookup() + { + // From the artifacts dir, it's possible to find where the sharedFrameworkPublish folder is. We need + // to locate it because we'll copy its contents into other folders + string artifactsDir = Environment.GetEnvironmentVariable("TEST_ARTIFACTS"); + _builtDotnet = Path.Combine(artifactsDir, "sharedFrameworkPublish"); + + // The dotnetSharedFxLookup dir will contain some folders and files that will be + // necessary to perform the tests + string baseDir = Path.Combine(artifactsDir, "dotnetSharedFxLookup"); + _baseDir = SharedFramework.CalculateUniqueTestDirectory(baseDir); + + // The three tested locations will be the cwd, the user folder and the exe dir. Both cwd and exe dir + // are easily overwritten, so they will be placed inside the multilevel folder. The actual user location will + // be used during tests + _currentWorkingDir = Path.Combine(_baseDir, "cwd"); + _userDir = Path.Combine(_baseDir, "user"); + _executableDir = Path.Combine(_baseDir, "exe"); + _globalDir = Path.Combine(_baseDir, "global"); + + RepoDirectories = new RepoDirectoriesProvider(builtDotnet: _executableDir); + + // SharedFxBaseDirs contain all available version folders + _cwdSharedFxBaseDir = Path.Combine(_currentWorkingDir, "shared", "Microsoft.NETCore.App"); + _userSharedFxBaseDir = Path.Combine(_userDir, ".dotnet", RepoDirectories.BuildArchitecture, "shared", "Microsoft.NETCore.App"); + _exeSharedFxBaseDir = Path.Combine(_executableDir, "shared", "Microsoft.NETCore.App"); + _globalSharedFxBaseDir = Path.Combine(_globalDir, "shared", "Microsoft.NETCore.App"); + + _cwdSharedUberFxBaseDir = Path.Combine(_currentWorkingDir, "shared", "Microsoft.UberFramework"); + _userSharedUberFxBaseDir = Path.Combine(_userDir, ".dotnet", RepoDirectories.BuildArchitecture, "shared", "Microsoft.UberFramework"); + _exeSharedUberFxBaseDir = Path.Combine(_executableDir, "shared", "Microsoft.UberFramework"); + _globalSharedUberFxBaseDir = Path.Combine(_globalDir, "shared", "Microsoft.UberFramework"); + + // Create directories. It's necessary to copy the entire publish folder to the exe dir because + // we'll need to build from it. The CopyDirectory method automatically creates the dest dir + Directory.CreateDirectory(_cwdSharedFxBaseDir); + Directory.CreateDirectory(_userSharedFxBaseDir); + Directory.CreateDirectory(_globalSharedFxBaseDir); + Directory.CreateDirectory(_cwdSharedUberFxBaseDir); + Directory.CreateDirectory(_userSharedUberFxBaseDir); + Directory.CreateDirectory(_globalSharedUberFxBaseDir); + SharedFramework.CopyDirectory(_builtDotnet, _executableDir); + + //Copy dotnet to global directory + File.Copy(Path.Combine(_builtDotnet, $"dotnet{Constants.ExeSuffix}"), Path.Combine(_globalDir, $"dotnet{Constants.ExeSuffix}"), true); + + // Restore and build SharedFxLookupPortableApp from exe dir + PreviouslyBuiltAndRestoredPortableTestProjectFixture = new TestProjectFixture("SharedFxLookupPortableApp", RepoDirectories) + .EnsureRestored(RepoDirectories.CorehostPackages) + .BuildProject(); + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture; + + // The actual framework version can be obtained from the built fixture. We'll use it to + // locate the builtSharedFxDir from which we can get the files contained in the version folder + string greatestVersionSharedFxPath = fixture.BuiltDotnet.GreatestVersionSharedFxPath; + _sharedFxVersion = (new DirectoryInfo(greatestVersionSharedFxPath)).Name; + _builtSharedFxDir = Path.Combine(_builtDotnet, "shared", "Microsoft.NETCore.App", _sharedFxVersion); + _builtSharedUberFxDir = Path.Combine(_builtDotnet, "shared", "Microsoft.UberFramework", _sharedFxVersion); + SharedFramework.CreateUberFrameworkArtifacts(_builtSharedFxDir, _builtSharedUberFxDir, SystemCollectionsImmutableAssemblyVersion, SystemCollectionsImmutableFileVersion); + + // Trace messages used to identify from which folder the framework was picked + _hostPolicyDllName = Path.GetFileName(fixture.TestProject.HostPolicyDll); + _cwdSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_cwdSharedFxBaseDir}"; + _userSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_userSharedFxBaseDir}"; + _exeSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_exeSharedFxBaseDir}"; + _globalSelectedMessage = $"The expected {_hostPolicyDllName} directory is [{_globalSharedFxBaseDir}"; + + _cwdFoundUberFxMessage = $"Chose FX version [{_cwdSharedUberFxBaseDir}"; + _userFoundUberFxMessage = $"Chose FX version [{_userSharedUberFxBaseDir}"; + _exeFoundUberFxMessage = $"Chose FX version [{_exeSharedUberFxBaseDir}"; + _globalFoundUberFxMessage = $"Chose FX version [{_globalSharedUberFxBaseDir}"; + } + + public void Dispose() + { + PreviouslyBuiltAndRestoredPortableTestProjectFixture.Dispose(); + + if (!TestProject.PreserveTestRuns()) + { + Directory.Delete(_baseDir, true); + } + } + + [Fact] + public void SharedFxLookup_Must_Verify_Folders_in_the_Correct_Order() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Set desired version = 9999.0.0 + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); + + // Add version in the exe dir + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0"); + + // Version: 9999.0.0 + // User: empty + // Exe: 9999.0.0 + // Expected: 9999.0.0 from exe dir + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .WithUserProfile(_userDir) + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(_exeSelectedMessage); + + // Add a dummy version in the user dir + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _userSharedFxBaseDir, "9999.0.0"); + + // Version: 9999.0.0 + // User: 9999.0.0 --> should not be picked + // Exe: 9999.0.0 + // Expected: 9999.0.0 from user dir + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .WithUserProfile(_userDir) + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(_exeSelectedMessage); + + // Add a dummy version in the cwd + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _cwdSharedFxBaseDir, "9999.0.0"); + + // Version: 9999.0.0 + // CWD: 9999.0.0 --> should not be picked + // User: 9999.0.0 + // Exe: 9999.0.0 + // Expected: 9999.0.0 from user Exe + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .WithUserProfile(_userDir) + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(_exeSelectedMessage); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0"); + } + + [Fact] + public void SharedFxLookup_Must_Not_Roll_Forward_If_Framework_Version_Is_Specified_Through_Argument() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Add some dummy versions + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0", "9999.0.2", "9999.0.0-dummy2", "9999.0.3", "9999.0.0-dummy3"); + + // Version: 9999.0.0 (through --fx-version arg) + // Exe: 9999.0.2, 9999.0.0-dummy2, 9999.0.0, 9999.0.3, 9999.0.0-dummy3 + // global: empty + // Expected: 9999.0.0 from exe dir + dotnet.Exec("--fx-version", "9999.0.0", appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0")); + + // Version: 9999.0.0-dummy1 (through --fx-version arg) + // Exe: 9999.0.2, 9999.0.0-dummy2,9999.0.0, 9999.0.3, 9999.0.0-dummy3 + // global: empty + // Expected: no compatible version + dotnet.Exec("--fx-version", "9999.0.0-dummy1", appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0-dummy2") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.2") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.3") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0-dummy3"); + } + + [Fact] + public void Roll_Forward_On_No_Candidate_Fx_Must_Happen_If_Compatible_Patch_Version_Is_Not_Available() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Set desired version = 9999.0.0 + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); + + // Add some dummy versions in the exe + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "10000.1.1", "10000.1.3"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' enabled with value 2 (major+minor) through env var + // exe: 10000.1.1, 10000.1.3 + // Expected: 10000.1.3 from exe + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "2") + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "10000.1.3")); + + // Add a dummy version in the exe dir + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' enabled with value 2 (major+minor) through env var + // exe: 9999.1.1, 10000.1.1, 10000.1.3 + // Expected: 9999.1.1 from exe + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "2") + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.1.1")) + .And + .HaveStdOutContaining("Framework Version:9999.1.1"); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 10000.1.1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 10000.1.3"); + } + + [Fact] + public void Roll_Forward_On_No_Candidate_Fx_Minor_And_Disabled() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Set desired version = 9999.0.0 + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); + + // Add some dummy versions in the exe + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "10000.1.1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' default value of 1 (minor) + // exe: 10000.1.1 + // Expected: fail with no framework + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + + // Add a dummy version in the exe dir + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' default value of 1 (minor) + // exe: 9999.1.1, 10000.1.1 + // Expected: 9999.1.1 from exe + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.1.1")) + .And + .HaveStdOutContaining("Framework Version:9999.1.1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' disabled through env var + // exe: 9999.1.1, 10000.1.1 + // Expected: fail with no framework + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 10000.1.1"); + } + + [Fact] + public void Roll_Forward_On_No_Candidate_Fx_Production_To_Preview() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Set desired version = 9999.0.0 + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0"); + + // Add preview version in the exe + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1-dummy1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' default value of 1 (minor) + // exe: 9999.1.1-dummy1 + // Expected: 9999.1.1-dummy1 since there is no production version + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.1.1-dummy1")); + + // Add a production version with higher value + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.2.1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' default value of 1 (minor) + // exe: 9999.1.1-dummy1, 9999.2.1 + // Expected: 9999.2.1 since we favor production over preview + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.2.1")); + + // Add a preview version with same major.minor as production + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.2.1-dummy1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' default value of 1 (minor) + // exe: 9999.1.1-dummy1, 9999.2.1, 9999.2.1-dummy1 + // Expected: 9999.2.1 since we favor production over preview + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.2.1")); + + // Add a preview version with same major.minor as production but higher patch version + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.2.2-dummy1"); + + // Version: 9999.0.0 + // 'Roll forward on no candidate fx' default value of 1 (minor) + // exe: 9999.1.1-dummy1, 9999.2.1, 9999.2.1-dummy1, 9999.2.2-dummy1 + // Expected: 9999.2.1 since we favor production over preview + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.2.1")); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.1-dummy1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.2.1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.2.1-dummy1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.2.2-dummy1"); + } + + [Fact] + public void Roll_Forward_On_No_Candidate_Fx_Preview_To_Production() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Set desired version = 9999.0.0-dummy1 + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.0.0-dummy1"); + + // Add dummy versions in the exe + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0", "9999.0.1-dummy1"); + + // Version: 9999.0.0-dummy1 + // exe: 9999.0.0, 9999.0.1-dummy1 + // Expected: fail since we don't roll forward unless match on major.minor.patch and never roll forward to production + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + + // Add preview versions in the exe with name major.minor.patch + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0-dummy2", "9999.0.0-dummy3"); + + // Version: 9999.0.0-dummy1 + // exe: 9999.0.0-dummy2, 9999.0.0-dummy3, 9999.0.0, 9999.0.1-dummy1 + // Expected: 9999.0.0-dummy2 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0-dummy2")) + .And + .HaveStdOutContaining("Framework Version:9999.0.0-dummy2"); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("9999.0.0-dummy2") + .And + .HaveStdOutContaining("9999.0.0-dummy3") + .And + .HaveStdOutContaining("9999.0.0") + .And + .HaveStdOutContaining("9999.0.1-dummy1"); + } + + [Fact] + public void Roll_Forward_On_No_Candidate_Fx_Fails_If_No_Higher_Version_Is_Available() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + // Set desired version = 9999.1.1 + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.1.1"); + + // Add some dummy versions in the exe + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9998.0.1", "9998.1.0", "9999.0.0", "9999.0.1", "9999.1.0"); + + // Version: 9999.1.1 + // exe: 9998.0.1, 9998.1.0, 9999.0.0, 9999.0.1, 9999.1.0 + // Expected: no compatible version + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9998.0.1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9998.1.0") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.1") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.1.0"); + } + + [Fact] + public void Multiple_SharedFxLookup_Independent_Roll_Forward() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.0"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); + + // Version: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // Exe: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // Expected: 9999.0.0 + // 7777.0.0 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.0")) + .And + .HaveStdOutContaining("Framework Version:9999.0.0") + .And + .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.0")); + + // Add a newer version to verify roll-forward + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.1"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.1"); + + // Version: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // Exe: NetCoreApp 9999.0.0, 9999.0.1 + // UberFramework 7777.0.0, 7777.0.1 + // Expected: 9999.0.1 + // 7777.0.1 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.0.1")) + .And + .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.1")); + + // Verify we have the expected runtime versions + dotnet.Exec("--list-runtimes") + .WorkingDirectory(_currentWorkingDir) + .WithUserProfile(_userDir) + .CaptureStdOut() + .Execute() + .Should() + .Pass() + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.0") + .And + .HaveStdOutContaining("Microsoft.NETCore.App 9999.0.1") + .And + .HaveStdOutContaining("Microsoft.UberFramework 7777.0.0") + .And + .HaveStdOutContaining("Microsoft.UberFramework 7777.0.1"); + } + + [Fact] + public void Multiple_SharedFxLookup_Do_Not_Propagate() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); + + // Version: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // 'Roll forward on no candidate fx' disabled through env var + // Exe: NetCoreApp 9999.1.0 + // UberFramework 7777.0.0 + // Expected: no compatible version + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + + // Enable rollForwardOnNoCandidateFx on app's config, which will not be used as the default for Uber's config + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", rollFwdOnNoCandidateFx: 1, useUberFramework: true); + + // Version: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // 'Roll forward on no candidate fx' enabled through config + // Exe: NetCoreApp 9999.1.0 + // UberFramework 7777.0.0 + // Expected: no compatible version + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .EnvironmentVariable("DOTNET_ROLL_FORWARD_ON_NO_CANDIDATE_FX", "0") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("It was not possible to find any compatible framework version"); + } + + [Fact] + public void Multiple_Fx_References_Cant_Roll_Forward_Because_Incompatible_Config() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + + var additionalfxs = new JArray(); + additionalfxs.Add(GetAdditionalFramework("Microsoft.NETCore.App", "9999.1.0", applyPatches: false, rollForwardOnNoCandidateFx: 0)); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true, frameworks: additionalfxs); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0", "9999.5.5"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); + + // Verify that both 9999.1.0 and 9999.5.5 can't be selected with roll-forward disabled + // Version: NetCoreApp 9999.5.5 (in framework section) + // NetCoreApp 9999.1.0 (in frameworks section) + // UberFramework 7777.0.0 + // Exe: NetCoreApp 9999.1.0 rollForwardOnNoCandidateFx:0 applyPatches:false + // NetCoreApp 9999.5.5 + // UberFramework 7777.0.0 + // Expected: no compatible version + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("cannot roll-forward to the previously referenced version '9999.5.5"); + } + + [Fact] + public void Multiple_Fx_References_Can_Roll_Forward_Without_Retry() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + + var additionalfxs = new JArray(); + additionalfxs.Add(GetAdditionalFramework("Microsoft.NETCore.App", "9999.1.1", applyPatches: false, rollForwardOnNoCandidateFx: 1)); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true, frameworks: additionalfxs); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0", "9999.5.5"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); + + // Version: NetCoreApp 9999.5.5 (in framework section) + // NetCoreApp 9999.1.0 (in frameworks section) + // UberFramework 7777.0.0 + // Exe: NetCoreApp 9999.1.0 rollForwardOnNoCandidateFx:1 applyPatches:false + // NetCoreApp 9999.5.5 + // UberFramework 7777.0.0 + // Expected: 9999.5.5 + // 7777.0.0 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.5.5")) + .And + .HaveStdOutContaining("Framework Version:9999.5.5") + .And + .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.0")) + .And + .NotHaveStdErrContaining("Restarting all framework resolution"); + } + + [Fact] + public void Multiple_Fx_References_Can_Roll_Forward_With_Retry() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + + var additionalfxs = new JArray(); + additionalfxs.Add(GetAdditionalFramework("Microsoft.UberFramework", "7777.0.0", null, null)); + // Specify Uber as additional fx so we find NetCoreApp 9999.1.1 and then need to do a re-try for 9999.5.5 + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "9999.1.1", null, null, frameworks: additionalfxs); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.1", "9999.5.5"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); + + // Version: NetCoreApp 9999.1.1 (in framework section) + // UberFramework 7777.0.0 (in frameworks section) + // NetCoreApp 9999.5.5 (in uber's config) + // Exe: NetCoreApp 9999.1.1 + // NetCoreApp 9999.5.5 + // UberFramework 7777.0.0 + // Expected: 9999.5.5 + // 7777.0.0 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine(_exeSelectedMessage, "9999.5.5")) + .And + .HaveStdOutContaining("Framework Version:9999.5.5") + .And + .HaveStdErrContaining(Path.Combine(_exeFoundUberFxMessage, "7777.0.0")) + .And + .HaveStdErrContaining("Restarting all framework resolution because the previously resolved framework 'Microsoft.NETCore.App', version '9999.1.1' must be re-resolved with the new version '9999.5.5'"); + } + + [Fact] + public void Multiple_Fx_References_Cant_Roll_Forward_Because_Disabled_Through_CommandLine() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + + var additionalfxs = new JArray(); + additionalfxs.Add(GetAdditionalFramework("Microsoft.NETCore.App", "9999.1.1", applyPatches: false, rollForwardOnNoCandidateFx: 1)); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true, frameworks: additionalfxs); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0", "9999.5.5"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.5.5", "7777.0.0"); + + // Version: NetCoreApp 9999.5.5 (in framework section) + // NetCoreApp 9999.1.0 (in frameworks section) + // UberFramework 7777.0.0 + // Exe: NetCoreApp 9999.1.0 rollForwardOnNoCandidateFx:1 applyPatches:false + // NetCoreApp 9999.5.5 + // UberFramework 7777.0.0 + // --roll-forward-on-no-candidate-fx=0 should override config settings + // Expected: 9999.5.5 + // 7777.0.0 + + dotnet.Exec( + "exec", + "--roll-forward-on-no-candidate-fx", "0", + appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute(fExpectedToFail: true) + .Should() + .Fail() + .And + .HaveStdErrContaining("cannot roll-forward to the previously referenced version '9999.5.5"); + } + + [Fact] + public void Multiple_SharedFxLookup_NetCoreApp_MinorRollForward_Wins_Over_UberFx() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); + + // Modify the Uber values + SharedFramework.CreateUberFrameworkArtifacts(_builtSharedFxDir, _builtSharedUberFxDir, "0.0.0.1", "0.0.0.2"); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.1.0"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); + + string uberFile = Path.Combine(_exeSharedUberFxBaseDir, "7777.0.0", "System.Collections.Immutable.dll"); + string netCoreAppFile = Path.Combine(_exeSharedFxBaseDir, "9999.1.0", "System.Collections.Immutable.dll"); + // The System.Collections.Immutable.dll is located in the UberFramework and NetCoreApp + // Version: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // 'Roll forward on no candidate fx' enabled through config + // Exe: NetCoreApp 9999.1.0 + // UberFramework 7777.0.0 + // Expected: 9999.1.0 + // 7777.0.0 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining($"Replacing deps entry [{uberFile}, AssemblyVersion:0.0.0.1, FileVersion:0.0.0.2] with [{netCoreAppFile}"); + } + + [Fact] + public void Multiple_SharedFxLookup_Uber_Wins_Over_NetCoreApp_On_PatchRollForward() + { + var fixture = PreviouslyBuiltAndRestoredPortableTestProjectFixture + .Copy(); + + var dotnet = fixture.BuiltDotnet; + var appDll = fixture.TestProject.AppDll; + + string runtimeConfig = Path.Combine(fixture.TestProject.OutputDirectory, "SharedFxLookupPortableApp.runtimeconfig.json"); + SharedFramework.SetRuntimeConfigJson(runtimeConfig, "7777.0.0", null, useUberFramework: true); + + // Add versions in the exe folders + SharedFramework.AddAvailableSharedFxVersions(_builtSharedFxDir, _exeSharedFxBaseDir, "9999.0.1"); + SharedFramework.AddAvailableSharedUberFxVersions(_builtSharedUberFxDir, _exeSharedUberFxBaseDir, "9999.0.0", "7777.0.0"); + + // The System.Collections.Immutable.dll is located in the UberFramework and NetCoreApp + // Version: NetCoreApp 9999.0.0 + // UberFramework 7777.0.0 + // 'Roll forward on no candidate fx' enabled through config + // Exe: NetCoreApp 9999.0.1 + // UberFramework 7777.0.0 + // Expected: 9999.0.1 + // 7777.0.0 + dotnet.Exec(appDll) + .WorkingDirectory(_currentWorkingDir) + .EnvironmentVariable("COREHOST_TRACE", "1") + .CaptureStdOut() + .CaptureStdErr() + .Execute() + .Should() + .Pass() + .And + .HaveStdErrContaining(Path.Combine("7777.0.0", "System.Collections.Immutable.dll")) + .And + .NotHaveStdErrContaining(Path.Combine("9999.1.0", "System.Collections.Immutable.dll")); + } + + static private JObject GetAdditionalFramework(string fxName, string fxVersion, bool? applyPatches, int? rollForwardOnNoCandidateFx) + { + var jobject = new JObject(new JProperty("name", fxName)); + + if (fxVersion != null) + { + jobject.Add(new JProperty("version", fxVersion)); + } + + if (applyPatches.HasValue) + { + jobject.Add(new JProperty("applyPatches", applyPatches.Value)); + } + + if (rollForwardOnNoCandidateFx.HasValue) + { + jobject.Add(new JProperty("rollForwardOnNoCandidateFx", rollForwardOnNoCandidateFx)); + } + + return jobject; + } + + static private string CreateAStore(TestProjectFixture testProjectFixture) + { + var storeoutputDirectory = Path.Combine(testProjectFixture.TestProject.ProjectDirectory, "store"); + if (!Directory.Exists(storeoutputDirectory)) + { + Directory.CreateDirectory(storeoutputDirectory); + } + + testProjectFixture.StoreProject(outputDirectory: storeoutputDirectory); + + return storeoutputDirectory; + } + } +} -- 2.7.4