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()
{