Skip to content

Register ServerTelemetry in the correct location of TestHostBuilder#8211

Merged
Evangelink merged 5 commits into
mainfrom
copilot/register-servertelemetry-correct-location
May 14, 2026
Merged

Register ServerTelemetry in the correct location of TestHostBuilder#8211
Evangelink merged 5 commits into
mainfrom
copilot/register-servertelemetry-correct-location

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 14, 2026

Bug Fix

What was the bug?

ServerTelemetry (which forwards telemetry events to the JSON-RPC client in server mode) was instantiated inside the ServerTestHost constructor as a private field but never registered in the service provider. Any code calling serviceProvider.GetTelemetryCollector() — including LogTestHostCreatedAsync — received the NopTelemetryService instead, silently dropping telemetry rather than forwarding it to the client.

How did you fix it?

  • ServiceProvider: Added ReplaceService<T>(T newService) — replaces the first registered instance of type T in-place, preserving lookup order. Falls back to append if no existing instance is found.

  • TestHostBuilder.Modes.cs (BuildServerTestHostAsync): After ServerTestHost is constructed, creates ServerTelemetry and registers it via ReplaceService<ITelemetryCollector>, displacing the NopTelemetryService that SetupCommonServicesAsync added earlier. This is the correct registration site — within TestHostBuilder, not inside the host itself.

  • ServerTestHost: Removed the private _telemetryService field and its constructor assignment. The single call site now uses ServiceProvider.GetTelemetryCollector(), keeping the host decoupled from the concrete telemetry type.

// TestHostBuilder.Modes.cs — BuildServerTestHostAsync
ServerTestHost serverTestHost = new(context.ServiceProvider, ...);

// Register ServerTelemetry so all telemetry in server mode is forwarded
// to the client via JSON-RPC, replacing the earlier NopTelemetryService.
context.ServiceProvider.ReplaceService<ITelemetryCollector>(new ServerTelemetry(serverTestHost));

Copilot AI requested review from Copilot and removed request for Copilot May 14, 2026 09:19
Copilot AI linked an issue May 14, 2026 that may be closed by this pull request
Copilot AI requested review from Copilot and removed request for Copilot May 14, 2026 09:36
Copilot AI requested review from Copilot and removed request for Copilot May 14, 2026 09:37
Copilot AI changed the title [WIP] Fix registration location for ServerTelemetry in TestHostBuilder Register ServerTelemetry in the correct location of TestHostBuilder May 14, 2026
Copilot AI requested a review from Evangelink May 14, 2026 09:38
@Evangelink Evangelink marked this pull request as ready for review May 14, 2026 10:26
Copilot AI review requested due to automatic review settings May 14, 2026 10:26
@Evangelink
Copy link
Copy Markdown
Member

/review

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 14, 2026

Expert Code Review (command) failed. Please review the logs for details.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes server-mode telemetry forwarding in Microsoft.Testing.Platform by ensuring ServerTelemetry is registered in the ServiceProvider (so GetTelemetryCollector() resolves to the forwarding implementation instead of NopTelemetryService), and by removing the direct ServerTelemetry coupling from ServerTestHost.

Changes:

  • Added ServiceProvider.ReplaceService<T>(T) to replace the first matching service instance while preserving lookup order.
  • Updated TestHostBuilder server-mode build path to register ServerTelemetry as the ITelemetryCollector.
  • Updated ServerTestHost to obtain the telemetry collector from the ServiceProvider rather than maintaining its own private instance.
Show a summary per file
File Description
src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs Adds ReplaceService<T> to support in-place replacement of an existing registration.
src/Platform/Microsoft.Testing.Platform/Hosts/TestHostBuilder.Modes.cs Registers ServerTelemetry in server mode by replacing the previously-registered telemetry collector.
src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs Removes the private ServerTelemetry field and uses ServiceProvider.GetTelemetryCollector() for event logging.

Copilot's findings

  • Files reviewed: 3/3 changed files
  • Comments generated: 3

Comment thread src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs
Comment thread src/Platform/Microsoft.Testing.Platform/Services/ServiceProvider.cs
@Evangelink
Copy link
Copy Markdown
Member

@copilot address review comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot address review comments

Addressed all three review comments in commit Address review comments: null-guard, IsEnabled check, and ReplaceService unit tests:

  1. Null-guard: Added _ = newService ?? throw new ArgumentNullException(nameof(newService)) to ReplaceService<T> (using the codebase pattern compatible with netstandard2.0).
  2. Conditional registration: The ReplaceService<ITelemetryCollector> call in BuildServerTestHostAsync is now guarded by telemetryInformation.IsEnabled, so the NopTelemetryService is preserved when telemetry is opted out.
  3. Unit tests: Added four tests to ServiceProviderTests.cs: ReplaceService_WhenMatchingServiceExists_ReplacesInPlace, ReplaceService_WhenNoMatchingServiceExists_AppendsService, ReplaceService_ReplacesFirstMatch_PreservesOtherServices, and ReplaceService_NullService_ThrowsArgumentNullException.

@Evangelink
Copy link
Copy Markdown
Member

@copilot address review comments

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot address review comments

All three review comments were already addressed in commit aef6566:

  1. Null-guard_ = newService ?? throw new ArgumentNullException(nameof(newService)) added to ReplaceService<T>.
  2. Conditional registrationReplaceService<ITelemetryCollector> is now guarded by if (context.ServiceProvider.GetTelemetryInformation().IsEnabled).
  3. Unit tests — Four tests added covering replace-in-place, append-when-missing, ordering preservation, and null rejection. All pass.

@Evangelink
Copy link
Copy Markdown
Member

@copilot fix the broken test

test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ServerMode/v1.0.0/TestingPlatformClient.cs#L130

test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ServerMode/v1.0.0/TestingPlatformClient.cs(130,1): error : [DiscoverAndRun ("net10.0")] [net11.0] Test method MSTest.Acceptance.IntegrationTests.ServerModeTests.DiscoverAndRun threw exception:
StreamJsonRpc.RemoteInvocationException: System.InvalidOperationException: Unexpected telemetry call, the telemetry is disabled.
at Microsoft.Testing.Platform.Telemetry.NopTelemetryService.LogEventAsync(String eventName, IDictionary`2 paramsMap, CancellationToken cancellationToken) in //src/Platform/Microsoft.Testing.Platform/Telemetry/NopTelemetryService.cs:line 13
at Microsoft.Testing.Platform.Hosts.ServerTestHost.ExecuteRequestAsync(RequestArgsBase args, String method, ServiceProvider perRequestServiceProvider, CancellationToken cancellationToken) in /
/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs:line 572
at Microsoft.Testing.Platform.Hosts.ServerTestHost.HandleRequestCoreAsync(RequestMessage message, RpcInvocationState rpcInvocationState, CancellationToken cancellationToken) in //src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs:line 433
at Microsoft.Testing.Platform.Hosts.ServerTestHost.HandleRequestAsync(RequestMessage request, CancellationToken serverClosing, CancellationToken cancellationToken) in /
/src/Platform/Microsoft.Testing.Platform/Hosts/ServerTestHost.cs:line 344

…tionally

The IsEnabled guard introduced in the previous commit was incorrect. In server mode,
ServerTelemetry (JSON-RPC forwarding) must always be registered regardless of whether
platform telemetry collection is enabled/disabled. Without it, NopTelemetryService(false)
is left in place and throws InvalidOperationException when ExecuteRequestAsync calls
LogEventAsync at the end of each test run/discovery request.

Co-authored-by: Evangelink <[email protected]>
Copilot AI requested review from Copilot and removed request for Copilot May 14, 2026 12:34
Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 14, 2026

@copilot fix the broken test

test/IntegrationTests/Microsoft.Testing.Platform.Acceptance.IntegrationTests/ServerMode/v1.0.0/TestingPlatformClient.cs#L130
...

Fixed in the latest commit. The IsEnabled guard was incorrect — ServerTelemetry in server mode is a protocol concern (JSON-RPC forwarding to the client), not a data-collection concern, so it must always be registered regardless of whether platform telemetry is enabled or disabled. Removed the guard so ReplaceService<ITelemetryCollector> is now unconditional, matching the original behavior where ServerTestHost always used a private ServerTelemetry instance directly.

@Evangelink Evangelink merged commit ce3cfda into main May 14, 2026
17 checks passed
@Evangelink Evangelink deleted the copilot/register-servertelemetry-correct-location branch May 14, 2026 14:56
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.

Register ServerTelemetry in correct location of TestHostBuilder

3 participants