Skip to content

Commit 3e0b7be

Browse files
committed
Avoid plugging in TerminalOutputDevice when running with pipe protocol
1 parent 7192356 commit 3e0b7be

5 files changed

Lines changed: 53 additions & 19 deletions

File tree

src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -207,9 +207,12 @@ public async Task<IHost> BuildAsync(
207207
serviceProvider.AddService(policiesService);
208208

209209
bool hasServerFlag = commandLineHandler.TryGetOptionArgumentList(PlatformCommandLineProvider.ServerOptionKey, out string[]? protocolName);
210-
bool isJsonRpcProtocol = protocolName is null || protocolName.Length == 0 || protocolName[0].Equals(PlatformCommandLineProvider.JsonRpcProtocolName, StringComparison.OrdinalIgnoreCase);
210+
bool isJsonRpcProtocol = hasServerFlag &&
211+
(protocolName is null || protocolName.Length == 0 || protocolName[0].Equals(PlatformCommandLineProvider.JsonRpcProtocolName, StringComparison.OrdinalIgnoreCase));
211212

212-
ProxyOutputDevice proxyOutputDevice = await _outputDisplay.BuildAsync(serviceProvider, hasServerFlag && isJsonRpcProtocol).ConfigureAwait(false);
213+
bool isPipeProtocol = hasServerFlag && protocolName?.Length == 1 && protocolName[1].Equals(PlatformCommandLineProvider.DotnetTestCliProtocolName, StringComparison.Ordinal);
214+
215+
ProxyOutputDevice proxyOutputDevice = await _outputDisplay.BuildAsync(serviceProvider, isJsonRpcProtocol, isPipeProtocol).ConfigureAwait(false);
213216

214217
// Add FileLoggerProvider if needed
215218
if (loggingState.FileLoggerProvider is not null)
@@ -433,7 +436,7 @@ await LogTestHostCreatedAsync(
433436
&& !commandLineHandler.IsOptionSet(PlatformCommandLineProvider.DiscoverTestsOptionKey))
434437
{
435438
PassiveNode? passiveNode = null;
436-
if (hasServerFlag && isJsonRpcProtocol)
439+
if (isJsonRpcProtocol)
437440
{
438441
// Build the IMessageHandlerFactory for the PassiveNode
439442
IMessageHandlerFactory messageHandlerFactory = ServerModeManager.Build(serviceProvider);
@@ -507,7 +510,7 @@ await LogTestHostCreatedAsync(
507510
serviceProvider.AddServices(testApplicationLifecycleCallback);
508511

509512
// ServerMode and Console mode uses different host
510-
if (hasServerFlag && isJsonRpcProtocol)
513+
if (isJsonRpcProtocol)
511514
{
512515
// Build the server mode with the user preferences
513516
IMessageHandlerFactory messageHandlerFactory = ServerModeManager.Build(serviceProvider);

src/Platform/Microsoft.Testing.Platform/OutputDevice/OutputDeviceManager.cs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,20 @@ public void SetPlatformOutputDevice(Func<IServiceProvider, IPlatformOutputDevice
2020
_platformOutputDeviceFactory = platformOutputDeviceFactory;
2121
}
2222

23-
internal async Task<ProxyOutputDevice> BuildAsync(ServiceProvider serviceProvider, bool useServerModeOutputDevice)
23+
internal async Task<ProxyOutputDevice> BuildAsync(ServiceProvider serviceProvider, bool useServerModeOutputDevice, bool isPipeProtocol)
2424
{
2525
// TODO: SetPlatformOutputDevice isn't public yet.
2626
// Before exposing it, do we want to pass the "useServerModeOutputDevice" info to it?
27-
IPlatformOutputDevice nonServerOutputDevice = _platformOutputDeviceFactory is null
28-
? GetDefaultTerminalOutputDevice(serviceProvider)
27+
IPlatformOutputDevice? nonServerOutputDevice = _platformOutputDeviceFactory is null
28+
? GetDefaultTerminalOutputDevice(serviceProvider, isPipeProtocol)
2929
: _platformOutputDeviceFactory(serviceProvider);
3030

3131
// If the externally provided output device is not enabled, we opt-in the default terminal output device.
32-
if (_platformOutputDeviceFactory is not null && !await nonServerOutputDevice.IsEnabledAsync().ConfigureAwait(false))
32+
if (_platformOutputDeviceFactory is not null
33+
&& nonServerOutputDevice is not null &&
34+
!await nonServerOutputDevice.IsEnabledAsync().ConfigureAwait(false))
3335
{
34-
nonServerOutputDevice = GetDefaultTerminalOutputDevice(serviceProvider);
36+
nonServerOutputDevice = GetDefaultTerminalOutputDevice(serviceProvider, isPipeProtocol);
3537
}
3638

3739
return new ProxyOutputDevice(
@@ -43,8 +45,13 @@ internal async Task<ProxyOutputDevice> BuildAsync(ServiceProvider serviceProvide
4345
: null);
4446
}
4547

46-
public static IPlatformOutputDevice GetDefaultTerminalOutputDevice(ServiceProvider serviceProvider)
48+
private static IPlatformOutputDevice? GetDefaultTerminalOutputDevice(ServiceProvider serviceProvider, bool isPipeProtocol)
4749
{
50+
if (isPipeProtocol)
51+
{
52+
return null;
53+
}
54+
4855
if (OperatingSystem.IsBrowser())
4956
{
5057
#if NET7_0_OR_GREATER

src/Platform/Microsoft.Testing.Platform/OutputDevice/ProxyOutputDevice.cs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,21 @@ internal sealed class ProxyOutputDevice : IOutputDevice
1111
{
1212
private readonly ServerModePerCallOutputDevice? _serverModeOutputDevice;
1313

14-
public ProxyOutputDevice(IPlatformOutputDevice originalOutputDevice, ServerModePerCallOutputDevice? serverModeOutputDevice)
14+
public ProxyOutputDevice(IPlatformOutputDevice? originalOutputDevice, ServerModePerCallOutputDevice? serverModeOutputDevice)
1515
{
1616
OriginalOutputDevice = originalOutputDevice;
1717
_serverModeOutputDevice = serverModeOutputDevice;
1818
}
1919

20-
internal IPlatformOutputDevice OriginalOutputDevice { get; }
20+
internal IPlatformOutputDevice? OriginalOutputDevice { get; }
2121

2222
public async Task DisplayAsync(IOutputDeviceDataProducer producer, IOutputDeviceData data, CancellationToken cancellationToken)
2323
{
24-
await OriginalOutputDevice.DisplayAsync(producer, data, cancellationToken).ConfigureAwait(false);
24+
if (OriginalOutputDevice is not null)
25+
{
26+
await OriginalOutputDevice.DisplayAsync(producer, data, cancellationToken).ConfigureAwait(false);
27+
}
28+
2529
if (_serverModeOutputDevice is not null)
2630
{
2731
await _serverModeOutputDevice.DisplayAsync(producer, data, cancellationToken).ConfigureAwait(false);
@@ -30,7 +34,11 @@ public async Task DisplayAsync(IOutputDeviceDataProducer producer, IOutputDevice
3034

3135
internal async Task DisplayBannerAsync(string? bannerMessage, CancellationToken cancellationToken)
3236
{
33-
await OriginalOutputDevice.DisplayBannerAsync(bannerMessage, cancellationToken).ConfigureAwait(false);
37+
if (OriginalOutputDevice is not null)
38+
{
39+
await OriginalOutputDevice.DisplayBannerAsync(bannerMessage, cancellationToken).ConfigureAwait(false);
40+
}
41+
3442
if (_serverModeOutputDevice is not null)
3543
{
3644
await _serverModeOutputDevice.DisplayBannerAsync(bannerMessage, cancellationToken).ConfigureAwait(false);
@@ -39,7 +47,11 @@ internal async Task DisplayBannerAsync(string? bannerMessage, CancellationToken
3947

4048
internal async Task DisplayBeforeSessionStartAsync(CancellationToken cancellationToken)
4149
{
42-
await OriginalOutputDevice.DisplayBeforeSessionStartAsync(cancellationToken).ConfigureAwait(false);
50+
if (OriginalOutputDevice is not null)
51+
{
52+
await OriginalOutputDevice.DisplayBeforeSessionStartAsync(cancellationToken).ConfigureAwait(false);
53+
}
54+
4355
if (_serverModeOutputDevice is not null)
4456
{
4557
await _serverModeOutputDevice.DisplayBeforeSessionStartAsync(cancellationToken).ConfigureAwait(false);
@@ -48,7 +60,11 @@ internal async Task DisplayBeforeSessionStartAsync(CancellationToken cancellatio
4860

4961
internal async Task DisplayAfterSessionEndRunAsync(CancellationToken cancellationToken)
5062
{
51-
await OriginalOutputDevice.DisplayAfterSessionEndRunAsync(cancellationToken).ConfigureAwait(false);
63+
if (OriginalOutputDevice is not null)
64+
{
65+
await OriginalOutputDevice.DisplayAfterSessionEndRunAsync(cancellationToken).ConfigureAwait(false);
66+
}
67+
5268
if (_serverModeOutputDevice is not null)
5369
{
5470
await _serverModeOutputDevice.DisplayAfterSessionEndRunAsync(cancellationToken).ConfigureAwait(false);
@@ -65,7 +81,11 @@ internal async Task InitializeAsync(ServerTestHost serverTestHost)
6581

6682
internal async Task HandleProcessRoleAsync(TestProcessRole processRole, CancellationToken cancellationToken)
6783
{
68-
await OriginalOutputDevice.HandleProcessRoleAsync(processRole, cancellationToken).ConfigureAwait(false);
84+
if (OriginalOutputDevice is not null)
85+
{
86+
await OriginalOutputDevice.HandleProcessRoleAsync(processRole, cancellationToken).ConfigureAwait(false);
87+
}
88+
6989
if (_serverModeOutputDevice is not null)
7090
{
7191
await _serverModeOutputDevice.HandleProcessRoleAsync(processRole, cancellationToken).ConfigureAwait(false);

src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/DotnetTestConnection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ public async Task<bool> IsCompatibleProtocolAsync(string hostType)
9292
{
9393
RoslynDebug.Assert(_dotnetTestPipeClient is not null);
9494

95-
string supportedProtocolVersions = ProtocolConstants.Version;
95+
const string supportedProtocolVersions = ProtocolConstants.SupportedVersions;
9696
HandshakeMessage handshakeMessage = new(new Dictionary<byte, string>
9797
{
9898
{ HandshakeMessagePropertyNames.PID, _environment.ProcessId.ToString(CultureInfo.InvariantCulture) },

src/Platform/Microsoft.Testing.Platform/ServerMode/DotnetTest/IPC/Constants.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,9 @@ internal static class HandshakeMessagePropertyNames
3737

3838
internal static class ProtocolConstants
3939
{
40-
internal const string Version = "1.0.0";
40+
// The change between 1.0.0 and 1.0.1 is that TerminalOutputDevice is no longer plugged in.
41+
// That's not really a protocol change, but we use the version to signify to SDK that it can avoid output redirection.
42+
// So, when SDK declares itself as supporting 1.0.1, and MTP is also using 1.0.1, and we negotiate to that version.
43+
// Then SDK can assume that MTP output doesn't interfere with SDK output, and we can safely let live output to work.
44+
internal const string SupportedVersions = "1.0.0;1.0.1";
4145
}

0 commit comments

Comments
 (0)