Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public RunConfiguration() : base(Constants.RunConfigurationSettingsName)
ForwardStandardOutput = !FeatureFlag.Instance.IsSet(FeatureFlag.VSTEST_DISABLE_STANDARD_OUTPUT_FORWARDING);
DisableSharedTestHost = FeatureFlag.Instance.IsSet(FeatureFlag.VSTEST_DISABLE_SHARING_NETFRAMEWORK_TESTHOST);
CreateNoNewWindow = true;
IsTargetPlatformInferred = true;
}

/// <summary>
Expand Down Expand Up @@ -474,6 +475,15 @@ public bool ResultsDirectorySet
/// </summary>
public bool SkipDefaultAdapters { get; private set; }

/// <summary>
/// Gets a value indicating whether the target platform was inferred by the platform rather than
/// pinned by the user (through <c>--arch</c>, <c>/Platform</c>, or <c>RunConfiguration.TargetPlatform</c>).
/// vstest.console stamps this into the run settings it hands to the test host manager so that the
/// per-request fact travels with the run settings instead of a process-wide singleton. Defaults to
/// <see langword="true"/> (inferred). Internal because only the in-box test host manager reads it.
/// </summary>
internal bool IsTargetPlatformInferred { get; private set; }

/// <inheritdoc/>
public override XmlElement ToXml()
{
Expand Down Expand Up @@ -1043,6 +1053,25 @@ public static RunConfiguration FromXml(XmlReader reader)
break;
}

case nameof(IsTargetPlatformInferred):
{
// Internal marker stamped by vstest.console recording whether the target platform
// was inferred (true) or pinned by the user (false). Not exposed to the public
// run settings schema; read only by the in-box test host manager.
XmlRunSettingsUtilities.ThrowOnHasAttributes(reader);
string element = reader.ReadElementContentAsString();

bool boolValue;
if (!bool.TryParse(element, out boolValue))
{
throw new SettingsException(string.Format(CultureInfo.CurrentCulture,
Resources.Resources.InvalidSettingsIncorrectValue, Constants.RunConfigurationSettingsName, boolValue, elementName));
}
Comment thread
nohwnd marked this conversation as resolved.

runConfiguration.IsTargetPlatformInferred = boolValue;
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ public class DotnetTestHostManager : ITestRuntimeProvider2
private readonly IDotnetHostHelper _dotnetHostHelper;
private readonly IEnvironment _platformEnvironment;
private readonly IProcessHelper _processHelper;
private readonly IRunSettingsHelper _runsettingHelper;
private readonly IFileHelper _fileHelper;
private readonly IWindowsRegistryHelper _windowsRegistryHelper;
private readonly IEnvironmentVariableHelper _environmentVariableHelper;
Expand All @@ -81,6 +80,12 @@ public class DotnetTestHostManager : ITestRuntimeProvider2
private string? _dotnetHostPath;
private bool _captureOutput;
private bool _createNoNewWindow;

// True when the target platform was inferred by the platform rather than pinned by the user. Read from
// the run settings in Initialize (RunConfiguration.IsTargetPlatformInferred), so this per-request fact
// travels with the run settings instead of the process-wide RunSettingsHelper singleton. Defaults to
// true (inferred), matching the historical RunSettingsHelper default when no marker is present.
private bool _isDefaultTargetArchitecture = true;
private protected TestHostManagerCallbacks? _testHostManagerCallbacks;

/// <summary>
Expand All @@ -92,7 +97,6 @@ public DotnetTestHostManager()
new FileHelper(),
new DotnetHostHelper(),
new PlatformEnvironment(),
RunSettingsHelper.Instance,
new WindowsRegistryHelper(),
new EnvironmentVariableHelper())
{
Expand All @@ -105,23 +109,20 @@ public DotnetTestHostManager()
/// <param name="fileHelper">File helper instance.</param>
/// <param name="dotnetHostHelper">DotnetHostHelper helper instance.</param>
/// <param name="platformEnvironment">Platform Environment</param>
/// <param name="runsettingHelper">RunsettingHelper instance</param>
/// <param name="windowsRegistryHelper">WindowsRegistryHelper instance</param>
/// <param name="environmentVariableHelper">EnvironmentVariableHelper instance</param>
internal DotnetTestHostManager(
IProcessHelper processHelper,
IFileHelper fileHelper,
IDotnetHostHelper dotnetHostHelper,
IEnvironment platformEnvironment,
IRunSettingsHelper runsettingHelper,
IWindowsRegistryHelper windowsRegistryHelper,
IEnvironmentVariableHelper environmentVariableHelper)
{
_processHelper = processHelper;
_fileHelper = fileHelper;
_dotnetHostHelper = dotnetHostHelper;
_platformEnvironment = platformEnvironment;
_runsettingHelper = runsettingHelper;
_windowsRegistryHelper = windowsRegistryHelper;
_environmentVariableHelper = environmentVariableHelper;
}
Expand Down Expand Up @@ -205,6 +206,7 @@ public void Initialize(IMessageLogger? logger, string runsettingsXml)
_architecture = runConfiguration.TargetPlatform;
_targetFramework = runConfiguration.TargetFramework;
_dotnetHostPath = runConfiguration.DotnetHostPath;
_isDefaultTargetArchitecture = runConfiguration.IsTargetPlatformInferred;
}

/// <inheritdoc/>
Expand Down Expand Up @@ -483,7 +485,7 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo(

// We silently force x64 only if the target architecture is the default one and is not specified by user
// through --arch or runsettings or -- RunConfiguration.TargetPlatform=arch
bool forceToX64 = _runsettingHelper.IsDefaultTargetArchitecture && SilentlyForceToX64(sourcePath);
bool forceToX64 = _isDefaultTargetArchitecture && SilentlyForceToX64(sourcePath);
EqtTrace.Verbose($"DotnetTestHostmanager: Current process architetcure '{_processHelper.GetCurrentProcessArchitecture()}'");
bool isSameArchitecture = IsSameArchitecture(_architecture, _processHelper.GetCurrentProcessArchitecture());
var currentProcessPath = _processHelper.GetCurrentProcessFileName()!;
Expand All @@ -505,7 +507,7 @@ public virtual TestProcessStartInfo GetTestHostProcessStartInfo(
EqtTrace.Verbose($"DotnetTestHostmanager: Searching muxer for the architecture '{targetArchitecture}', OS '{_platformEnvironment.OperatingSystem}' framework '{_targetFramework}' SDK platform architecture '{_platformEnvironment.Architecture}'");
if (forceToX64)
{
EqtTrace.Verbose($"DotnetTestHostmanager: Forcing the search to x64 architecure, IsDefaultTargetArchitecture '{_runsettingHelper.IsDefaultTargetArchitecture}' OS '{_platformEnvironment.OperatingSystem}' framework '{_targetFramework}'");
EqtTrace.Verbose($"DotnetTestHostmanager: Forcing the search to x64 architecure, IsDefaultTargetArchitecture '{_isDefaultTargetArchitecture}' OS '{_platformEnvironment.OperatingSystem}' framework '{_targetFramework}'");
Comment thread
nohwnd marked this conversation as resolved.
}

// Check if DOTNET_ROOT resolution should be bypassed.
Expand Down
15 changes: 15 additions & 0 deletions src/Microsoft.TestPlatform.Utilities/InferRunSettingsHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,13 @@ public class InferRunSettingsHelper
private const string TargetPlatformNodeName = "TargetPlatform";
private const string TargetFrameworkNodeName = "TargetFrameworkVersion";
private const string TargetDevice = "TargetDevice";
private const string IsTargetPlatformInferredNodeName = "IsTargetPlatformInferred";

private const string DesignModeNodePath = @"/RunSettings/RunConfiguration/DesignMode";
private const string BatchSizeNodePath = @"/RunSettings/RunConfiguration/BatchSize";
private const string CollectSourceInformationNodePath = @"/RunSettings/RunConfiguration/CollectSourceInformation";
private const string RunConfigurationNodePath = @"/RunSettings/RunConfiguration";
private const string IsTargetPlatformInferredNodePath = @"/RunSettings/RunConfiguration/IsTargetPlatformInferred";
private const string TargetPlatformNodePath = @"/RunSettings/RunConfiguration/TargetPlatform";
private const string TargetFrameworkNodePath = @"/RunSettings/RunConfiguration/TargetFrameworkVersion";
private const string ResultsDirectoryNodePath = @"/RunSettings/RunConfiguration/ResultsDirectory";
Expand Down Expand Up @@ -227,6 +229,19 @@ public static void UpdateCollectSourceInformation(XmlDocument runSettingsDocumen
AddNodeIfNotPresent(runSettingsDocument, CollectSourceInformationNodePath, CollectSourceInformationNodeName, collectSourceInformationValue);
}

/// <summary>
/// Records whether the target platform was inferred by the platform (<see langword="true"/>) or pinned
/// by the user (<see langword="false"/>) into <c>RunConfiguration.IsTargetPlatformInferred</c>. Always
/// overwrites so the value reflects the current run. This is an internal marker read by the in-box test
/// host manager; it is not part of the public run settings schema.
/// </summary>
/// <param name="runSettingsDocument">Document for runsettings xml</param>
/// <param name="isTargetPlatformInferred">Value to set</param>
public static void UpdateIsTargetPlatformInferred(XmlDocument runSettingsDocument, bool isTargetPlatformInferred)
{
AddNodeIfNotPresent(runSettingsDocument, IsTargetPlatformInferredNodePath, IsTargetPlatformInferredNodeName, isTargetPlatformInferred, overwrite: true);
}

/// <summary>
/// Updates the <c>RunConfiguration.TargetDevice</c> value for a run settings. Doesn't do anything if the value is already set.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
#nullable enable
static Microsoft.VisualStudio.TestPlatform.Utilities.InferRunSettingsHelper.UpdateIsTargetPlatformInferred(System.Xml.XmlDocument! runSettingsDocument, bool isTargetPlatformInferred) -> void
14 changes: 14 additions & 0 deletions src/vstest.console/TestPlatformHelpers/TestRequestManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -710,6 +710,7 @@ private bool UpdateRunSettingsIfRequired(
}

settingsUpdated |= UpdateDesignMode(document, runConfiguration);
settingsUpdated |= UpdateIsTargetPlatformInferred(document);
settingsUpdated |= UpdateCollectSourceInformation(document, runConfiguration);
settingsUpdated |= UpdateTargetDevice(navigator, document);
settingsUpdated |= AddOrUpdateBuiltInLoggers(document, runConfiguration, loggerRunSettings);
Expand Down Expand Up @@ -883,6 +884,19 @@ private bool UpdateDesignMode(XmlDocument document, RunConfiguration runConfigur
return updateRequired;
}

private bool UpdateIsTargetPlatformInferred(XmlDocument document)
{
// Stamp whether the target platform was inferred by the platform rather than pinned by the user
// (through --arch, /Platform, or RunConfiguration.TargetPlatform). The test host manager reads this
// per-request fact from the run settings instead of the process-wide RunSettingsHelper singleton, so
// it does not leak across requests when a single vstest.console process serves multiple requests in
// design mode. Always written so the marker reflects the current request.
InferRunSettingsHelper.UpdateIsTargetPlatformInferred(
document,
_runSettingsHelper.IsDefaultTargetArchitecture);
return true;
}

internal /* for testing purposes */ static bool AddOrUpdateBatchSize(XmlDocument document, RunConfiguration runConfiguration, bool isDiscovery)
{
// On run keep it as is to fall back to the current default value (which is 10 right now).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ public class ProxyOperationManagerTests : ProxyBaseManagerTests
private readonly Mock<IRequestData> _mockRequestData;

private Mock<IProcessHelper>? _mockProcessHelper;
private Mock<IRunSettingsHelper>? _mockRunsettingHelper;
private Mock<IWindowsRegistryHelper>? _mockWindowsRegistry;
private Mock<IEnvironmentVariableHelper>? _mockEnvironmentVariableHelper;
private Mock<IFileHelper>? _mockFileHelper;
Expand Down Expand Up @@ -358,7 +357,7 @@ public void SetupChannelShouldThrowExceptionIfVersionCheckFails()
public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredFalseShouldNotCheckVersionWithTestHost()
{
SetUpMocksForDotNetTestHost();
var testHostManager = new TestableDotnetTestHostManager(false, _mockProcessHelper.Object, _mockFileHelper.Object, _mockEnvironment.Object, _mockRunsettingHelper.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariableHelper.Object);
var testHostManager = new TestableDotnetTestHostManager(false, _mockProcessHelper.Object, _mockFileHelper.Object, _mockEnvironment.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariableHelper.Object);
testHostManager.Initialize(new NullMessageLogger(), DefaultRunSettings);

var operationManager = new TestableProxyOperationManager(_mockRequestData.Object, _mockRequestSender.Object, testHostManager);
Expand All @@ -372,7 +371,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredFalseShoul
public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredTrueShouldCheckVersionWithTestHost()
{
SetUpMocksForDotNetTestHost();
var testHostManager = new TestableDotnetTestHostManager(true, _mockProcessHelper.Object, _mockFileHelper.Object, _mockEnvironment.Object, _mockRunsettingHelper.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariableHelper.Object);
var testHostManager = new TestableDotnetTestHostManager(true, _mockProcessHelper.Object, _mockFileHelper.Object, _mockEnvironment.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariableHelper.Object);
testHostManager.Initialize(new NullMessageLogger(), DefaultRunSettings);
var operationManager = new TestableProxyOperationManager(_mockRequestData.Object, _mockRequestSender.Object, testHostManager);

Expand Down Expand Up @@ -649,17 +648,15 @@ public void UpdateTestProcessStartInfoShouldUpdateTelemetryOptedInArgFalseIfTele
Assert.Contains("--telemetryoptedin false", receivedTestProcessInfo.Arguments!);
}

[MemberNotNull(nameof(_mockProcessHelper), nameof(_mockFileHelper), nameof(_mockEnvironment), nameof(_mockRunsettingHelper), nameof(_mockWindowsRegistry), nameof(_mockEnvironmentVariableHelper))]
[MemberNotNull(nameof(_mockProcessHelper), nameof(_mockFileHelper), nameof(_mockEnvironment), nameof(_mockWindowsRegistry), nameof(_mockEnvironmentVariableHelper))]
private void SetUpMocksForDotNetTestHost()
{
_mockProcessHelper = new Mock<IProcessHelper>();
_mockFileHelper = new Mock<IFileHelper>();
_mockEnvironment = new Mock<IEnvironment>();
_mockRunsettingHelper = new Mock<IRunSettingsHelper>();
_mockWindowsRegistry = new Mock<IWindowsRegistryHelper>();
_mockEnvironmentVariableHelper = new Mock<IEnvironmentVariableHelper>();

_mockRunsettingHelper.SetupGet(r => r.IsDefaultTargetArchitecture).Returns(true);
_mockProcessHelper.Setup(
ph =>
ph.LaunchProcess(
Expand Down Expand Up @@ -715,14 +712,12 @@ public TestableDotnetTestHostManager(
IProcessHelper processHelper,
IFileHelper fileHelper,
IEnvironment environment,
IRunSettingsHelper runsettingHelper,
IWindowsRegistryHelper windowsRegistryHelper,
IEnvironmentVariableHelper environmentVariableHelper) : base(
processHelper,
fileHelper,
new DotnetHostHelper(fileHelper, environment, windowsRegistryHelper, environmentVariableHelper, processHelper),
environment,
runsettingHelper,
windowsRegistryHelper,
environmentVariableHelper)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,51 @@ public void RunConfigurationToXmlShouldProvideCreateNoNewWindow()

Assert.Contains("<CreateNoNewWindow>True</CreateNoNewWindow>", runConfiguration.ToXml().InnerXml);
}

[TestMethod]
public void RunConfigurationReadsIsTargetPlatformInferredFromXml()
{
string settingsXml =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<RunSettings>
<RunConfiguration>
<IsTargetPlatformInferred>false</IsTargetPlatformInferred>
</RunConfiguration>
</RunSettings>";

var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(settingsXml);

Assert.IsFalse(runConfiguration.IsTargetPlatformInferred);
}

[TestMethod]
public void RunConfigurationIsTargetPlatformInferredDefaultsToTrueWhenNotPresentInXml()
{
string settingsXml =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<RunSettings>
<RunConfiguration>
<TargetPlatform>x64</TargetPlatform>
</RunConfiguration>
</RunSettings>";

var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(settingsXml);

Assert.IsTrue(runConfiguration.IsTargetPlatformInferred);
}

[TestMethod]
public void RunConfigurationFromXmlThrowsSettingsExceptionIfIsTargetPlatformInferredIsInvalid()
{
string settingsXml =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<RunSettings>
<RunConfiguration>
<IsTargetPlatformInferred>InvalidValue</IsTargetPlatformInferred>
</RunConfiguration>
</RunSettings>";

Assert.ThrowsExactly<SettingsException>(
() => XmlRunSettingsUtilities.GetRunConfigurationNode(settingsXml));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public class DotnetTestHostManagerFilesystemIntegrationTests
private readonly Mock<IProcessHelper> _mockProcessHelper = new();
private readonly Mock<IEnvironment> _mockEnvironment = new();
private readonly Mock<IMessageLogger> _mockMessageLogger = new();
private readonly Mock<IRunSettingsHelper> _mockRunsettingsHelper = new();
private readonly Mock<IWindowsRegistryHelper> _mockWindowsRegistry = new();
private readonly Mock<IEnvironmentVariableHelper> _mockEnvironmentVariable = new();
private readonly TestRunnerConnectionInfo _connectionInfo = new()
Expand All @@ -56,7 +55,6 @@ public void SetUp()
// Simulate non-Windows so the code goes to testhost.dll discovery (not testhost.exe).
_mockEnvironment.Setup(e => e.OperatingSystem).Returns(PlatformOperatingSystem.Unix);
_mockEnvironment.SetupGet(e => e.Architecture).Returns(PlatformArchitecture.X64);
_mockRunsettingsHelper.SetupGet(r => r.IsDefaultTargetArchitecture).Returns(true);

// Current process is a dotnet muxer so it is used as-is for FileName.
_mockProcessHelper.Setup(p => p.GetCurrentProcessFileName()).Returns("/usr/bin/dotnet");
Expand Down Expand Up @@ -292,7 +290,6 @@ private DotnetTestHostManager CreateManager(IFileHelper fileHelper)
fileHelper,
new DotnetHostHelper(fileHelper, _mockEnvironment.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariable.Object, _mockProcessHelper.Object),
_mockEnvironment.Object,
_mockRunsettingsHelper.Object,
_mockWindowsRegistry.Object,
_mockEnvironmentVariable.Object);
}
Loading