diff --git a/src/Cli/dotnet/Commands/Test/CliConstants.cs b/src/Cli/dotnet/Commands/Test/CliConstants.cs index 9fb46e3a91ff..9e04272229b7 100644 --- a/src/Cli/dotnet/Commands/Test/CliConstants.cs +++ b/src/Cli/dotnet/Commands/Test/CliConstants.cs @@ -60,9 +60,9 @@ internal static class HandshakeMessagePropertyNames internal static class ProtocolConstants { /// - /// The protocol versions that are supported by the current SDK. Multiple versions can be present and be semicolon separated. + /// The protocol versions that are supported by the current SDK. Must be ordered from highest version to lowest version. /// - internal const string SupportedVersions = "1.0.0"; + internal static readonly string[] SupportedVersions = ["1.1.0", "1.0.0"]; } internal static class ProjectProperties diff --git a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs index ca8ea35e2d57..d0dd95057842 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs @@ -753,7 +753,7 @@ internal void AssemblyRunCompleted(string executionId, }); } - internal void HandshakeFailure(string assemblyPath, string? targetFramework, int exitCode, string outputData, string errorData) + internal void HandshakeFailure(string assemblyPath, string? targetFramework, int exitCode, string? outputData, string? errorData) { if (_isHelp) { diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs index d5d733a17044..b7df12f3e915 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs @@ -54,6 +54,8 @@ public async Task RunAsync() using var process = Process.Start(processStartInfo)!; + int exitCode; + // Reading from process stdout/stderr is done on separate threads to avoid blocking IO on the threadpool. // Note: even with 'process.StandardOutput.ReadToEndAsync()' or 'process.BeginOutputReadLine()', we ended up with // many TP threads just doing synchronous IO, slowing down the progress of the test run. @@ -69,7 +71,14 @@ public async Task RunAsync() string? currentLine; while ((currentLine = stdOut.ReadLine()) is not null) { - stdOutBuilder.Enqueue(currentLine); + if (_handler.ShouldHideOutputAndError) + { + stdOutBuilder.Enqueue(currentLine); + } + else + { + Console.WriteLine(currentLine); + } } }, TaskCreationOptions.LongRunning); @@ -79,7 +88,14 @@ public async Task RunAsync() string? currentLine; while ((currentLine = stdErr.ReadLine()) is not null) { - stdErrBuilder.Enqueue(currentLine); + if (_handler.ShouldHideOutputAndError) + { + stdErrBuilder.Enqueue(currentLine); + } + else + { + Console.WriteLine(currentLine); + } } }, TaskCreationOptions.LongRunning); @@ -97,7 +113,7 @@ public async Task RunAsync() { } - var exitCode = process.ExitCode; + exitCode = process.ExitCode; _handler.OnTestProcessExited(exitCode, string.Join(Environment.NewLine, stdOutBuilder), string.Join(Environment.NewLine, stdErrBuilder)); // This condition is to prevent considering the test app as successful when we didn't receive test session end. @@ -254,7 +270,7 @@ private Task OnRequest(NamedPipeServer server, IRequest request) case HandshakeMessage handshakeMessage: _handshakes.Add(server, handshakeMessage); string negotiatedVersion = GetSupportedProtocolVersion(handshakeMessage); - OnHandshakeMessage(handshakeMessage, negotiatedVersion.Length > 0); + OnHandshakeMessage(handshakeMessage, negotiatedVersion); return Task.FromResult((IResponse)CreateHandshakeMessage(negotiatedVersion)); case CommandLineOptionMessages commandLineOptionMessages: @@ -317,14 +333,15 @@ private static string GetSupportedProtocolVersion(HandshakeMessage handshakeMess return string.Empty; } - // NOTE: Today, ProtocolConstants.Version is only 1.0.0 (i.e, SDK supports only a single version). - // Whenever we support multiple versions in SDK, we should do intersection - // between protocolVersions given by MTP, and the versions supported by SDK. - // Then we return the "highest" version from the intersection. - // The current logic **assumes** that ProtocolConstants.SupportedVersions is a single version. - if (protocolVersions.Split(";").Contains(ProtocolConstants.SupportedVersions)) + // ProtocolConstant.SupportedVersions is the SDK supported versions, ordered from highest version to lowest version. + // So, we take the first highest version that is also supported by MTP. + var protocolVersionsByMTP = protocolVersions.Split(";"); + foreach (var sdkSupportedVersion in ProtocolConstants.SupportedVersions) { - return ProtocolConstants.SupportedVersions; + if (protocolVersionsByMTP.Contains(sdkSupportedVersion)) + { + return sdkSupportedVersion; + } } // The version given by MTP is not supported by SDK. @@ -341,8 +358,8 @@ private static HandshakeMessage CreateHandshakeMessage(string version) => { HandshakeMessagePropertyNames.SupportedProtocolVersions, version } }); - public void OnHandshakeMessage(HandshakeMessage handshakeMessage, bool gotSupportedVersion) - => _handler.OnHandshakeReceived(handshakeMessage, gotSupportedVersion); + public void OnHandshakeMessage(HandshakeMessage handshakeMessage, string negotiatedVersion) + => _handler.OnHandshakeReceived(handshakeMessage, negotiatedVersion); private void OnCommandLineOptionMessages(CommandLineOptionMessages commandLineOptionMessages) { diff --git a/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs b/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs index 9735d0ab72b2..c35dae3166c1 100644 --- a/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs +++ b/src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs @@ -14,7 +14,7 @@ internal sealed class TestApplicationHandler private readonly Lock _lock = new(); private readonly Dictionary _testSessionEventCountPerSessionUid = new(); - private (string? TargetFramework, string? Architecture, string ExecutionId)? _handshakeInfo; + private (string? TargetFramework, string? Architecture, string ExecutionId, string NegotiatedVersion)? _handshakeInfo; private bool _receivedTestHostHandshake; public TestApplicationHandler(TerminalTestReporter output, TestModule module, TestOptions options) @@ -24,11 +24,15 @@ public TestApplicationHandler(TerminalTestReporter output, TestModule module, Te _options = options; } - internal void OnHandshakeReceived(HandshakeMessage handshakeMessage, bool gotSupportedVersion) + // Only 1.0.0 hides the output. + // Otherwise, TerminalTestReporter of the test app will interfere with the output of the test command. + internal bool ShouldHideOutputAndError => _handshakeInfo.HasValue && _handshakeInfo.Value.NegotiatedVersion == "1.0.0"; + + internal void OnHandshakeReceived(HandshakeMessage handshakeMessage, string negotiatedVersion) { LogHandshake(handshakeMessage); - if (!gotSupportedVersion) + if (negotiatedVersion.Length == 0) { _output.HandshakeFailure( _module.TargetPath, @@ -37,7 +41,7 @@ internal void OnHandshakeReceived(HandshakeMessage handshakeMessage, bool gotSup string.Format( CliCommandStrings.DotnetTestIncompatibleHandshakeVersion, handshakeMessage.Properties[HandshakeMessagePropertyNames.SupportedProtocolVersions], - ProtocolConstants.SupportedVersions), + string.Join(';', ProtocolConstants.SupportedVersions)), string.Empty); // Protocol version is not supported. @@ -48,7 +52,7 @@ internal void OnHandshakeReceived(HandshakeMessage handshakeMessage, bool gotSup var executionId = handshakeMessage.Properties[HandshakeMessagePropertyNames.ExecutionId]; var arch = handshakeMessage.Properties[HandshakeMessagePropertyNames.Architecture]?.ToLower(); var tfm = TargetFrameworkParser.GetShortTargetFramework(handshakeMessage.Properties[HandshakeMessagePropertyNames.Framework]); - var currentHandshakeInfo = (tfm, arch, executionId); + var currentHandshakeInfo = (tfm, arch, executionId, negotiatedVersion); if (!_handshakeInfo.HasValue) { @@ -137,6 +141,7 @@ internal void OnTestResultsReceived(TestResultMessages testResultMessage) } var handshakeInfo = _handshakeInfo.Value; + var shouldHide = ShouldHideOutputAndError; foreach (var testResult in testResultMessage.SuccessfulTestMessages) { _output.TestCompleted(_module.TargetPath, handshakeInfo.TargetFramework, handshakeInfo.Architecture, handshakeInfo.ExecutionId, @@ -149,8 +154,8 @@ internal void OnTestResultsReceived(TestResultMessages testResultMessage) exceptions: null, expected: null, actual: null, - standardOutput: testResult.StandardOutput, - errorOutput: testResult.ErrorOutput); + standardOutput: shouldHide ? testResult.StandardOutput : null, + errorOutput: shouldHide ? testResult.ErrorOutput : null); } foreach (var testResult in testResultMessage.FailedTestMessages) @@ -164,8 +169,8 @@ internal void OnTestResultsReceived(TestResultMessages testResultMessage) exceptions: [.. testResult.Exceptions!.Select(fe => new Terminal.FlatException(fe.ErrorMessage, fe.ErrorType, fe.StackTrace))], expected: null, actual: null, - standardOutput: testResult.StandardOutput, - errorOutput: testResult.ErrorOutput); + standardOutput: shouldHide ? testResult.StandardOutput : null, + errorOutput: shouldHide ? testResult.ErrorOutput : null); } } @@ -263,7 +268,7 @@ internal bool HasMismatchingTestSessionEventCount() return false; } - internal void OnTestProcessExited(int exitCode, string outputData, string errorData) + internal void OnTestProcessExited(int exitCode, string? outputData, string? errorData) { if (_receivedTestHostHandshake && _handshakeInfo.HasValue) { @@ -378,7 +383,7 @@ private static void LogFileArtifacts(FileArtifactMessages fileArtifactMessages) Logger.LogTrace(logMessageBuilder, static logMessageBuilder => logMessageBuilder.ToString()); } - private static void LogTestProcessExit(int exitCode, string outputData, string errorData) + private static void LogTestProcessExit(int exitCode, string? outputData, string? errorData) { if (!Logger.TraceEnabled) {