Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in) - #9743

Merged
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest
Jul 8, 2026
Merged

Native MTP framework for MSTest — Phases 3–5 (native filter/runsettings/context, opt-in)#9743
Amaury Levé (Evangelink) merged 4 commits into
mainfrom
dev/amauryleve/remove-vstest-bridge-mstest

Conversation

@Evangelink

Copy link
Copy Markdown
Member

Follow-up to #9706 (RFC 018 + Phases 1–2, merged). Continues retiring the Microsoft.Testing.Extensions.VSTestBridge dependency from MSTest's Microsoft.Testing.Platform (MTP) code path. Everything is behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP switch, so the shipping default (the bridge) is unchanged.

What

A native MSTestTestFramework : ITestFramework, IDataProducer that handles the MTP discovery/run request directly and reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine — removing all VSTest bridge object-model adapters (RunContextAdapter, DiscoveryContextAdapter, FrameworkHandlerAdapter, RunSettingsAdapter, TestCaseDiscoverySinkAdapter, MessageLoggerAdapter) from the native request path.

New (all #if !WINDOWS_UWP):

  • MSTestFilterContext (MSTestRunContext / MSTestDiscoveryContext) — native IRunContext / IDiscoveryContext that builds the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings <TestCaseFilter> (reusing Microsoft.TestPlatform.Filter.Source, now referenced directly). MSTest's existing TestMethodFilter matching is unchanged.
  • MSTestRunSettings — native IRunSettings: reads runsettings, patches MTP defaults (DesignMode / ResultsDirectory / --test-parameter), and warns on unsupported entries (reusing the bridge's already-localized ExtensionResources).
  • MSTestFrameworkHandle — an IFrameworkHandle that only forwards messages to IOutputDevice (results flow through the native MtpTestResultRecorder).
  • MSTestTestFramework — session lifecycle + request handling; drives discovery/execution through the native seams from Native MTP integration for MSTest — RFC 018 + Phases 1–5 (opt-in native path) #9706.

AddMSTest branches the framework factory on the flag. The bridge's shared command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework), and the now-unused Phase 2 SessionUid helper is removed from the bridge base.

Validation

  • Full .\build.cmd — 0 warnings, 0 errors across all TFMs (rebased onto current main).
  • Unit tests: 45 (MSTestAdapter.UnitTests) + 898 (MSTestAdapter.PlatformServices.UnitTests), all green.
  • Native path (flag on, acceptance):185 tests green — FilterTests, RunsettingsTests (incl. localization), OutputTests, TrxReportTests, ThreadingTests (STA), ServerModeTests, DeploymentItem, DataSourceTests, Inconclusive/Ignore, TestRunParameters, TimeoutTests.
  • Default bridge path (flag off, acceptance):FilterTests + RunsettingsTests (45) — unchanged.

Remaining — Phase 6 (separate, gated)

Flip the default to native and drop the VSTestBridge dependency from MSTest. Gated on (1) full MSTest acceptance-suite parity on the native path (needs CI) and (2) native replacements for the bridge's remaining shared registrations (the --filter/--settings/--test-parameter option providers and the runsettings config/env-var providers) so the package reference can be removed.

The bridge package itself is not removed — NUnit/Expecto/3rd-party adapters still use it.

…t, opt-in)
Replaces the VSTest bridge framework on the opt-in native path (MSTEST_EXPERIMENTAL_NATIVE_MTP) with a native MSTestTestFramework that handles the MTP discovery/run requests directly — no VSTest bridge object-model adapters (RunContextAdapter/DiscoveryContextAdapter/FrameworkHandlerAdapter/RunSettingsAdapter/TestCaseDiscoverySinkAdapter/MessageLoggerAdapter) on the request path.
New (all #if !WINDOWS_UWP, reusing MSTest's existing MSTestDiscoverer/MSTestExecutor engine):
- MSTestTestFramework: ITestFramework + IDataProducer + single-session lifecycle; builds native context/runsettings/handle and drives discovery/execution via the Phase 1 seams (MtpUnitTestElementSink/MtpTestResultRecorder).
- MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext): native IRunContext/IDiscoveryContext building the VSTest ITestCaseFilterExpression from the MTP ITestExecutionFilter + --filter + runsettings TestCaseFilter (reuses Microsoft.TestPlatform.Filter.Source, now referenced directly).
- MSTestRunSettings: native IRunSettings (runsettings read + MTP patching: DesignMode/ResultsDirectory/--test-parameter + unsupported-entry warnings), reusing the bridge's already-localized ExtensionResources.
- MSTestFrameworkHandle: IFrameworkHandle that only forwards messages to IOutputDevice (results go through the recorder).
AddMSTest branches the framework factory on the flag; the bridge's command-line/config/env-var registrations are kept for now (retired with the dependency in the final step). MSTestBridgedTestFramework reverts to pure-bridge (native production now lives in the native framework).
Validated: full build 0/0; unit tests 45 + 898; native-path acceptance 185 (filter, runsettings incl. localization, output, trx, threading/STA, server mode, deployment, data-driven, outcomes, test-parameters, timeouts); default bridge-path acceptance 45 unchanged.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:13

CopilotAI 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

This PR is a follow-up to #9706 that continues the phased migration of MSTest's Microsoft.Testing.Platform (MTP) integration away from the Microsoft.Testing.Extensions.VSTestBridge object model. It introduces a nativeMSTestTestFramework (implementing ITestFramework/IDataProducer directly) that reuses MSTest's existing MSTestDiscoverer/MSTestExecutor engine and builds filter/runsettings/framework-handle context natively. Everything remains behind the opt-in MSTEST_EXPERIMENTAL_NATIVE_MTP environment switch, so the shipping default (the bridged framework) is unchanged. The new native classes are faithful ports of the corresponding bridge adapters (ContextAdapterBase, RunSettingsAdapter/RunSettingsPatcher/RunSettingsHelpers, MessageLoggerAdapter), and the previously-added Phase 2 SessionUid helper is removed from the bridge base now that native production lives in the native framework.

Changes:

  • Adds native MSTestTestFramework, MSTestRunSettings, MSTestFrameworkHandle, and MSTestFilterContext (MSTestRunContext/MSTestDiscoveryContext) that mirror the bridge adapters without depending on the bridge request path.
  • AddMSTest branches the framework factory on the flag; MSTestBridgedTestFramework reverts to pure-bridge and the unused SessionUid property is dropped from the bridge base.
  • References Microsoft.TestPlatform.Filter.Source directly in MSTest.TestAdapter.csproj (it flowed only privately via the bridge before).
Show a summary per file
FileDescription
TestApplicationBuilderExtensions.csAdds the MSTEST_EXPERIMENTAL_NATIVE_MTP flag and branches framework construction between native and bridged frameworks.
MSTestTestFramework.csNew native MTP framework: session lifecycle, request routing, discovery/run via the existing engine and native seams.
MSTestRunSettings.csNew native IRunSettings: reads/patches runsettings and warns on unsupported entries (port of bridge helpers).
MSTestFrameworkHandle.csNew native IFrameworkHandle forwarding only diagnostic messages to IOutputDevice; VSTest recording members are no-ops.
MSTestFilterContext.csNew native IRunContext/IDiscoveryContext building the VSTest filter expression from MTP filter/--filter/runsettings.
MSTestBridgedTestFramework.csReverts to pure-bridge production, removing the Phase 2 native-production branches.
SynchronizedSingleSessionVSTestAndTestAnywhereAdapter.csRemoves the now-unused internal SessionUid property, using a private _sessionUid field.
MSTest.TestAdapter.csprojAdds an explicit Microsoft.TestPlatform.Filter.Source reference for the native filter-parsing path.

The native classes are faithful copies of already-reviewed bridge logic, the SessionUid removal has no dangling references, and the package reference is correct. The one concrete issue found is that all four new .cs files are missing the UTF-8 BOM required by .editorconfig (every sibling file in the folder has one).

Review details

  • Files reviewed: 8/8 changed files
  • Comments generated: 4
  • Review effort level: Medium

Comment threadsrc/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestRunSettings.cs Outdated

@github-actionsgithub-actionsBot 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 — Phases 3–5 Native MTP Framework

Verdict: COMMENT (no blocking issues)

Overall this is a well-structured introduction of the native MSTestTestFramework. The architecture cleanly separates the native MTP path from the bridge, the CountdownEvent lifecycle is correct, and the opt-in gating via MSTEST_EXPERIMENTAL_NATIVE_MTP keeps shipping behavior untouched.

Dimension Results

#DimensionResult
1Algorithmic Correctness⚠️ Note — BuildFilter escape logic uses wrong loop variable (i vs k). Pre-existing bridge parity; latent.
2Concurrency / Thread Safety✅ LGTM — CountdownEvent pattern mirrors bridge; protocol guarantees prevent race.
3Resource Management✅ LGTM — IDisposable on CountdownEvent; no leaked handles.
4Defensive Coding⚠️ Suggestions — missing duplicate-session guard and default switch case (see inline).
5Error Handling✅ LGTM — Exceptions propagate correctly; finally ensures Signal()+Complete().
6API Surface✅ LGTM — All new types are internal. No public API additions.
7Backward Compatibility✅ LGTM — Opt-in only; bridge path unchanged. SessionUid visibility downgrade is internal.
8Performance✅ LGTM — No unnecessary allocations on hot path; XDocument parsing acceptable for settings.
9Naming & Style✅ LGTM
10Documentation✅ LGTM — XML docs are thorough.
11-22Remaining dimsN/A or LGTM

Notes

  • The sync-over-async in MSTestFrameworkHandle.SendMessage (.GetAwaiter().GetResult()) mirrors the bridge's FrameworkHandlerAdapter — acceptable for this opt-in path.
  • PatchTestRunParameters is safe against missing = because the upstream ValidateOptionArgumentsAsync rejects such input.
  • The IRunSettings.RunSettings property getter on MSTestFilterContextBase is a nullable IRunSettings? but the constructor always assigns it — this is fine.

Solid work. The three inline suggestions are non-blocking quality improvements.

…warning
- Re-save the four new TestingPlatformAdapter files as UTF-8 with BOM (per .editorconfig charset=utf-8-bom).
- MSTestRunSettings.WarnOnUnsupportedEntries: filter the settings sequence explicitly with .Where(...) instead of a foreach + if.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:26

CopilotAI 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: 8/8 changed files
  • Comments generated: 1
  • Review effort level: Medium

- MSTestTestFramework.CreateTestSessionAsync: throw InvalidOperationException if a session was already created (mirrors the bridge base), instead of silently overwriting.
- MSTestTestFramework.ExecuteRequestAsync: throw NotSupportedException for unrecognized request types instead of silently completing.
- MSTestFilterContext.BuildFilter: fix the escape-already-present check to index the previous character with the inner loop index k (was i, the test-node index) — avoids a potential IndexOutOfRangeException and corrects the escaping. The bridge's ContextAdapterBase has the same latent bug; a follow-up can fix it there too.
Validated: full build 0/0 (warnings-as-errors); native-path acceptance FilterTests+ServerModeTests+RunsettingsTests 51/51 green.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 15:35

CopilotAI 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: 8/8 changed files
  • Comments generated: 3
  • Review effort level: Low

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 8, 2026
…ureAwait
- MSTestRunSettings.ReadRunSettings: use the first --settings argument when one or more are provided (Length > 0), matching the runsettings environment-variable provider, instead of requiring exactly one and silently ignoring an otherwise-valid value.
- MSTestTestFramework.CreateTestSessionAsync: use the shared localized ExtensionResources.VSTestBridgedTestFrameworkSessionAlreadyCreatedErrorMessage instead of a hard-coded English string.
- MSTestFrameworkHandle.SendMessage: add ConfigureAwait(false) before GetAwaiter().GetResult() to reduce deadlock risk on context-bound threads.
Validated: full build 0/0 (warnings-as-errors).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 8, 2026 16:47
@Evangelink
Amaury Levé (Evangelink) merged commit 18c741f into mainJul 8, 2026
33 of 35 checks passed
@Evangelink
Amaury Levé (Evangelink) deleted the dev/amauryleve/remove-vstest-bridge-mstest branch July 8, 2026 16:47

CopilotAI 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: 8/8 changed files
  • Comments generated: 0 new
  • Review effort level: Low

github-actionsBot added a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Amaury Levé (Evangelink) pushed a commit that referenced this pull request Jul 9, 2026
- AzureFoundry: add DefaultAzureCredential/managed identity auth details
and required environment variables (PR #9707)
- MSTestTestFramework: new entry documenting the native MTP ITestFramework
for MSTest introduced by RFC 018 (PRs #9706, #9743, #9748, #9755)
- VSTestBridge: note MSTest no longer depends on it on the MTP path
as of MSTest 4.3
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

state/needs-reviewAwaiting review from the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@Evangelink@0101