Skip to content

Deduplicate ExecutionId/InstanceId envelope across DotnetTest IPC serializers#9820

Merged
Evangelink merged 3 commits into
mainfrom
dev/amauryleve/jubilant-adventure
Jul 10, 2026
Merged

Deduplicate ExecutionId/InstanceId envelope across DotnetTest IPC serializers#9820
Evangelink merged 3 commits into
mainfrom
dev/amauryleve/jubilant-adventure

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Fixes #9812.

Summary

Four dotnet test IPC serializers — DiscoveredTestMessagesSerializer, TestResultMessagesSerializer, TestInProgressMessagesSerializer, and FileArtifactMessagesSerializer — shared an identical top-level ExecutionId/InstanceId envelope in their DeserializeCore/SerializeCore methods (the same ExecutionId/InstanceId switch cases + field-count/write scaffolding, ~18 lines per serializer). This PR extracts that shared scaffold.

Changes

  • Added two stateless static helpers to the shared BaseSerializer (IPC/Serializers/BaseSerializer.cs):
    • ReadExecutionScopedFields(...) — reads the leading ExecutionId (id 1) / InstanceId (id 2) string fields and delegates every other field id to a caller-supplied payload reader, returning the two envelope values.
    • WriteExecutionScopedFields(...) — writes the field-count prefix, the ExecutionId/InstanceId fields, then invokes a payload writer.
  • Refactored the four serializers to use the helpers and dropped their now-redundant top-level GetFieldCount(<Messages>) methods (the per-message-item GetFieldCount overloads are unchanged).
  • Updated the tracked InternalAPI.Unshipped.txt for the platform and the extension projects that embed these shared-source serializers.

The helpers are stateless (the serializers are registered as singletons), so no shared mutable state is introduced.

Wire compatibility

The field ids (ExecutionId=1, InstanceId=2, message lists), their order and layout are unchanged — this is a pure code-dedup refactor. These files are also vendored into dotnet/sdk, so the round-trip contract is preserved.

Verification

  • Microsoft.Testing.Platform.DotnetTestProtocolContract.UnitTests (standalone shared-source round-trip contract): 21/21 passed.
  • Microsoft.Testing.Platform.UnitTests ProtocolTests + ProtocolEdgeCaseTests: 33/33 passed.
  • Full solution/analyzer build succeeds (0 warnings, 0 errors).

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

…ializers

Introduce shared ReadExecutionScopedFields/WriteExecutionScopedFields helpers on
BaseSerializer and refactor DiscoveredTestMessagesSerializer, TestResultMessagesSerializer,
TestInProgressMessagesSerializer and FileArtifactMessagesSerializer to use them. The
top-level ExecutionId/InstanceId (+ message list) serialize/deserialize scaffold was
duplicated verbatim across all four; the wire format is unchanged.

Fixes #9812

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 10, 2026 09:40

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

Deduplicates execution-scoped envelope handling across four dotnet test IPC serializers while preserving wire compatibility.

Changes:

  • Adds shared read/write envelope helpers.
  • Refactors four serializers to use them.
  • Updates tracked internal API declarations.
Show a summary per file
File Description
BaseSerializer.cs Adds shared envelope helpers.
DiscoveredTestMessagesSerializer.cs Uses shared envelope handling.
TestResultMessagesSerializer.cs Uses shared envelope handling.
TestInProgressMessagesSerializer.cs Uses shared envelope handling.
FileArtifactMessagesSerializer.cs Uses shared envelope handling.
Microsoft.Testing.Platform/InternalAPI/net/InternalAPI.Unshipped.txt Tracks new helper APIs.
Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txt Tracks new helper APIs.
Microsoft.Testing.Extensions.TrxReport/InternalAPI/InternalAPI.Unshipped.txt Tracks shared-source APIs.
Microsoft.Testing.Extensions.Retry/InternalAPI/InternalAPI.Unshipped.txt Tracks shared-source APIs.
Microsoft.Testing.Extensions.MSBuild/InternalAPI.Unshipped.txt Tracks shared-source APIs.
Microsoft.Testing.Extensions.HangDump/InternalAPI/InternalAPI.Unshipped.txt Tracks shared-source APIs.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs Outdated

@github-actions github-actions Bot 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.

Note

🤖 Automated review by GitHub Copilot. Generated by the Expert Code Review workflow. To request a follow-up action, reply by tagging @copilot directly.

Review Summary

Clean dedup refactor — the wire format is preserved, the helpers are stateless, and the field-id constants match all four serializers. No issues found.

# Dimension Verdict
1 Correctness ✅ Pass — field ids 1/2 match all four *FieldsId classes; read/write logic is equivalent to the inlined original.
2 Bug risk ✅ Pass — no behavioral change.
3 Edge cases ✅ Pass — null ExecutionId/InstanceId handled identically (conditional field count + WriteField no-ops on null).
4 Security ✅ N/A — no auth, no user input parsing changes.
5 Performance ✅ Pass — one extra delegate allocation per call, but serializers are not hot-path; acceptable.
6 Concurrency ✅ Pass — helpers are stateless static; no shared mutable state.
7 Error handling ✅ Pass — unchanged from original.
8 API design ✅ Pass — protected static scope is appropriate; tuple return is idiomatic.
9 Naming ✅ Pass — ReadExecutionScopedFields/WriteExecutionScopedFields clearly describe purpose.
10 Documentation ✅ Pass — XML docs on both helpers; inline comment explains wire-id contract.
11 Style / formatting ✅ Pass — consistent with codebase conventions.
12 DRY / duplication ✅ Pass — this is the point of the PR; duplication eliminated.
13 Testability ✅ Pass — existing serializer round-trip tests cover the refactored paths.
14 Backward compat ✅ Pass — wire ids and layout unchanged; vendored-into-SDK contract preserved.
15 Public API surface ✅ Pass — InternalAPI.Unshipped.txt updated in all 6 locations.
16 Localization ✅ N/A
17 Logging / diagnostics ✅ N/A
18 Disposal / resources ✅ N/A
19 Configuration ✅ N/A
20 Dependencies ✅ Pass — no new dependencies.
21 TODOs ✅ Pass — none introduced.
22 Test coverage ✅ Pass — covered by existing IPC serializer unit tests.

Overall: No issues. Straightforward and safe dedup refactor.

Minor observation (non-blocking): DisplayMessageSerializer and AzureDevOpsLogMessageSerializer share the same ExecutionId=1/InstanceId=2 envelope pattern but weren't included in this refactor. Could be a follow-up if desired.

@Evangelink Evangelink added the state/needs-review Awaiting review from the team. label Jul 10, 2026
…ssages

Address PR review: AzureDevOpsLogMessage/DisplayMessage also place ExecutionId/InstanceId
at ids 1/2 but carry scalar payloads and don't use these helpers, so narrow the wording
to the four collection envelopes.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 10, 2026 12:57

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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment thread src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs Outdated
Comment thread src/Platform/Microsoft.Testing.Platform/IPC/Serializers/BaseSerializer.cs Outdated
Address PR review: the callback-based ReadExecutionScopedFields/WriteExecutionScopedFields
added a closure/delegate allocation per serialized/deserialized envelope on the per-test
IPC path. Replace them with closure-free helpers:
- TryReadExecutionScopedField(ref executionId, ref instanceId): a ref-based field matcher
  the caller invokes from its own single ReadFields lambda (no second closure; same one
  closure as before the dedup).
- WriteExecutionScopedHeader(...): writes the field count + ExecutionId/InstanceId header,
  after which the caller writes its payload directly (no callback).

Wire format unchanged; contract + protocol round-trip tests pass.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 10, 2026 13:31

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.

Review details

  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@Evangelink Evangelink merged commit f19af28 into main Jul 10, 2026
40 of 46 checks passed
@Evangelink Evangelink deleted the dev/amauryleve/jubilant-adventure branch July 10, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-review Awaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicated ExecutionId/InstanceId Envelope Pattern Across 4 DotnetTest IPC Serializers

3 participants