Skip to content

Add MTP artifact post-processing to dotnet test - #55419

Merged
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/mtp-artifact-post-processing
Jul 23, 2026
Merged

Add MTP artifact post-processing to dotnet test#55419
Evangelink merged 2 commits into
mainfrom
dev/amauryleve/mtp-artifact-post-processing

Conversation

@Evangelink

@Evangelink Evangelink commented Jul 22, 2026

Copy link
Copy Markdown
Member

Multi-module Microsoft.Testing.Platform runs currently report one artifact per test application, leaving users with many TRX or coverage files. This adds SDK-side orchestration for the TestFX artifact post-processing protocol so compatible artifacts are consolidated before the final dotnet test summary.

The implementation:

  • bumps TestFX to the build containing the post-processing contract, handshake capabilities, artifact kind metadata, and hidden dispatcher tool
  • collects capabilities and attributed artifacts during normal test execution
  • computes a deterministic minimal set-cover to relaunch the fewest compatible test applications
  • invokes the hidden dispatcher with a versioned manifest and replaces consumed originals only after merged artifacts return over the existing pipe
  • preserves original artifacts and the test run exit code when post-processing fails, times out, or is unavailable
  • supports mixed tagged and legacy extension-based artifacts

Merged report naming

TRX post-processing writes merged-{runId:N}.trx. TestFX derives runId by hashing the ordered normalized input paths together with their execution IDs. This keeps the name deterministic within an invocation while giving separate dotnet test invocations distinct names, even when they share a results directory. The end-to-end test runs the same solution twice into one directory and verifies that both merged reports are preserved without collision.

Adds planner, protocol, reporter, failure-path, mixed-version, naming-collision, and end-to-end TRX merge coverage.

Relates to #47613

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a56f3957-e35c-47df-bad9-c5f342ee302a
Copilot AI review requested due to automatic review settings July 22, 2026 21:22
@Evangelink
Evangelink requested review from a team as code owners July 22, 2026 21:22
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).
2 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds SDK-side orchestration for Microsoft.Testing.Platform (MTP) artifact post-processing during dotnet test, enabling consolidation of multi-module artifacts (e.g., TRX) before the final summary is printed.

Changes:

  • Introduces artifact post-processing planning/execution (capability + artifact metadata capture, deterministic planning, dispatcher relaunch, and summary artifact replacement).
  • Updates MTP execution pipeline (new IsArtifactPostProcessing mode, handshake/host-type validation, artifact collection hooks, and reporter artifact removal support).
  • Adds unit and end-to-end tests for the planner/manager/handler and TRX merge behavior; bumps TestFX/TestPlatform/MSTest versions and adds new localized strings.
Show a summary per file
File Description
test/dotnet.Tests/CommandTests/Test/TestApplicationHandlerTests.cs Adds handler tests for post-processing capability/artifact capture and failure-path behavior.
test/dotnet.Tests/CommandTests/Test/GivenDotnetTestBuildsAndRunsArtifactPostProcessingMTP.cs End-to-end test validating TRX consolidation behavior and output reporting.
test/dotnet.Tests/CommandTests/Test/ArtifactPostProcessingPlannerTests.cs Unit tests for the planner’s grouping, coverage, and set-cover selection logic.
test/dotnet.Tests/CommandTests/Test/ArtifactPostProcessingManagerTests.cs Unit tests for applying merged outputs and consuming originals in the reporter.
src/Cli/dotnet/Commands/Test/MTP/TestApplicationHandler.cs Adds post-processing handshake host-type validation and routes artifact messages into manager/invocation.
src/Cli/dotnet/Commands/Test/MTP/TestApplicationActionQueue.cs Threads the post-processing manager through test application execution.
src/Cli/dotnet/Commands/Test/MTP/TestApplication.cs Adds post-processing launch mode/args, timeout behavior, and launch-settings suppression for tool runs.
src/Cli/dotnet/Commands/Test/MTP/Terminal/TerminalTestReporter.cs Makes artifact tracking thread-safe and adds RemoveArtifacts for post-processed consolidation.
src/Cli/dotnet/Commands/Test/MTP/Options.cs Extends TestOptions with IsArtifactPostProcessing.
src/Cli/dotnet/Commands/Test/MTP/MicrosoftTestingPlatformTestCommand.cs Executes post-processing after test runs complete (when applicable).
src/Cli/dotnet/Commands/Test/MTP/ArtifactPostProcessingPlanner.cs New planner: groups artifacts and computes a deterministic minimal job set.
src/Cli/dotnet/Commands/Test/MTP/ArtifactPostProcessingManager.cs New manager: records capabilities/artifacts, runs dispatcher tool jobs, and applies merged outputs.
src/Cli/dotnet/Commands/Test/CliConstants.cs Adds protocol constants for post-processing tool name/options, handshake host type, and capability properties.
src/Cli/dotnet/Commands/CliCommandStrings.resx Adds new user-facing strings for post-processing failures and host-type mismatch.
src/Cli/dotnet/Commands/xlf/CliCommandStrings.*.xlf Updates localized string entries corresponding to the new resx strings.
global.json Bumps MSTest.Sdk version to match the updated TestFX build.
eng/Version.Details.xml Bumps Microsoft.Testing.Platform/MSTest/MSTest.Sdk dependency versions and SHA.
eng/Version.Details.props Updates the corresponding version properties for the TestFX packages.

Copilot's findings

  • Files reviewed: 30/30 changed files
  • Comments generated: 0

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a56f3957-e35c-47df-bad9-c5f342ee302a
@Evangelink
Evangelink enabled auto-merge July 23, 2026 07:37
@Evangelink
Evangelink merged commit 5e25224 into main Jul 23, 2026
28 checks passed
@Evangelink
Evangelink deleted the dev/amauryleve/mtp-artifact-post-processing branch July 23, 2026 14:15
@Evangelink

Copy link
Copy Markdown
Member Author

/backport to release/11.0.1xx-preview7

@github-actions

Copy link
Copy Markdown
Contributor

Started backporting to release/11.0.1xx-preview7 (link to workflow run)

@dotnet-milestone-bot dotnet-milestone-bot Bot added this to the 11.0-rc1 milestone Jul 24, 2026
Evangelink added a commit to microsoft/testfx that referenced this pull request Jul 28, 2026
…orts

Bumps global.json (tools.dotnet + sdk.version) to 11.0.100-preview.7.26376.106.
That build carries the SDK-side artifact post-processing orchestration
(dotnet/sdk#55419, backported to release/11.0.1xx-preview7 as dotnet/sdk#55453),
which flowed into the VMR via '[release/11.0.1xx-preview7] Source code updates
from dotnet/sdk' (dotnet/dotnet#7944), so RFC 018 phase 2 now actually runs for
this repo's multi-module 'dotnet test' invocations.

Enabling it surfaced a problem that is not specific to this repo. The SDK points
the processor's output directory at the run's --results-directory, which already
holds the per-module reports the merge consumed, so TrxArtifactPostProcessor was
writing the merged report as a sibling of its own inputs. Collecting a results
directory with a non-recursive '*.trx' glob is near-universal (Arcade's 'Publish
TRX Test Results' step, the PublishTestResults@2 defaults, typical
ReportGenerator setups), and every such consumer would ingest both the merged
report and the reports it summarizes, double-counting every test.

TrxArtifactPostProcessor now writes to '<outputDirectory>/merged/', which keeps
the merged report out of those globs by construction instead of asking each
consumer to special-case the merged file name.

Nesting also keeps the report co-located with its attachments, which a
CI-side move could not. MergeToFileAsync derives the attachment deployment root
from the output path and records it in the TRX as a relative runDeploymentRoot,
so the report and its attachment tree have to stay in the same directory for
those references to resolve; writing the report into the subdirectory moves both
together. Adds a regression test covering that, and asserting nothing of the
merged report is left in the results-directory root.

Verified end to end on this SDK: two MTP modules (23 + 2 tests) run through
'dotnet test' with a shared --results-directory produce
'merged/merged-<runId>.trx' with total=25, reported back over the existing pipe
as an out-of-process file artifact, with the per-module reports left intact at
the root and nothing else matching a non-recursive '*.trx' glob there.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4a6c06b2-7dcb-407e-bb9e-ca0c8302fa93
Evangelink added a commit to microsoft/testfx that referenced this pull request Jul 28, 2026
…orts

Bumps global.json (tools.dotnet + sdk.version) to 11.0.100-preview.7.26376.106.
That build carries the SDK-side artifact post-processing orchestration
(dotnet/sdk#55419, backported to release/11.0.1xx-preview7 as dotnet/sdk#55453),
which flowed into the VMR via '[release/11.0.1xx-preview7] Source code updates
from dotnet/sdk' (dotnet/dotnet#7944), so RFC 018 phase 2 now actually runs for
this repo's multi-module 'dotnet test' invocations.

Enabling it surfaced a problem that is not specific to this repo. The SDK points
the processor's output directory at the run's --results-directory, which already
holds the per-module reports the merge consumed, so TrxArtifactPostProcessor was
writing the merged report as a sibling of its own inputs. Collecting a results
directory with a non-recursive '*.trx' glob is near-universal (Arcade's 'Publish
TRX Test Results' step, the PublishTestResults@2 defaults, typical
ReportGenerator setups), and every such consumer would ingest both the merged
report and the reports it summarizes, double-counting every test.

TrxArtifactPostProcessor now writes to '<outputDirectory>/merged/', which keeps
the merged report out of those globs by construction instead of asking each
consumer to special-case the merged file name.

Nesting also keeps the report co-located with its attachments, which a
CI-side move could not. MergeToFileAsync derives the attachment deployment root
from the output path and records it in the TRX as a relative runDeploymentRoot,
so the report and its attachment tree have to stay in the same directory for
those references to resolve; writing the report into the subdirectory moves both
together. Adds a regression test covering that, and asserting nothing of the
merged report is left in the results-directory root.

Verified end to end on this SDK: two MTP modules (23 + 2 tests) run through
'dotnet test' with a shared --results-directory produce
'merged/merged-<runId>.trx' with total=25, reported back over the existing pipe
as an out-of-process file artifact, with the per-module reports left intact at
the root and nothing else matching a non-recursive '*.trx' glob there.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4a6c06b2-7dcb-407e-bb9e-ca0c8302fa93
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants