Skip to content

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

@Evangelink@0101
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
RFC 020: Add composable test execution filter providers by Evangelink · Pull Request #10235 · microsoft/testfx · GitHub
Skip to content

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

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

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

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

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

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

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

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

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

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

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

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

RFC 020: Add composable test execution filter providers - #10235

Merged
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc
Jul 28, 2026
Merged

RFC 020: Add composable test execution filter providers#10235
Amaury Levé (Evangelink) merged 3 commits into
mainfrom
dev/amauryleve/mtp-filter-composition-rfc

Conversation

@Evangelink

@EvangelinkAmaury Levé (Evangelink) commented Jul 26, 2026

Copy link
Copy Markdown
Member

Summary

Adds RFC 020 and its implementation in the same change:

  • introduces an experimental multi-registration ITestExecutionFilterProvider API with run/discovery kind, console/server origin, and request cancellation;
  • composes the built-in request filter with all enabled provider constraints using explicit AND semantics;
  • adds CompositeTestExecutionFilter and normalizes UID-list constraints by intersection, including match-none empty intersections;
  • short-circuits composition when no provider contributes, so the built-in request filter instance is returned untouched;
  • preserves JSON-RPC request selection and rejects non-empty server-origin provider contributions with actionable diagnostics;
  • recursively translates composites in native MSTest and VSTestBridge while preserving runsettings/CLI AND behavior;
  • fixes empty TestNodeUidListFilter semantics in both adapter paths and covers server empty selection.

The provider API is scenario-neutral: providers contribute per-request constraints. Sharding, batching, retry, and other multi-run planning remain orchestrator responsibilities.

Motivation and issue coverage

Fixes#3530.

This does notclose#3590. That issue asks for framework authors to be able to supply their own ITestExecutionFilter implementations, and this change still rejects custom filter types. It delivers the composable extension point plus the recursive validation that a future capability negotiation needs, but not custom-kind support. The RFC now states this explicitly in Motivation, Scope, and Custom filter types.

This establishes common infrastructure relevant to #3528, #4068, and #7160 without implementing batching/sharding or a new cross-framework filter language. It documents why #4293 remains an adapter capability concern and explicitly rejects unsupported tree/custom filters instead of silently ignoring them.

This is orthogonal to draft #8820: that RFC proposes how a user-facing expression becomes a request filter; this PR defines how that built-in request filter composes with independent extension constraints. It does not add, rename, or claim any CLI option.

Compatibility

  • Existing applications without providers keep the current built-in CLI/request filter behavior. Composition short-circuits before any normalization or validation, so the same filter instance is used, UID order is not changed, and a framework-specific filter representation produced by the internal factory is not rejected.
  • The same short-circuit applies when providers are registered but all of them return null/NopFilter for a request, which is the expected server-origin path in this version.
  • Existing CLI option names and JSON-RPC payloads are unchanged.
  • New public API is additive and marked [Experimental("TPEXP")] with PublicAPI entries.
  • Internal signature changes are tracked in InternalAPI files.
  • Empty UID lists now consistently mean match none instead of producing the invalid VSTest expression ().
  • Adapters fail explicitly for filter representations they cannot evaluate.

Validation

  • Repository package build and package validation: succeeded.
  • Microsoft.Testing.Platform.UnitTests: 1,673 passed.
  • Microsoft.Testing.Extensions.VSTestBridge.UnitTests: 70 passed.
  • MSTestAdapter.UnitTests: 61 passed.
  • ExecutionTests packed acceptance matrix: 51 passed across net462, net8.0, and net10.0.
  • Affected platform, adapter, bridge, unit-test, and acceptance projects build with zero warnings/errors.

Two independent local review passes were completed. The first found internal API tracking gaps; those were fixed by replacing RS0051 suppressions with explicit shipped/unshipped API entries. The second found no additional issues.

Deferred work

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:50

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

Adds RFC 020 and experimental infrastructure for composing independent test execution constraints in Microsoft.Testing.Platform.

Changes:

  • Adds filter-provider registration, request context, AND composition, and UID intersection.
  • Updates MSTest and VSTestBridge filter translation and empty-selection behavior.
  • Adds unit/acceptance coverage, API tracking, diagnostics, and localization resources.
Show a summary per file
FileDescription
test/UnitTests/MSTestAdapter.UnitTests/MSTestFilterContextTests.csTests MSTest filter translation.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/ServerMode/ServerTests.csTests empty server selections.
test/UnitTests/Microsoft.Testing.Platform.UnitTests/Requests/TestExecutionFilterComposerTests.csTests composition and provider lifecycle.
test/UnitTests/Microsoft.Testing.Extensions.VSTestBridge.UnitTests/ObjectModel/RunContextAdapterFilterTests.csTests bridge filter translation.
test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ExecutionTests.csAdds end-to-end provider scenarios.
src/Platform/Microsoft.Testing.Platform/TestHost/TestHostManager.csRegisters and builds providers.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hant.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.zh-Hans.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.tr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ru.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pt-BR.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.pl.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ko.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.ja.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.it.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.fr.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.es.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.de.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/xlf/PlatformResources.cs.xlfAdds localized resource entries.
src/Platform/Microsoft.Testing.Platform/Resources/PlatformResources.resxDefines composition diagnostics.
src/Platform/Microsoft.Testing.Platform/Requests/TestNodeUidListFilter.csDocuments empty-list semantics.
src/Platform/Microsoft.Testing.Platform/Requests/TestHostTestFrameworkInvoker.csPropagates request cancellation.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestOrigin.csDefines request origins.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionRequestKind.csDefines request kinds.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterOperator.csDefines AND composition.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterContext.csExposes provider request context.
src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.csComposes and normalizes constraints.
src/Platform/Microsoft.Testing.Platform/Requests/ServerTestExecutionRequestFactory.csSupports asynchronous request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionRequestFactory.csAdds cancellation to request creation.
src/Platform/Microsoft.Testing.Platform/Requests/ITestExecutionFilterProvider.csDefines the provider API.
src/Platform/Microsoft.Testing.Platform/Requests/ConsoleTestExecutionRequestFactory.csApplies providers to console requests.
src/Platform/Microsoft.Testing.Platform/Requests/CompositeTestExecutionFilter.csDefines composite filters.
src/Platform/Microsoft.Testing.Platform/PublicAPI/PublicAPI.Unshipped.txtTracks new public APIs.
src/Platform/Microsoft.Testing.Platform/InternalAPI/InternalAPI.Unshipped.txtTracks internal API changes.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.csAdds providers to host services.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.RequestExecution.csEvaluates server-origin providers.
src/Platform/Microsoft.Testing.Platform/Hosts/ConsoleTestHost.csSupplies providers to request creation.
src/Platform/Microsoft.Testing.Platform/Helpers/TestApplicationBuilderExtensions.csExposes provider registration.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hant.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.zh-Hans.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.tr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ru.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pt-BR.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.pl.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ko.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.ja.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.it.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.fr.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.es.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.de.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/xlf/ExtensionResources.cs.xlfAdds localized bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/Resources/ExtensionResources.resxDefines bridge diagnostics.
src/Platform/Microsoft.Testing.Extensions.VSTestBridge/ObjectModel/ContextAdapterBase.csTranslates composite and empty filters.
src/Adapter/MSTest.TestAdapter/TestingPlatformAdapter/MSTestFilterContext.csTranslates native MSTest filters.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hant.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.zh-Hans.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.tr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ru.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pt-BR.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.pl.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ko.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.ja.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.it.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.fr.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.es.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.de.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/xlf/PlatformAdapterResources.cs.xlfAdds localized adapter diagnostics.
src/Adapter/MSTest.TestAdapter/Resources/PlatformAdapterResources.resxDefines adapter diagnostics.
docs/RFCs/020-Test-Execution-Filter-Providers.mdDocuments the design and scope.

Review details

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

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: d7adc271-ccc0-4654-aede-93ac7d83dd40
CopilotAI review requested due to automatic review settings July 26, 2026 10:56

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

Comments suppressed due to low confidence (1)

src/Platform/Microsoft.Testing.Platform/Requests/TestExecutionFilterComposer.cs:20

  • When no providers are enabled, this still normalizes and validates the request filter. That contradicts the RFC's compatibility guarantee that the same built-in filter object is preserved: UID filters are replaced/sorted/deduplicated, and a custom filter returned by the existing internal factory now throws. Short-circuiting preserves the pre-provider path while retaining composition whenever a provider is present.
  • Files reviewed: 69/69 changed files
  • Comments generated: 2
  • Review effort level: Medium

Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
Comment threaddocs/RFCs/020-Test-Execution-Filter-Providers.md
@github-actions

This comment has been minimized.

Address PR review feedback:
- ComposeAsync now returns the built-in request filter instance
untouched when no enabled provider contributes a constraint, so
NopFilter/TestNodeUidListFilter are not rebuilt, UID order is not
changed, and a framework-specific request filter is no longer
rejected. This makes the RFC compatibility guarantee literally true.
- Document the short-circuit in the composition algorithm, examples,
and compatibility sections.
- Add the missing [Experimental("TPEXP")] attribute to the three enums
in the RFC public API listing so it matches the real declarations.
- State explicitly that this RFC does not resolve#3590 (custom filter
implementations), which stays open pending capability negotiation.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b9d32942-cfb3-453e-a488-7e6aed7c42fd
CopilotAI review requested due to automatic review settings July 27, 2026 12: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.

Review details

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

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test quality grade — PR #10235

GradeTestMutationNotesHow to improve
B (80–89)new ExecutionTests.
Exec_
WhenTwoProvidersContributeDisjointUids_
RunsNoTests
2/3 killedExit code ZeroTests is checked but no summary assertion; a bug returning 1 run would pass.Add AssertOutputContainsSummary(failed:0, passed:0, skipped:0).
B (80–89)new ExecutionTests.
Exec_
WhenTreeAndProviderConstraintsAreDisjoint_
RunsNoTests
2/3 killedOnly exit code checked; wrong-count mutation (running 1 test instead of 0) still exits ZeroTests.Assert exact summary (0 passed) so a count regression is caught.
A (90–100)new ExecutionTests.
Exec_
WhenFilterProviderIsEnabled_
OnlyContributedUidRuns
3/3 killedExit code and exact summary (1 passed, 0 failed, 0 skipped) together protect all meaningful mutations.
A (90–100)new ExecutionTests.
Exec_
WhenBuiltInAndProviderUidFiltersAreSpecified_
UsesIntersection
3/3 killedIntersection semantics verified end-to-end: 2 built-in UIDs ∩ 1 provider UID → exactly 1 run.
A (90–100)new ExecutionTests.
Exec_
WhenProviderOnlyConstrainsRun_
DiscoveryRemainsUnfiltered
4/4 killedBoth discovery (finds 2) and run (executes 1) paths are asserted, covering the request-kind split.
A (90–100)new MSTestFilterContextTests.
EmptyUidListBuildsMatchNoneFilter
3/3 killedFilter string value, sentinel non-match, and normal FQN non-match all verified.
A (90–100)new MSTestFilterContextTests.
AndCompositeTranslatesChildrenRecursively
2/2 killedExact rendered filter string asserted; wrong order or missing term mutations are caught.
A (90–100)new MSTestFilterContextTests.
RunSettingsCommandLineAndCompositePreserveAndSemantics
3/3 killedThree-way AND combining run-settings, CLI option, and composite filter pinned by exact string.
A (90–100)new MSTestFilterContextTests.
TreeNodeFilterThrowsActionableError
2/2 killedException type and both required substrings in the message are verified.
A (90–100)new MSTestFilterContextTests.
CustomFilterThrowsActionableError
2/2 killedException type and both required message substrings checked for custom filter types.
A (90–100)mod RunContextAdapterFilterTests.
GetTestCaseFilter_
WithEmptyNodeList_
BuildsMatchNoneFilter
3/3 killedUpdated from old throw-expectation; now verifies exact filter string and two match=false cases.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithAndComposite_
TranslatesChildrenRecursively
2/2 killedExact rendered AND-composite string asserted; any missing or reordered term is caught.
A (90–100)new RunContextAdapterFilterTests.
GetTestCaseFilter_
WithRunSettingsAndComposite_
PreservesAndSemantics
2/2 killedExact filter string pins runsettings + composite UID AND semantics.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithTreeNodeFilter_
ThrowsActionableError
2/2 killedException type, type name, and VSTestBridge substring all verified.
A (90–100)new RunContextAdapterFilterTests.
Constructor_
WithCustomFilter_
ThrowsActionableError
2/2 killedException type and both required message substrings verified for unrecognised filter types.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInFilterOnly_
PreservesConstraint
1/1 killedIdentity (same instance returned) is the only meaningful property; AreSame covers it.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
ReturnsSameNopFilterInstance
1/1 killedAreSame pins the no-provider short-circuit path for NopFilter.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotNormalizeUidFilter
1/1 killedEnsures that with no providers the UID filter is returned as-is (no dedup/sort side-effect).
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithoutProviders_
DoesNotRejectCustomRequestFilter
1/1 killedConfirms that with no providers a custom filter does not throw and is returned unchanged.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WhenAllProvidersOptOut_
ReturnsSameRequestFilterInstance
2/2 killedBoth null-return and NopFilter providers exercised; AreSame guards the no-contribution path.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithProviderContribution_
RejectsCustomRequestFilter
2/2 killedException type and type-name substring verified for unrecognised built-in filter + provider.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithOneProvider_
UsesProviderConstraint
2/2 killedUID list verified by count and value (sorted); swap or extra element mutations are caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTwoUidProviders_
IntersectsIndependentlyOfRegistrationOrder
3/3 killedCommutativity verified with both orderings; exact UID content asserted in each direction.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithDisjointUidProviders_
ReturnsEmptyUidFilter
2/2 killedEmpty intersection returns empty UID list; any skip-empty-check mutation is caught.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithBuiltInAndProviderUidFilters_
IntersectsConstraints
2/2 killedBuilt-in UID list included in intersection; exact result UID asserted.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithTreeAndUidConstraints_
ReturnsAndComposite
3/3 killedComposite type, operator, count, and both child types individually verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithNestedAndComposite_
FlattensAndIntersectsUidConstraints
3/3 killedFlattening + UID intersection of nested composite verified with exact child-type and UID checks.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithUnsupportedProviderFilter_
ThrowsActionableError
2/2 killedException type, provider uid, and filter type name all verified in message.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithNullContribution_
PreservesRequestFilterAndContext
4/4 killedReturn-value identity, RequestKind, Origin, and non-null context all verified.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
ForServerWithProviderConstraint_
ThrowsActionableError
2/2 killedException type, provider uid, and return-null hint verified in the server-mode guard.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
PassesRequestContextAndCancellationToken
2/2 killedBoth context reference (AreSame) and exact token identity verified via capture.
A (90–100)new TestExecutionFilterComposerTests.
ComposeAsync_
WithCanceledToken_
DoesNotInvokeProvider
2/2 killedBoth cancellation exception and non-invocation of provider lambda are checked.
A (90–100)new TestExecutionFilterComposerTests.
BuildTestExecutionFilterProvidersAsync_
SkipsDisabledAndInitializesAllEnabledProviders
4/4 killedCount, order, and IsInitialized state for each provider (enabled×2 + disabled×1) all checked.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithFewerThanTwoChildren_
Throws
1/1 killedArgumentException thrown for single-child composite; guard condition is pinned.
A (90–100)new TestExecutionFilterComposerTests.
CompositeFilter_
WithNullChild_
Throws
1/1 killedArgumentException thrown when null child is supplied; null-guard mutation is caught.
A (90–100)new ServerTests.
RunRequestWithEmptyTests_
PreservesEmptyUidSelection
3/3 killedRequest type, filter type, and empty UID-list verified end-to-end over a real TCP server.

This advisory comment was generated automatically. Grades are heuristic
and informational — they do not block merging. Re-run with
/grade-tests.

🤖 Automated content by GitHub Copilot. Generated by the Grade Tests on PR (on open / sync) workflow. · sonnet46 108.1 AIC · ⌖ 5.66 AIC · ⊞ 10.3K · [◷]( · )

@EvangelinkAmaury Levé (Evangelink) added the state/needs-review Awaiting review from the team. label Jul 28, 2026
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.

[Testing Platform] Open up filters for custom implementations [Testing Platform] Aggregate Filter

3 participants

@Evangelink@0101