Skip to content

Commit

Permalink
Write standard output and error, and respect execution id (#3934)
Browse files Browse the repository at this point in the history
  • Loading branch information
nohwnd authored Oct 14, 2024
1 parent cb555a1 commit dec5768
Show file tree
Hide file tree
Showing 22 changed files with 315 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ This package provides the core platform and the .NET implementation of the proto
<!-- end netstandard2.0 polyfill -->

<ItemGroup>
<InternalsVisibleTo Include="dotnet" Key="$(MicrosoftAspNetCorePublicKey)" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" Key="$(MoqPublicKey)" />
<InternalsVisibleTo Include="Microsoft.Testing.Extensions.CrashDump" Key="$(VsPublicKey)" />
<InternalsVisibleTo Include="Microsoft.Testing.Extensions.Experimental" Key="$(VsPublicKey)" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,12 @@ public void Render(AnsiTerminalTestProgressFrame previousFrame, AnsiTerminal ter
terminal.MoveCursorUp(previousFrame.ProgressCount + 2);
}

terminal.AppendLine();
// When there is nothing to render, don't write empty lines, e.g. when we start the test run, and then we kick off build
// in dotnet test, there is a long pause where we have no assemblies and no test results (yet).
if (ProgressCount > 0)
{
terminal.AppendLine();
}

int i = 0;
for (; i < ProgressCount; i++)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,16 @@ public void EraseProgress()

public void RenderProgress(TestProgressState?[] progress)
{
int count = 0;
foreach (TestProgressState? p in progress)
{
if (p == null)
{
continue;
}

count++;

string durationString = HumanReadableDurationFormatter.Render(p.Stopwatch.Elapsed);

int passed = p.PassedTests;
Expand Down Expand Up @@ -232,7 +235,11 @@ public void RenderProgress(TestProgressState?[] progress)
AppendLine();
}

AppendLine();
// Do not render empty lines when there is nothing to show.
if (count > 0)
{
AppendLine();
}
}

public void StartBusyIndicator()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void TestExecutionStarted(DateTimeOffset testStartTime, int workerCount)
_terminalWithProgress.StartShowingProgress(workerCount);
}

public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture)
public void AssemblyRunStarted(string assembly, string? targetFramework, string? architecture, string? executionId)
{
if (_options.ShowAssembly && _options.ShowAssemblyStartAndComplete)
{
Expand All @@ -151,12 +151,12 @@ public void AssemblyRunStarted(string assembly, string? targetFramework, string?
});
}

GetOrAddAssemblyRun(assembly, targetFramework, architecture);
GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
}

private TestProgressState GetOrAddAssemblyRun(string assembly, string? targetFramework, string? architecture)
private TestProgressState GetOrAddAssemblyRun(string assembly, string? targetFramework, string? architecture, string? executionId)
{
string key = $"{assembly}|{targetFramework}|{architecture}";
string key = $"{assembly}|{targetFramework}|{architecture}|{executionId}";
if (_assemblies.TryGetValue(key, out TestProgressState? asm))
{
return asm;
Expand Down Expand Up @@ -369,15 +369,18 @@ internal void TestCompleted(
string assembly,
string? targetFramework,
string? architecture,
string? executionId,
string displayName,
TestOutcome outcome,
TimeSpan duration,
string? errorMessage,
string? errorStackTrace,
string? expected,
string? actual)
string? actual,
string? standardOutput,
string? errorOutput)
{
TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}"];
TestProgressState asm = _assemblies[$"{assembly}|{targetFramework}|{architecture}|{executionId}"];

switch (outcome)
{
Expand Down Expand Up @@ -412,7 +415,9 @@ internal void TestCompleted(
errorMessage,
errorStackTrace,
expected,
actual));
actual,
standardOutput,
errorOutput));
}
}

Expand All @@ -427,7 +432,9 @@ internal void TestCompleted(
string? errorMessage,
string? errorStackTrace,
string? expected,
string? actual)
string? actual,
string? standardOutput,
string? errorOutput)
{
if (outcome == TestOutcome.Passed && !_options.ShowPassedTests)
{
Expand Down Expand Up @@ -472,6 +479,7 @@ internal void TestCompleted(
FormatErrorMessage(terminal, errorMessage);
FormatExpectedAndActual(terminal, expected, actual);
FormatStackTrace(terminal, errorStackTrace);
FormatStandardAndErrorOutput(terminal, standardOutput, errorOutput);
}

private static void AppendAssemblyLinkTargetFrameworkAndArchitecture(ITerminal terminal, string assembly, string? targetFramework, string? architecture)
Expand Down Expand Up @@ -621,9 +629,9 @@ private static void AppendIndentedLine(ITerminal terminal, string? message, stri
}
}

internal void AssemblyRunCompleted(string assembly, string? targetFramework, string? architecture)
internal void AssemblyRunCompleted(string assembly, string? targetFramework, string? architecture, string? executionId)
{
TestProgressState assemblyRun = GetOrAddAssemblyRun(assembly, targetFramework, architecture);
TestProgressState assemblyRun = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
assemblyRun.Stopwatch.Stop();

_terminalWithProgress.RemoveWorker(assemblyRun.SlotIndex);
Expand All @@ -634,6 +642,30 @@ internal void AssemblyRunCompleted(string assembly, string? targetFramework, str
}
}

private static void FormatStandardAndErrorOutput(ITerminal terminal, string? standardOutput, string? standardError)
{
if (RoslynString.IsNullOrWhiteSpace(standardOutput) && RoslynString.IsNullOrWhiteSpace(standardError))
{
return;
}

terminal.SetColor(TerminalColor.DarkGray);
terminal.Append(SingleIndentation);
terminal.AppendLine(PlatformResources.StandardOutput);
string? standardOutputWithoutSpecialChars = NormalizeSpecialCharacters(standardOutput);
AppendIndentedLine(terminal, standardOutputWithoutSpecialChars, DoubleIndentation);
terminal.Append(SingleIndentation);
terminal.AppendLine(PlatformResources.StandardError);
string? standardErrorWithoutSpecialChars = NormalizeSpecialCharacters(standardError);
AppendIndentedLine(terminal, standardErrorWithoutSpecialChars, DoubleIndentation);
terminal.ResetColor();
}

private static string? NormalizeSpecialCharacters(string? text)
=> text?.Replace('\0', '\x2400')
// escape char
.Replace('\x001b', '\x241b');

private static void AppendAssemblySummary(TestProgressState assemblyRun, ITerminal terminal)
{
int failedTests = assemblyRun.FailedTests;
Expand All @@ -644,6 +676,7 @@ private static void AppendAssemblySummary(TestProgressState assemblyRun, ITermin
AppendAssemblyResult(terminal, assemblyRun.FailedTests == 0, failedTests, warnings);
terminal.Append(' ');
AppendLongDuration(terminal, assemblyRun.Stopwatch.Elapsed);
terminal.AppendLine();
}

/// <summary>
Expand All @@ -666,8 +699,8 @@ private static void AppendLongDuration(ITerminal terminal, TimeSpan duration, bo

public void Dispose() => _terminalWithProgress.Dispose();

public void ArtifactAdded(bool outOfProcess, string? assembly, string? targetFramework, string? architecture, string? testName, string path)
=> _artifacts.Add(new TestRunArtifact(outOfProcess, assembly, targetFramework, architecture, testName, path));
public void ArtifactAdded(bool outOfProcess, string? assembly, string? targetFramework, string? architecture, string? executionId, string? testName, string path)
=> _artifacts.Add(new TestRunArtifact(outOfProcess, assembly, targetFramework, architecture, executionId, testName, path));

/// <summary>
/// Let the user know that cancellation was triggered.
Expand All @@ -683,9 +716,9 @@ internal void StartCancelling()
});
}

internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string text, int? padding)
internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string? executionId, string text, int? padding)
{
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture);
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
asm.AddError(text);

_terminalWithProgress.WriteToTerminal(terminal =>
Expand All @@ -704,9 +737,9 @@ internal void WriteErrorMessage(string assembly, string? targetFramework, string
});
}

internal void WriteWarningMessage(string assembly, string? targetFramework, string? architecture, string text, int? padding)
internal void WriteWarningMessage(string assembly, string? targetFramework, string? architecture, string? executionId, string text, int? padding)
{
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture);
TestProgressState asm = GetOrAddAssemblyRun(assembly, targetFramework, architecture, executionId);
asm.AddWarning(text);
_terminalWithProgress.WriteToTerminal(terminal =>
{
Expand All @@ -724,8 +757,8 @@ internal void WriteWarningMessage(string assembly, string? targetFramework, stri
});
}

internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, Exception exception)
=> WriteErrorMessage(assembly, targetFramework, architecture, exception.ToString(), padding: null);
internal void WriteErrorMessage(string assembly, string? targetFramework, string? architecture, string? executionId, Exception exception)
=> WriteErrorMessage(assembly, targetFramework, architecture, executionId, exception.ToString(), padding: null);

internal void WriteMessage(string text, SystemConsoleColor? color = null, int? padding = null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ namespace Microsoft.Testing.Platform.OutputDevice.Terminal;
/// <summary>
/// An artifact / attachment that was reported during run.
/// </summary>
internal record TestRunArtifact(bool OutOfProcess, string? Assembly, string? TargetFramework, string? Architecture, string? TestName, string Path);
internal record TestRunArtifact(bool OutOfProcess, string? Assembly, string? TargetFramework, string? Architecture, string? ExecutionId, string? TestName, string Path);
Loading

0 comments on commit dec5768

Please sign in to comment.