diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/CommandDefinitionStrings.resx b/src/Cli/Microsoft.DotNet.Cli.Definitions/CommandDefinitionStrings.resx
index 9645faf1db54..225cf839c4b0 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/CommandDefinitionStrings.resx
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/CommandDefinitionStrings.resx
@@ -494,6 +494,9 @@ This is equivalent to deleting project.assets.json.
Disable Http Caching for packages.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
Disable progress reporting.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs b/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs
index 8862525d8418..61ff9e11af13 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/Commands/Test/TestCommandDefinition.MicrosoftTestingPlatform.cs
@@ -133,6 +133,12 @@ public sealed partial class MicrosoftTestingPlatform : TestCommandDefinition, IC
Arity = ArgumentArity.Zero
};
+ public readonly Option NoArtifactPostProcessingOption = new("--no-artifact-post-processing")
+ {
+ Description = CommandDefinitionStrings.CmdNoArtifactPostProcessingDescription,
+ Arity = ArgumentArity.Zero
+ };
+
public readonly Option OutputOption = new("--output")
{
Description = CommandDefinitionStrings.CmdTestOutputDescription,
@@ -215,6 +221,7 @@ public MicrosoftTestingPlatform()
Options.Add(UseCurrentRuntimeOption);
Options.Add(NoAnsiOption);
Options.Add(NoProgressOption);
+ Options.Add(NoArtifactPostProcessingOption);
Options.Add(OutputOption);
Options.Add(ListTestsOption);
Options.Add(NoLaunchProfileOption);
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.cs.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.cs.xlf
index 06000cb8f219..7aec231e2ddb 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.cs.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.cs.xlf
@@ -439,6 +439,11 @@ Jedná se o ekvivalent odstranění project.assets.json.
Zakáže výstup ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Nesestavujte projekt, dokud ho neotestujete. Implikuje možnost --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.de.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.de.xlf
index 83979a8c32b6..7d88f7c7a435 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.de.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.de.xlf
@@ -439,6 +439,11 @@ Dies entspricht dem Löschen von "project.assets.json".
Deaktivieren Sie die ANSI-Ausgabe.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Erstellt das Projekt nicht vor dem Testen. Impliziert "--no-restore".
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.es.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.es.xlf
index e85ecdec78c8..38b8bad076ec 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.es.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.es.xlf
@@ -439,6 +439,11 @@ Esta acción es equivalente a eliminar project.assets.json.
Deshabilite la salida ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.No compile el proyecto antes de probarlo. Implica --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.fr.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.fr.xlf
index 48890e4a1dbf..9acc94604593 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.fr.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.fr.xlf
@@ -439,6 +439,11 @@ Cela équivaut à supprimer project.assets.json.
Désactivez la sortie ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Ne pas générer le projet avant les tests. Implique --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.it.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.it.xlf
index b48974079e2b..3e1d85e7e905 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.it.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.it.xlf
@@ -439,6 +439,11 @@ Equivale a eliminare project.assets.json.
Disabilita l'output ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Non compila il progetto prima del test. Implica --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ja.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ja.xlf
index 789645e7aeff..4628143f0a2c 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ja.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ja.xlf
@@ -439,6 +439,11 @@ This is equivalent to deleting project.assets.json.
ANSI 出力を無効にします。
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.テストする前にプロジェクトをビルドしないでください。--no-restore を意味します。
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ko.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ko.xlf
index 39a7e14d7881..6720cec7cbf1 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ko.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ko.xlf
@@ -439,6 +439,11 @@ project.assets.json을 삭제하는 것과 동일합니다.
ANSI 출력을 비활성화합니다.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.테스트하기 전에 프로젝트를 빌드하지 않습니다. 복원 없음을 의미합니다.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pl.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pl.xlf
index 68aac5510e09..700dc031935d 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pl.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pl.xlf
@@ -439,6 +439,11 @@ Jest to równoważne usunięciu pliku project.assets.json.
Wyłącz dane wyjściowe ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Nie kompiluj tego projektu przed testowaniem. Powoduje przyjęcie, że podano parametr --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pt-BR.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pt-BR.xlf
index 7b285cd2bd81..b56b9668c9e2 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pt-BR.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.pt-BR.xlf
@@ -439,6 +439,11 @@ Isso equivale a excluir o project.assets.json.
Desabilite a saída ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Não compile o projeto antes de testar. Implica em --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ru.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ru.xlf
index c6f28a7d1221..a70352c370ba 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ru.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.ru.xlf
@@ -439,6 +439,11 @@ This is equivalent to deleting project.assets.json.
Отключить вывод ANSI.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Сборка проекта перед тестированием не выполняется. Подразумевает --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.tr.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.tr.xlf
index bce3188757f2..eb7fd2553d10 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.tr.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.tr.xlf
@@ -439,6 +439,11 @@ project.assets.json öğesini silmeyle eşdeğerdir.
ANSI çıkışını devre dışı bırakın.
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.Test etmeden önce projeyi derlemeyin. --no-restore anlamına gelir.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hans.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hans.xlf
index 15b4af011561..b5d44694133a 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hans.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hans.xlf
@@ -439,6 +439,11 @@ This is equivalent to deleting project.assets.json.
禁用 ANSI 输出。
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.测试之前不要生成项目。Implies --no-restore.
diff --git a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hant.xlf b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hant.xlf
index 702ac70b0e3d..137e54b25716 100644
--- a/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hant.xlf
+++ b/src/Cli/Microsoft.DotNet.Cli.Definitions/xlf/CommandDefinitionStrings.zh-Hant.xlf
@@ -439,6 +439,11 @@ This is equivalent to deleting project.assets.json.
停用 ANSI 輸出。
+
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+ Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications.
+
+ Do not build the project before testing. Implies --no-restore.請勿在測試之前建置專案。提示:-no-restore。
diff --git a/src/Cli/dotnet/Commands/Test/MTP/ArtifactPostProcessingManager.cs b/src/Cli/dotnet/Commands/Test/MTP/ArtifactPostProcessingManager.cs
index 45029f9aed6b..ed60d21429cb 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/ArtifactPostProcessingManager.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/ArtifactPostProcessingManager.cs
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.ComponentModel;
using System.Globalization;
using System.Text.Json;
using Microsoft.DotNet.Cli.Commands.Test.IPC.Models;
@@ -112,7 +111,7 @@ public async Task ExecuteAsync(
if (invocation.FailureMessage is { } failureMessage)
{
- output.WriteWarningMessage(string.Format(
+ ReportFailureUnlessCancelled(output, ctrlC, string.Format(
CultureInfo.CurrentCulture,
CliCommandStrings.ArtifactPostProcessingFailed,
job.Application.Module.TargetPath,
@@ -120,21 +119,21 @@ public async Task ExecuteAsync(
}
else if (exitCode != ExitCode.Success)
{
- output.WriteWarningMessage(string.Format(
+ ReportFailureUnlessCancelled(output, ctrlC, string.Format(
CultureInfo.CurrentCulture,
CliCommandStrings.ArtifactPostProcessingProcessFailed,
job.Application.Module.TargetPath,
exitCode));
}
}
- catch (Exception ex) when (ex is IOException
- or UnauthorizedAccessException
- or InvalidOperationException
- or Win32Exception
- or NotSupportedException
- or TimeoutException)
+ catch (Exception ex)
{
- output.WriteWarningMessage(string.Format(
+ // Post-processing is a best-effort convenience on top of a completed test run: the
+ // original artifacts are always still on disk and still reported, so no failure here
+ // may escape and turn a finished run into a CLI crash with a different exit code.
+ Logger.LogTrace($"Artifact post-processing with '{job.Application.Module.TargetPath}' failed: {ex}");
+
+ ReportFailureUnlessCancelled(output, ctrlC, string.Format(
CultureInfo.CurrentCulture,
CliCommandStrings.ArtifactPostProcessingFailed,
job.Application.Module.TargetPath,
@@ -157,6 +156,24 @@ or NotSupportedException
}
}
+ ///
+ /// Reports a post-processing failure, unless the user cancelled the run. Cancellation kills the
+ /// post-processing process the same way it kills a test application, so the resulting failure is
+ /// the cancellation the user asked for rather than a post-processing problem worth reporting.
+ ///
+ internal static void ReportFailureUnlessCancelled(
+ TerminalTestReporter output,
+ CtrlCCancellationManager ctrlC,
+ string message)
+ {
+ if (ctrlC.Token.IsCancellationRequested)
+ {
+ return;
+ }
+
+ output.WriteWarningMessage(message);
+ }
+
internal IReadOnlyList SnapshotApplications()
{
lock (_lock)
diff --git a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs
index b0fa329d6aa8..6a4f98087c43 100644
--- a/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs
+++ b/src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs
@@ -116,7 +116,10 @@ public int Run(ParseResult parseResult, bool isHelp)
exitCode = ExitCode.TestSessionAborted;
}
- if (!testOptions.IsHelp && !testOptions.IsDiscovery && !ctrlC.Token.IsCancellationRequested)
+ if (!testOptions.IsHelp
+ && !testOptions.IsDiscovery
+ && !parseResult.GetValue(definition.NoArtifactPostProcessingOption)
+ && !ctrlC.Token.IsCancellationRequested)
{
artifactPostProcessingManager.ExecuteAsync(buildOptions, output, ctrlC).GetAwaiter().GetResult();
}
diff --git a/test/dotnet.Tests/CommandTests/Test/ArtifactPostProcessingManagerTests.cs b/test/dotnet.Tests/CommandTests/Test/ArtifactPostProcessingManagerTests.cs
index 1de00153a755..f546c93c8d93 100644
--- a/test/dotnet.Tests/CommandTests/Test/ArtifactPostProcessingManagerTests.cs
+++ b/test/dotnet.Tests/CommandTests/Test/ArtifactPostProcessingManagerTests.cs
@@ -1,8 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+using Microsoft.DotNet.Cli.Commands;
using Microsoft.DotNet.Cli.Commands.Run;
using Microsoft.DotNet.Cli.Commands.Test;
+using Microsoft.DotNet.Cli.Commands.Test.IPC.Models;
using Microsoft.DotNet.Cli.Commands.Test.Terminal;
using TestExitCode = Microsoft.DotNet.Cli.Commands.Test.ExitCode;
@@ -129,6 +131,135 @@ public void GetArtifactPostProcessingLaunchArguments_AppHost_UsesNoTestArguments
arguments.Should().BeEmpty();
}
+ [TestMethod]
+ public async Task ExecuteAsync_WhenJobFailsUnexpectedly_ReportsWarningWithoutThrowing()
+ {
+ var console = new CapturingConsole();
+ using var reporter = CreateReporter(console);
+ // A NUL character makes Path.GetFullPath throw ArgumentException while planning the job.
+ // ArgumentException is outside the exception set this code used to catch, so before the
+ // catch-all it escaped ExecuteAsync and crashed a 'dotnet test' run that had already
+ // completed, replacing its exit code.
+ ArtifactPostProcessingManager manager = CreateManagerWithMergeableArtifacts("first\0.trx", "second\0.trx");
+ using var ctrlC = CreateCancellationManager();
+
+ await manager.ExecuteAsync(CreateBuildOptions(), reporter, ctrlC);
+ reporter.TestExecutionCompleted(DateTimeOffset.UtcNow, TestExitCode.Success);
+
+ console.GetOutput().Should().Contain(
+ FormatPrefix(CliCommandStrings.ArtifactPostProcessingFailed, "A.dll"),
+ "the failure must degrade to a warning instead of escaping");
+ }
+
+ ///
+ /// Formats a two-placeholder message up to its second placeholder, so an assertion can match the
+ /// reported message without depending on the exception text that fills the placeholder.
+ ///
+ private static string FormatPrefix(string format, string firstArgument)
+ => string.Format(format, firstArgument, "\u0001").Split('\u0001')[0];
+
+ [TestMethod]
+ public async Task ExecuteAsync_WhenCancelledBeforeStarting_RunsNoJobs()
+ {
+ var console = new CapturingConsole();
+ using var reporter = CreateReporter(console);
+ ArtifactPostProcessingManager manager = CreateManagerWithMergeableArtifacts("first.trx", "second.trx");
+ using var ctrlC = CreateCancellationManager();
+ ctrlC.SimulateCtrlC();
+ // Running a job creates its results directory before anything else is attempted, so the
+ // directory staying absent is the observable proof that no job ran. Asserting on the absence
+ // of a warning would not be: a job that ran and failed is silent too, because the failure of
+ // a cancelled run is deliberately not reported.
+ string resultsDirectory = Path.Combine(
+ Path.GetTempPath(),
+ $"dotnet-test-postproc-tests-{Guid.NewGuid():N}");
+
+ try
+ {
+ await manager.ExecuteAsync(CreateBuildOptions(resultsDirectory), reporter, ctrlC);
+
+ Directory.Exists(resultsDirectory).Should().BeFalse(
+ "a cancelled run must not start the jobs it planned");
+ }
+ finally
+ {
+ if (Directory.Exists(resultsDirectory))
+ {
+ Directory.Delete(resultsDirectory, recursive: true);
+ }
+ }
+ }
+
+ [TestMethod]
+ public void ReportFailureUnlessCancelled_WhenNotCancelled_WritesWarning()
+ {
+ var console = new CapturingConsole();
+ using var reporter = CreateReporter(console);
+ using var ctrlC = CreateCancellationManager();
+
+ ArtifactPostProcessingManager.ReportFailureUnlessCancelled(reporter, ctrlC, "post-processing warning");
+
+ console.GetOutput().Should().Contain("post-processing warning");
+ }
+
+ [TestMethod]
+ public void ReportFailureUnlessCancelled_WhenCancelled_WritesNothing()
+ {
+ var console = new CapturingConsole();
+ using var reporter = CreateReporter(console);
+ using var ctrlC = CreateCancellationManager();
+ // Cancellation kills the post-processing process, so its failure is the cancellation the
+ // user asked for rather than a post-processing problem worth reporting.
+ ctrlC.SimulateCtrlC();
+
+ ArtifactPostProcessingManager.ReportFailureUnlessCancelled(reporter, ctrlC, "post-processing warning");
+
+ console.GetOutput().Should().NotContain("post-processing warning");
+ }
+
+ private static ArtifactPostProcessingManager CreateManagerWithMergeableArtifacts(params string[] artifactPaths)
+ {
+ var manager = new ArtifactPostProcessingManager();
+ TestModule module = CreateModule();
+ manager.RecordCapabilities(
+ module,
+ "net10.0",
+ "x64",
+ new HandshakeMessage(new Dictionary
+ {
+ [HandshakeMessagePropertyNames.SupportedPostProcessorKinds] = "microsoft.testing.trx",
+ }));
+
+ foreach (string artifactPath in artifactPaths)
+ {
+ manager.RecordArtifact(
+ module,
+ "net10.0",
+ "x64",
+ "execution-1",
+ new FileArtifactMessage(artifactPath, "TRX", null, null, null, null, "microsoft.testing.trx"));
+ }
+
+ return manager;
+ }
+
+ private static CtrlCCancellationManager CreateCancellationManager()
+ => new(onFirstCtrlC: () => { }, exitAction: _ => { }, subscribeToConsole: false);
+
+ private static BuildOptions CreateBuildOptions(string? resultsDirectory = null)
+ => new(
+ new PathOptions(null, null, null, ResultsDirectoryPath: resultsDirectory, null, null),
+ HasNoRestore: false,
+ HasNoBuild: false,
+ Verbosity: null,
+ NoLaunchProfile: false,
+ NoLaunchProfileArguments: false,
+ TestApplicationArguments: [],
+ MSBuildArgs: [],
+ Device: null,
+ ListDevices: false,
+ EnvironmentVariables: new Dictionary());
+
private static TerminalTestReporter CreateReporter(CapturingConsole console)
{
var reporter = new TerminalTestReporter(console, new TerminalTestReporterOptions
@@ -147,7 +278,16 @@ private static TerminalTestReporter CreateReporter(CapturingConsole console)
private static ArtifactPostProcessingApplication CreateApplication()
{
- var module = new TestModule(
+ return new ArtifactPostProcessingApplication(
+ CreateModule(),
+ "net10.0",
+ "x64",
+ new HashSet(StringComparer.Ordinal) { "microsoft.testing.trx", "microsoft.codecoverage" },
+ new HashSet(StringComparer.Ordinal));
+ }
+
+ private static TestModule CreateModule()
+ => new(
new RunProperties("dotnet", "A.dll", null),
ProjectFullPath: null,
TargetFramework: "net10.0",
@@ -156,13 +296,6 @@ private static ArtifactPostProcessingApplication CreateApplication()
TargetPath: "A.dll",
DotnetRootArchVariableName: null,
EnvironmentVariables: new Dictionary());
- return new ArtifactPostProcessingApplication(
- module,
- "net10.0",
- "x64",
- new HashSet(StringComparer.Ordinal) { "microsoft.testing.trx", "microsoft.codecoverage" },
- new HashSet(StringComparer.Ordinal));
- }
private static ArtifactPostProcessingArtifact CreateArtifact(string path, string? kind)
=> new(path, kind, "A.dll", "net10.0", "x64", Guid.NewGuid().ToString("N"));
diff --git a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsArtifactPostProcessingMTP.cs b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsArtifactPostProcessingMTP.cs
index 68a9731b1d15..1bb91fe9f9d3 100644
--- a/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsArtifactPostProcessingMTP.cs
+++ b/test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsArtifactPostProcessingMTP.cs
@@ -44,13 +44,40 @@ public void MultiProjectRun_MergesTrxArtifacts()
mergedTrx.Descendants(ns + "Counters").Single().Attribute("total")!.Value.Should().Be("5");
}
- private CommandResult Run(string workingDirectory, string resultsDirectory)
- => new DotnetTestCommand(Log, disableNewOutput: false)
+ [TestMethod]
+ public void MultiProjectRun_WithNoArtifactPostProcessing_KeepsOneReportPerTestApplication()
+ {
+ TestAsset testInstance = TestAssetsManager
+ .CopyTestAsset("MultiTestProjectSolutionWithTests", Guid.NewGuid().ToString())
+ .WithSource();
+ EnableTrxReport(testInstance.Path);
+ string resultsDirectory = Path.Combine(testInstance.Path, "TestResults");
+
+ CommandResult result = Run(testInstance.Path, resultsDirectory, "--no-artifact-post-processing");
+
+ result.ExitCode.Should().Be(
+ ExitCodes.AtLeastOneTestFailed,
+ $"the test output was:{Environment.NewLine}{result.StdOut}{Environment.NewLine}{result.StdErr}");
+
+ string[] trxReports = Directory.GetFiles(resultsDirectory, "*.trx", SearchOption.AllDirectories);
+ trxReports.Should().HaveCount(2, "no test application is relaunched to merge the reports");
+ trxReports.Should().NotContain(path => Path.GetFileName(path).StartsWith("merged-", StringComparison.Ordinal));
+ }
+
+ private CommandResult Run(string workingDirectory, string resultsDirectory, params string[] additionalArguments)
+ {
+ string[] arguments =
+ [
+ "--report-trx",
+ "--results-directory", resultsDirectory,
+ "--configuration", TestingConstants.Debug,
+ .. additionalArguments
+ ];
+
+ return new DotnetTestCommand(Log, disableNewOutput: false)
.WithWorkingDirectory(workingDirectory)
- .Execute(
- "--report-trx",
- "--results-directory", resultsDirectory,
- "--configuration", TestingConstants.Debug);
+ .Execute(arguments);
+ }
private static string GetMergedTrxPath(CommandResult result)
{
diff --git a/test/dotnet.Tests/CommandTests/Test/snapshots/MTPHelpSnapshotTests.VerifyMTPHelpOutput.verified.txt b/test/dotnet.Tests/CommandTests/Test/snapshots/MTPHelpSnapshotTests.VerifyMTPHelpOutput.verified.txt
index 5e3f844bf320..8ec0dd17f5b8 100644
--- a/test/dotnet.Tests/CommandTests/Test/snapshots/MTPHelpSnapshotTests.VerifyMTPHelpOutput.verified.txt
+++ b/test/dotnet.Tests/CommandTests/Test/snapshots/MTPHelpSnapshotTests.VerifyMTPHelpOutput.verified.txt
@@ -41,6 +41,7 @@ Options:
--ucr, --use-current-runtime Use current runtime as the target runtime. [default: False]
--no-ansi Disable ANSI output. [default: False]
--no-progress Disable progress reporting. [default: False]
+ --no-artifact-post-processing Do not merge compatible artifacts, such as TRX reports or code coverage files, produced by different test applications. [default: False]
--output Verbosity of test output.
--list-tests List the discovered tests instead of running the tests. Optionally accepts a format: 'text' (default) for human-readable output or 'json' for machine-readable output.
--no-launch-profile Do not attempt to use launchSettings.json or [app].run.json to configure the application. [default: False]