From 6e83749a7c7aacc93775a77669a0b288f74a6a66 Mon Sep 17 00:00:00 2001 From: nohwnd Date: Fri, 13 Mar 2020 17:59:54 +0100 Subject: [PATCH] Add option to specify custom test host --- .../RunSettings/RunConfiguration.cs | 17 ++++++++++++++ .../Hosting/DotnetTestHostManager.cs | 23 +++++++++++++++---- .../Hosting/DotnetTestHostManagerTests.cs | 12 ++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs b/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs index 5656640d21..24f5ff8959 100644 --- a/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs +++ b/src/Microsoft.TestPlatform.ObjectModel/RunSettings/RunConfiguration.cs @@ -487,6 +487,11 @@ public bool ResultsDirectorySet /// public bool CollectSourceInformationSet { get; private set; } = false; + /// + /// Path to dotnet executable to be used to invoke testhost.dll. Specifying this will skip looking up testhost.exe and will force usage of the testhost.dll. + /// + public string DotnetHostPath { get; private set; } + #endregion /// @@ -571,6 +576,13 @@ public override XmlElement ToXml() root.AppendChild(targetDevice); } + if (!string.IsNullOrEmpty(this.DotnetHostPath)) + { + XmlElement dotnetHostPath = doc.CreateElement(nameof(DotnetHostPath)); + dotnetHostPath.InnerXml = this.DotnetHostPath; + root.AppendChild(dotnetHostPath); + } + return root; } @@ -867,6 +879,11 @@ public static RunConfiguration FromXml(XmlReader reader) runConfiguration.TargetDevice = reader.ReadElementContentAsString(); break; + case "DotNetHostPath": + XmlRunSettingsUtilities.ThrowOnHasAttributes(reader); + runConfiguration.DotnetHostPath = reader.ReadElementContentAsString(); + break; + default: // Ignore a runsettings element that we don't understand. It could occur in the case // the test runner is of a newer version, but the test host is of an earlier version. diff --git a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs index 0552944438..324e40be31 100644 --- a/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs +++ b/src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs @@ -68,6 +68,8 @@ public class DotnetTestHostManager : ITestRuntimeProvider private bool isVersionCheckRequired = true; + private string dotnetHostPath; + /// /// Initializes a new instance of the class. /// @@ -156,6 +158,7 @@ public void Initialize(IMessageLogger logger, string runsettingsXml) var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettingsXml); this.architecture = runConfiguration.TargetPlatform; + this.dotnetHostPath = runConfiguration.DotnetHostPath; } /// @@ -218,10 +221,16 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo( var runtimeConfigDevPath = Path.Combine(sourceDirectory, string.Concat(sourceFile, ".runtimeconfig.dev.json")); string testHostPath = string.Empty; + bool useCustomDotnetHostpath = !string.IsNullOrEmpty(this.dotnetHostPath); - // If testhost.exe is available use it + if (useCustomDotnetHostpath) + { + EqtTrace.Verbose("DotnetTestHostmanager: User specified custom path to dotnet host: '{0}'.", this.dotnetHostPath); + } + + // If testhost.exe is available use it, unless user specified path to dotnet.exe, then we will use the testhost.dll bool testHostExeFound = false; - if (this.platformEnvironment.OperatingSystem.Equals(PlatformOperatingSystem.Windows)) + if (!useCustomDotnetHostpath && this.platformEnvironment.OperatingSystem.Equals(PlatformOperatingSystem.Windows)) { var exeName = this.architecture == Architecture.X86 ? "testhost.x86.exe" : "testhost.exe"; var fullExePath = Path.Combine(sourceDirectory, exeName); @@ -257,17 +266,21 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo( if (!testHostExeFound) { - var currentProcessPath = this.processHelper.GetCurrentProcessFileName(); - if (string.IsNullOrEmpty(testHostPath)) { testHostPath = this.GetTestHostPath(runtimeConfigDevPath, depsFilePath, sourceDirectory); } + var currentProcessPath = this.processHelper.GetCurrentProcessFileName(); + if (useCustomDotnetHostpath) + { + startInfo.FileName = this.dotnetHostPath; + } + // This host manager can create process start info for dotnet core targets only. // If already running with the dotnet executable, use it; otherwise pick up the dotnet available on path. // Wrap the paths with quotes in case dotnet executable is installed on a path with whitespace. - if (currentProcessPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase) + else if (currentProcessPath.EndsWith("dotnet", StringComparison.OrdinalIgnoreCase) || currentProcessPath.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase)) { startInfo.FileName = currentProcessPath; diff --git a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs index 6922852c0c..2cf1a8889d 100644 --- a/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs +++ b/test/Microsoft.TestPlatform.TestHostProvider.UnitTests/Hosting/DotnetTestHostManagerTests.cs @@ -279,6 +279,18 @@ public void GetTestHostProcessStartInfoShouldUseTestHostExeIfPresentOnWindows() StringAssert.Contains(startInfo.FileName, testhostExePath); } + [TestMethod] + public void GetTestHostProcessStartInfoShouldUseDotnetHostPathFromRunsettings() + { + var dotnetHostPath = @"C:\dotnet.exe"; + this.mockFileHelper.Setup(ph => ph.Exists("testhost.dll")).Returns(true); + this.mockEnvironment.Setup(ev => ev.OperatingSystem).Returns(PlatformOperatingSystem.Windows); + this.dotnetHostManager.Initialize(this.mockMessageLogger.Object, $"{dotnetHostPath}"); + var startInfo = this.GetDefaultStartInfo(); + + StringAssert.Contains(startInfo.FileName, dotnetHostPath); + } + [TestMethod] public void GetTestHostProcessStartInfoShouldUseTestHostExeFromNugetIfNotFoundInSourceLocation() {