Skip to content

Commit bb26385

Browse files
authored
Add output forwarding for .NET (#4988)
* Add output forwarding for .NET * Fix tests
1 parent 631ca02 commit bb26385

4 files changed

Lines changed: 39 additions & 10 deletions

File tree

src/Microsoft.TestPlatform.CoreUtilities/Helpers/DotnetHostHelper.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,8 +409,10 @@ public bool TryGetDotnetPathByArchitecture(
409409
using var headerReader = _fileHelper.GetStream(path, FileMode.Open, FileAccess.Read);
410410
var magicBytes = new byte[4];
411411
var cpuInfoBytes = new byte[4];
412+
#pragma warning disable CA2022 // Avoid inexact read with 'Stream.Read'
412413
headerReader.Read(magicBytes, 0, magicBytes.Length);
413414
headerReader.Read(cpuInfoBytes, 0, cpuInfoBytes.Length);
415+
#pragma warning restore CA2022 // Avoid inexact read with 'Stream.Read'
414416

415417
var magic = BitConverter.ToUInt32(magicBytes, 0);
416418
var cpuInfo = BitConverter.ToUInt32(cpuInfoBytes, 0);

src/Microsoft.TestPlatform.TestHostProvider/Hosting/DefaultTestHostManager.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public class DefaultTestHostManager : ITestRuntimeProvider2
6767
private StringBuilder? _testHostProcessStdOut;
6868
private IMessageLogger? _messageLogger;
6969
private bool _hostExitedEventRaised;
70-
private TestHostManagerCallbacks? _testhostManagerCallbacks;
70+
private TestHostManagerCallbacks? _testHostManagerCallbacks;
7171

7272
/// <summary>
7373
/// Initializes a new instance of the <see cref="DefaultTestHostManager"/> class.
@@ -124,7 +124,7 @@ internal DefaultTestHostManager(
124124
private Action<object?> ExitCallBack => process =>
125125
{
126126
TPDebug.Assert(_testHostProcessStdError is not null, "LaunchTestHostAsync must have been called before ExitCallBack");
127-
TPDebug.Assert(_testhostManagerCallbacks is not null, "Initialize must have been called before ExitCallBack");
127+
TPDebug.Assert(_testHostManagerCallbacks is not null, "Initialize must have been called before ExitCallBack");
128128
TestHostManagerCallbacks.ExitCallBack(_processHelper, process, _testHostProcessStdError, OnHostExited);
129129
};
130130

@@ -134,18 +134,18 @@ internal DefaultTestHostManager(
134134
private Action<object?, string?> ErrorReceivedCallback => (process, data) =>
135135
{
136136
TPDebug.Assert(_testHostProcessStdError is not null, "LaunchTestHostAsync must have been called before ErrorReceivedCallback");
137-
TPDebug.Assert(_testhostManagerCallbacks is not null, "Initialize must have been called before ErrorReceivedCallback");
138-
_testhostManagerCallbacks.ErrorReceivedCallback(_testHostProcessStdError, data);
137+
TPDebug.Assert(_testHostManagerCallbacks is not null, "Initialize must have been called before ErrorReceivedCallback");
138+
_testHostManagerCallbacks.ErrorReceivedCallback(_testHostProcessStdError, data);
139139
};
140140

141141
/// <summary>
142-
/// Gets callback to read from process error stream
142+
/// Gets callback to read from process standard stream
143143
/// </summary>
144144
private Action<object?, string?> OutputReceivedCallback => (process, data) =>
145145
{
146146
TPDebug.Assert(_testHostProcessStdOut is not null, "LaunchTestHostAsync must have been called before OutputReceivedCallback");
147-
TPDebug.Assert(_testhostManagerCallbacks is not null, "Initialize must have been called before OutputReceivedCallback");
148-
_testhostManagerCallbacks.StandardOutputReceivedCallback(_testHostProcessStdOut, data);
147+
TPDebug.Assert(_testHostManagerCallbacks is not null, "Initialize must have been called before OutputReceivedCallback");
148+
_testHostManagerCallbacks.StandardOutputReceivedCallback(_testHostProcessStdOut, data);
149149
};
150150

151151
/// <inheritdoc/>
@@ -371,7 +371,7 @@ public void Initialize(IMessageLogger? logger, string runsettingsXml)
371371
var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettingsXml);
372372

373373
_messageLogger = logger;
374-
_testhostManagerCallbacks = new TestHostManagerCallbacks(_environmentVariableHelper.GetEnvironmentVariable("VSTEST_EXPERIMENTAL_FORWARD_OUTPUT_FEATURE") == "1", logger);
374+
_testHostManagerCallbacks = new TestHostManagerCallbacks(_environmentVariableHelper.GetEnvironmentVariable("VSTEST_EXPERIMENTAL_FORWARD_OUTPUT_FEATURE") == "1", logger);
375375
_architecture = runConfiguration.TargetPlatform;
376376
_targetFramework = runConfiguration.TargetFramework;
377377
_testHostProcess = null;

src/Microsoft.TestPlatform.TestHostProvider/Hosting/DotnetTestHostManager.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,16 @@ public class DotnetTestHostManager : ITestRuntimeProvider2
6767
private ITestHostLauncher? _customTestHostLauncher;
6868
private Process? _testHostProcess;
6969
private StringBuilder? _testHostProcessStdError;
70+
private StringBuilder? _testHostProcessStdOut;
7071
private bool _hostExitedEventRaised;
7172
private string _hostPackageVersion = "15.0.0";
7273
private Architecture _architecture;
7374
private Framework? _targetFramework;
7475
private bool _isVersionCheckRequired = true;
7576
private string? _dotnetHostPath;
7677

78+
private protected TestHostManagerCallbacks? _testHostManagerCallbacks;
79+
7780
/// <summary>
7881
/// Initializes a new instance of the <see cref="DotnetTestHostManager"/> class.
7982
/// </summary>
@@ -169,13 +172,25 @@ private set
169172
private Action<object?, string?> ErrorReceivedCallback => (process, data) =>
170173
{
171174
TPDebug.Assert(_testHostProcessStdError is not null, "_testHostProcessStdError is null");
172-
new TestHostManagerCallbacks(false, null).ErrorReceivedCallback(_testHostProcessStdError, data);
175+
TPDebug.Assert(_testHostManagerCallbacks is not null, "Initialize must have been called before ExitCallBack");
176+
_testHostManagerCallbacks.ErrorReceivedCallback(_testHostProcessStdError, data);
177+
};
178+
179+
/// <summary>
180+
/// Gets callback to read from process standard stream
181+
/// </summary>
182+
private Action<object?, string?> OutputReceivedCallback => (process, data) =>
183+
{
184+
TPDebug.Assert(_testHostProcessStdOut is not null, "LaunchTestHostAsync must have been called before OutputReceivedCallback");
185+
TPDebug.Assert(_testHostManagerCallbacks is not null, "Initialize must have been called before OutputReceivedCallback");
186+
_testHostManagerCallbacks.StandardOutputReceivedCallback(_testHostProcessStdOut, data);
173187
};
174188

175189
/// <inheritdoc/>
176190
public void Initialize(IMessageLogger? logger, string runsettingsXml)
177191
{
178192
_hostExitedEventRaised = false;
193+
_testHostManagerCallbacks = new TestHostManagerCallbacks(_environmentVariableHelper.GetEnvironmentVariable("VSTEST_EXPERIMENTAL_FORWARD_OUTPUT_FEATURE") == "1", logger);
179194

180195
var runConfiguration = XmlRunSettingsUtilities.GetRunConfigurationNode(runsettingsXml);
181196
_architecture = runConfiguration.TargetPlatform;
@@ -706,6 +721,7 @@ private void OnHostExited(HostProviderEventArgs e)
706721
private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToken cancellationToken)
707722
{
708723
_testHostProcessStdError = new StringBuilder(0, CoreUtilities.Constants.StandardErrorMaxLength);
724+
_testHostProcessStdOut = new StringBuilder(0, CoreUtilities.Constants.StandardErrorMaxLength);
709725

710726
// We launch the test host process here if we're on the normal test running workflow.
711727
// If we're debugging and we have access to the newest version of the testhost launcher
@@ -729,7 +745,7 @@ private bool LaunchHost(TestProcessStartInfo testHostStartInfo, CancellationToke
729745
testHostStartInfo.EnvironmentVariables,
730746
ErrorReceivedCallback,
731747
ExitCallBack,
732-
null) as Process;
748+
OutputReceivedCallback) as Process;
733749
}
734750
else
735751
{

test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyOperationManagerTests.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
2222
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client;
2323
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Host;
24+
using Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging;
2425
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
2526
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;
2627
using Microsoft.VisualStudio.TestTools.UnitTesting;
@@ -357,6 +358,8 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredFalseShoul
357358
{
358359
SetUpMocksForDotNetTestHost();
359360
var testHostManager = new TestableDotnetTestHostManager(false, _mockProcessHelper.Object, _mockFileHelper.Object, _mockEnvironment.Object, _mockRunsettingHelper.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariableHelper.Object);
361+
testHostManager.Initialize(new NullMessageLogger(), DefaultRunSettings);
362+
360363
var operationManager = new TestableProxyOperationManager(_mockRequestData.Object, _mockRequestSender.Object, testHostManager);
361364

362365
operationManager.SetupChannel(Enumerable.Empty<string>(), DefaultRunSettings);
@@ -369,6 +372,7 @@ public void SetupChannelForDotnetHostManagerWithIsVersionCheckRequiredTrueShould
369372
{
370373
SetUpMocksForDotNetTestHost();
371374
var testHostManager = new TestableDotnetTestHostManager(true, _mockProcessHelper.Object, _mockFileHelper.Object, _mockEnvironment.Object, _mockRunsettingHelper.Object, _mockWindowsRegistry.Object, _mockEnvironmentVariableHelper.Object);
375+
testHostManager.Initialize(new NullMessageLogger(), DefaultRunSettings);
372376
var operationManager = new TestableProxyOperationManager(_mockRequestData.Object, _mockRequestSender.Object, testHostManager);
373377

374378
operationManager.SetupChannel(Enumerable.Empty<string>(), DefaultRunSettings);
@@ -587,3 +591,10 @@ public override TestProcessStartInfo GetTestHostProcessStartInfo(
587591
}
588592
}
589593
}
594+
595+
internal class NullMessageLogger : IMessageLogger
596+
{
597+
public void SendMessage(TestMessageLevel testMessageLevel, string message)
598+
{
599+
}
600+
}

0 commit comments

Comments
 (0)