Skip to content
Draft
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
4 changes: 2 additions & 2 deletions src/Cli/dotnet/Commands/Test/CliConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ internal static class HandshakeMessagePropertyNames
internal static class ProtocolConstants
{
/// <summary>
/// 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.
/// </summary>
internal const string SupportedVersions = "1.0.0";
internal static readonly string[] SupportedVersions = ["1.1.0", "1.0.0"];
}

internal static class ProjectProperties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down
43 changes: 30 additions & 13 deletions src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public async Task<int> 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.
Expand All @@ -69,7 +71,14 @@ public async Task<int> 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);

Expand All @@ -79,7 +88,14 @@ public async Task<int> 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);

Expand All @@ -97,7 +113,7 @@ public async Task<int> 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.
Expand Down Expand Up @@ -254,7 +270,7 @@ private Task<IResponse> 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:
Expand Down Expand Up @@ -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.
Expand All @@ -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)
{
Expand Down
27 changes: 16 additions & 11 deletions src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ internal sealed class TestApplicationHandler
private readonly Lock _lock = new();
private readonly Dictionary<string, (int TestSessionStartCount, int TestSessionEndCount)> _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)
Expand All @@ -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,
Expand All @@ -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.
Expand All @@ -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)
{
Expand Down Expand Up @@ -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,
Expand All @@ -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)
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -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)
{
Expand Down
Loading