[file-diet] Refactor TestHostControllersTestHost.cs (641 lines) into smaller, focused files
type/tech-debttype/automation
### Overview
The file `src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControllersTestHost.cs` has grown to 641 lines, making it harder to navigate and maintain. This task involves refactoring it into smaller, more focused files.
### Current State
- **File**: `src/Platform/Microsoft.Testing.Platform/Hosts/TestHostControllersTestHost.cs`
- **Size**: 641 lines
- **Language**: C#
<details>
<summary><b>Structural Analysis</b></summary>
The class `TestHostControllersTestHost` (internal sealed, implements `CommonHost`, `IHost`, `IDisposable`, `IOutputDeviceDataProducer`) contains:
- `InternalRunAsync` (lines 72–466, ~395 lines) — a single monolithic method that:
- Resolves services and builds the test host process command line/environment variables
- Applies `ITestHostEnvironmentVariableProvider` extensions and validates environment variables
- Fires `ITestHostProcessLifetimeHandler.BeforeTestHostProcessStartAsync`
- Launches the test host process (default or custom launcher)
- Sets up the named-pipe IPC server and waits for the test host PID handshake
- Fires `OnTestHostProcessStartedAsync` / waits for process exit / handles cancellation-triggered termination
- Fires `OnTestHostProcessExitedAsync`, drains/disables the message bus
- Applies coverage threshold checks and computes the final exit code
- Collects telemetry/extension information and logs the final result
- `LaunchUsingCustomLauncherAsync` (lines 467–508) — launches the process via a custom `ITestHostLauncher`
- `GetAuthorizedSecurityIdentitiesAsync` (lines 509–556) — resolves security identities for the IPC server
- `DisposeServicesAsync` (lines 557–610) — disposes services in the provider
- `HandleRequestAsync` (lines 611–638) — handles inbound IPC requests (PID/exit-code messages)
- `Dispose` (line 639+)
The bulk of the size and complexity lives in the single `InternalRunAsync` method, which mixes several distinct concerns (environment variable setup, process launch, IPC handshake, lifetime-handler notification, exit/coverage handling, cleanup) in one long procedural block.
</details>
### Refactoring Strategy
#### Proposed File Splits
1. **`TestHostControllersTestHost.EnvironmentSetup.cs`** *(partial class)*
- Contents: environment-variable preparation logic currently inline in `InternalRunAsync` (building `partialCommandLine`, `ProcessStartInfo`, applying `ITestHostEnvironmentVariableProvider`/`ITestHostEnvironmentVariableProvider` validation)
- Responsibility: Preparing process start info, environment variables, and validating them via extensions
2. **`TestHostControllersTestHost.ProcessLifecycle.cs`** *(partial class)*
- Contents: `LaunchUsingCustomLauncherAsync`, the process-launch/wait-for-exit block (including the cancellation-triggered termination logic), and `OnTestHostProcessStartedAsync`/`OnTestHostProcessExitedAsync` lifetime-handler invocation helpers extracted as private methods
- Responsibility: Starting the test host process and coordinating `ITestHostProcessLifetimeHandler` notifications around its lifetime
3. **`TestHostControllersTestHost.Ipc.cs`** *(partial class)*
- Contents: `GetAuthorizedSecurityIdentitiesAsync`, `HandleRequestAsync`, and the named-pipe IPC server setup/handshake logic
- Responsibility: Managing the controller↔test-host IPC channel and PID handshake
4. **`TestHostControllersTestHost.cs`** *(remaining, trimmed)*
- Contents: Class fields, constructor, `IExtension` properties, `DisposeServicesAsync`, `Dispose`, and a slimmed-down `InternalRunAsync` that delegates to the extracted private methods (coverage-threshold/exit-code computation can remain here or move to a small helper method)
- Responsibility: Orchestration entry point (`InternalRunAsync`) and disposal
### Implementation Guidelines
1. **Preserve Behavior**: All existing functionality must work identically after the split
2. **Maintain Public API**: Keep exported/public symbols accessible with the same names (this class is `internal`, so no public API changes are expected, but constructor/property signatures must remain unchanged)
3. **Update Imports**: Fix all import paths throughout the codebase (partial-class split does not require external import changes, but `using` directives per file must be adjusted)
4. **Test After Each Split**: Run the test suite after each incremental change (`./build.sh -test`, focusing on `Microsoft.Testing.Platform.UnitTests` and related acceptance tests)
5. **One File at a Time**: Split one module at a time to make review easier — start with `Ipc.cs` (most self-contained), then `ProcessLifecycle.cs`, then `EnvironmentSetup.cs`
### Acceptance Criteria
- [ ] Original file is split into focused partial-class files
- [ ] Each new file is under 300 lines
- [ ] All tests pass after refactoring
- [ ] No breaking changes to public API
- [ ] All import paths updated correctly
---
**Priority**: Medium
**Effort**: Medium (single class, but the `InternalRunAsync` method has intricate cancellation/error-handling control flow that must be preserved exactly)
**Expected Impact**: Improved code navigability, easier testing, reduced merge conflicts
<!-- gh-aw-tracker-id: daily-file-diet -->
> 🤖 **Automated content by GitHub Copilot.** Generated by the [Daily File Diet](https://github.com/microsoft/testfx/actions/runs/31210194010/agentic_workflow) workflow. · auto · 35.2 AIC · ⌖ 2.09 AIC · ⊞ 11.4K · [◷]( · [◷](https://github.com/search?q=repo%3Amicrosoft%2Ftestfx+is%3Aissue+%22gh-aw-workflow-call-id%3A+microsoft%2Ftestfx%2Fdaily-file-diet%22&type=issues))
> - [x] expires <!-- gh-aw-expires: 2026-08-09T19:15:35.163Z --> on Aug 9, 2026, 7:15 PM UTC
<!-- gh-aw-agentic-workflow: Daily File Diet, gh-aw-tracker-id: daily-file-diet, engine: copilot, model: auto, id: 31210194010, workflow_id: daily-file-diet, run: https://github.com/microsoft/testfx/actions/runs/31210194010 -->
<!-- gh-aw-workflow-id: daily-file-diet -->
<!-- gh-aw-workflow-call-id: microsoft/testfx/daily-file-diet -->
0 条评论