Skip to content

Inject TestSessionPool into the CrossPlatEngine session proxies - #16225

Merged
Jakub Jareš (nohwnd) merged 1 commit into
microsoft:mainfrom
nohwnd:nohwnd-inject-testsessionpool
Jul 7, 2026
Merged

Jakub Jareš (nohwnd) merged 1 commit into
microsoft:mainfrom
nohwnd:nohwnd-inject-testsessionpool

Conversation

@nohwnd

Copy link
Copy Markdown
Member

Problem

TestSessionPool is reached everywhere through the mutable public static TestSessionPool.Instance. The sites that coordinate a test session - the writer ProxyTestSessionManager.AddSession and the readers TestEngine.TryTakeProxy, ProxyDiscoveryManager.ReturnProxy and ProxyExecutionManager.ReturnProxy - only agree on the same pool because they all resolve the same static. That is process-wide state feeding a request-scoped concern, and it makes the session proxies awkward to exercise in isolation.

Change

TestEngine is the single place that constructs the session-mode proxies, so I thread one TestSessionPool? from there into ProxyTestSessionManager, ProxyDiscoveryManager and ProxyExecutionManager. Each stores it in a nullable field and reads (_testSessionPool ?? TestSessionPool.Instance) at the call site.

  • When nothing is injected the field is null and every site reads TestSessionPool.Instance, exactly as before - runtime behavior is byte-for-byte identical.
  • The new parameters live on internal constructors/overloads only, so there is no change to any shipped public signature and no PublicAPI edit. TestSessionPool.Instance is untouched and keeps working for the callers that still use it (no [Obsolete]).
  • TestRequestManager.KillSession in vstest.console is intentionally left on the static. It is not one of the objects TestEngine builds, so wiring it would be a separate seam; in production it resolves the same static instance, so it is already correct.

This follows the same "inject one instance from the composition root, default it to the existing static" shape as the earlier argument-processor changes.

Verification

Added a ProxyTestSessionManagerTests case that injects one pool as the shared instance and puts a different pool behind the static default. StartSession writes to the injected pool, and a TryTakeProxy off that same injected instance observes the proxy the writer added, while the static default never sees the session. If a writer and a reader ever ended up on different instances, that read side would come back empty - so the test guards the same-instance contract the refactor depends on.

Locally on Windows:

  • build.cmd -c Release - 0 errors, no IDE0005 (only the pre-existing CommunicationUtilities IL trim warnings).
  • Microsoft.TestPlatform.CrossPlatEngine.UnitTests (net481) - 675 total, 674 passed, 1 skipped, 0 failed.
  • build.cmd -pack - binding-redirect and DLL-target-framework checks pass.
  • test.cmd -smokeTest - Library.IntegrationTests and Acceptance.IntegrationTests all green.

`TestSessionPool` is reached through the mutable public static `TestSessionPool.Instance`
from every site that coordinates a test session: the writer `ProxyTestSessionManager.AddSession`,
and the readers `TestEngine.TryTakeProxy`, `ProxyDiscoveryManager.ReturnProxy` and
`ProxyExecutionManager.ReturnProxy`. Because it is process-wide state, the writer and readers
of a given session only line up by virtue of all resolving the same static, which is the kind
of implicit shared state that makes this code hard to test in isolation.

Thread one `TestSessionPool?` from `TestEngine` (the single place that constructs the
session-mode proxies) into `ProxyTestSessionManager`, `ProxyDiscoveryManager` and
`ProxyExecutionManager`. Each holds the injected pool in a nullable field and reads
`(_testSessionPool ?? TestSessionPool.Instance)` at the call site, so when nothing is injected
the behavior is byte-for-byte what it was before. The new parameters live on internal
constructors/overloads only, so no shipped public signature changes and `TestSessionPool.Instance`
keeps working for the callers that still use it. `TestRequestManager.KillSession` in
vstest.console is intentionally left on the static - it is not one of the objects `TestEngine`
builds, so injecting there would be a separate seam.

Adds a `ProxyTestSessionManagerTests` case that injects one pool as the shared instance and a
different pool behind the static default: `StartSession` writes to the injected pool and a
`TryTakeProxy` off the same injected instance observes the proxy, while the static default never
sees the session. That guards the same-instance contract the refactor relies on.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces reliance on the mutable global TestSessionPool.Instance by allowing TestEngine (the composition root for session-mode proxies) to optionally inject a TestSessionPool instance into the session-aware proxy components. This improves testability and reduces hidden coupling while keeping the default runtime behavior unchanged when nothing is injected.

Changes:

  • Thread an optional TestSessionPool? from TestEngine into ProxyTestSessionManager, ProxyDiscoveryManager, and ProxyExecutionManager.
  • Update session-mode proxy acquisition/return paths to use (_testSessionPool ?? TestSessionPool.Instance) at the call sites.
  • Add a unit test ensuring the writer (StartSession/AddSession) and reader (TryTakeProxy) operate on the same injected pool instance (and not the static singleton).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
test/Microsoft.TestPlatform.CrossPlatEngine.UnitTests/Client/ProxyTestSessionManagerTests.cs Adds a unit test verifying injected pool usage (writer/reader coherence).
src/Microsoft.TestPlatform.CrossPlatEngine/TestSession/ProxyTestSessionManager.cs Allows injecting a pool for AddSession while preserving the static fallback.
src/Microsoft.TestPlatform.CrossPlatEngine/TestEngine.cs Threads an optional pool through session-mode proxy creation and proxy take/return logic.
src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyExecutionManager.cs Returns proxies to the injected pool (or falls back to the static pool).
src/Microsoft.TestPlatform.CrossPlatEngine/Client/ProxyDiscoveryManager.cs Returns proxies to the injected pool (or falls back to the static pool).

@nohwnd
Jakub Jareš (nohwnd) merged commit 56d779e into microsoft:main Jul 7, 2026
27 of 28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants