Skip to content

[duplicate-code] Duplicate Code: Extension Lifecycle Build Loop Repeated Across 7 Platform Manager Classes #9652

Description

@github-actions

Summary

Seven *Manager classes in Microsoft.Testing.Platform each independently implement the same 5-step "instantiate → validate unique → check enabled → initialize → register" loop for building platform extensions. The loop body is structurally identical across ~12 methods and 7 files; only the factory delegate type and the list element type differ.

Duplication Details

Pattern: Extension build loop — ~12 independent implementations

The core template (varying only the type parameter T):

foreach (Func<IServiceProvider, T> factory in _factories)
{
    T service = factory(serviceProvider);                              // step 1: instantiate
    existingList.ValidateUniqueExtension(service);                    // step 2: duplicate check
    if (await service.IsEnabledAsync().ConfigureAwait(false))         // step 3: enabled guard
    {
        await service.TryInitializeAsync().ConfigureAwait(false);     // step 4: initialize
        existingList.Add(service);                                    // step 5: register
    }
}

Files and approximate line ranges:

File Method Lines
TestHost/TestHostManager.cs BuildTestApplicationLifecycleCallbackAsync 97–114
TestHost/TestHostManager.cs BuildDataConsumersAsync (simple factory path) 138–153
TestHost/TestHostManager.cs BuildTestSessionLifetimeHandleAsync (simple path) 233–248
TestHostControllers/TestHostControllersManager.cs BuildAsync (env-var handlers) 158–174
TestHostControllers/TestHostControllersManager.cs BuildAsync (lifetime handlers) 215–231
TestHostControllers/TestHostControllersManager.cs BuildTestHostLauncherAsync 337–351
TestHostOrchestrator/TestHostOrchestratorManager.cs BuildAsync (main) 41–58
TestHostOrchestrator/TestHostOrchestratorManager.cs BuildTestHostOrchestratorApplicationLifetimesAsync 69–87
CommandLine/CommandLineManager.cs BuildAsync 43–57
Configurations/ConfigurationManager.cs BuildAsync 29–47
Tools/ToolsManager.cs BuildAsync 18–29
Logging/LoggingManager.cs BuildAsync 20–31

Composite-factory variant — 5 more identical copies (~25 lines each)

A longer variant that additionally handles CompositeExtensionFactory<T> (clone-or-reuse-singleton logic, alreadyBuiltServices.Add(), and a type-check-or-throw) is also duplicated ~5 times inside TestHostManager.cs (lines 155–196, 250–293) and TestHostControllersManager.cs (lines 176–213, 233–268, 272–313).

  • Severity: High
  • Occurrences: ~17 loop bodies across 7 files
  • Total duplicated lines: ~300+

Impact Analysis

  • Maintainability: Any change to the initialization protocol — adding a cancellation token to TryInitializeAsync, reordering ValidateUniqueExtension vs IsEnabledAsync, injecting a timeout guard — must be applied to all 17 loop bodies consistently.
  • Bug Risk: Protocol divergence already exists: some loops pass a registrationOrder index, others do not. A missed update could silently produce a different ordering for one extension type.
  • Code Bloat: The 7 manager classes each re-express the same algorithm, making the codebase harder to reason about for new contributors.

Refactoring Recommendations

  1. Extract a shared BuildExtensionsAsync<T> helper (e.g., in a new ExtensionManagerHelper.cs internal to the platform) with signature:
    internal static async Task BuildExtensionsAsync<T>(
        IEnumerable<Func<IServiceProvider, T>> factories,
        IServiceProvider serviceProvider,
        List<T> result)
        where T : IExtension
  2. Extract BuildCompositeExtensionsAsync<T> for the composite-factory path, handling the clone-or-reuse-singleton logic once.
  3. Update all 7 manager classes to delegate to these helpers, reducing each Build*Async method to a couple of lines.

Implementation Checklist

  • Review duplication findings
  • Design the shared BuildExtensionsAsync / BuildCompositeExtensionsAsync helper API
  • Implement helpers in src/Platform/Microsoft.Testing.Platform/
  • Refactor all 7 manager Build*Async methods to use the helpers
  • Run the full unit test suite to verify behavior is unchanged
  • Verify no functional differences in registration order or error handling

Analysis Metadata

  • Analyzed Files: 7 manager files across TestHost/, TestHostControllers/, TestHostOrchestrator/, CommandLine/, Configurations/, Tools/, Logging/
  • Detection Method: Semantic code analysis
  • Commit: 8609d3b
  • Analysis Date: 2026-07-06

🤖 Automated content by GitHub Copilot. Posted via a maintainer's GitHub token, so it appears under their account — the account owner did not write or approve this content personally. Generated by the Duplicate Code Detector workflow. · 264.8 AIC · ⌖ 8.27 AIC · ⊞ 8K · [◷]( · )

Add this agentic workflows to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/duplicate-code-detector.md@main
  • expires on Jul 8, 2026, 5:46 AM UTC

Metadata

Metadata

Assignees

No one assigned

    Labels

    type/automationCreated or maintained by an agentic workflow.type/tech-debtCode health, refactoring, simplification.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions