Skip to content

Pre-build VSTest project and use --no-build for TelemetryTests#8312

Merged
Evangelink merged 3 commits into
mainfrom
evangelink/fix-telemetry-vstest-flake-nobuild
May 18, 2026
Merged

Pre-build VSTest project and use --no-build for TelemetryTests#8312
Evangelink merged 3 commits into
mainfrom
evangelink/fix-telemetry-vstest-flake-nobuild

Conversation

@Evangelink
Copy link
Copy Markdown
Member

Follow-up to #8292 which only added [DoNotParallelize] to TelemetryTests.

The VSTest_RunTests_Succeeds and VSTest_DiscoverTests_Succeeds cases were still flaking on SDK 11 preview (11.0.100-preview.5.26227.104) with:

error MSB4018: The "GenerateRuntimeConfigurationFiles" task failed unexpectedly.
System.IO.IOException: The process cannot access the file
'...bin/Release/<tfm>/TelemetryVSTestProject.runtimeconfig.json' because it is being used by another process.

Even though [DoNotParallelize] serializes the test methods inside the class, every dotnet test invocation still re-runs the build (and GenerateRuntimeConfigurationFiles), and the shared bin/<tfm>/ outputs were racing with leftover MSBuild / testhost handles across serialized invocations.

Fix

  • Add EnsureVSTestProjectBuiltAsync(tfm, ct) on the fixture, gated by a SemaphoreSlim + HashSet<string> so the VSTest project is built exactly once per TFM. The TFM is only cached after a successful build to avoid poisoning on cancellation/failure.
  • Change VSTest_* tests to call the pre-build then run dotnet test ... --no-build --no-restore so the build/restore targets that write the locked file never run during the actual tests.
  • Keep [DoNotParallelize] as defense in depth.

Verification

  • Local dotnet build of MSTest.Acceptance.IntegrationTests.csproj succeeds.
  • Functional verification has to happen in CI since this is an intermittent SDK 11 preview race.

The VSTest_RunTests_Succeeds and VSTest_DiscoverTests_Succeeds tests
were still flaking on SDK 11 preview with:

  error MSB4018: The `GenerateRuntimeConfigurationFiles` task failed
  unexpectedly. System.IO.IOException: The process cannot access the
  file '...bin/Release/<tfm>/TelemetryVSTestProject.runtimeconfig.json'
  because it is being used by another process.

Even though [DoNotParallelize] (PR #8292) serializes the test methods,
`dotnet test` re-runs the build (and `GenerateRuntimeConfigurationFiles`)
for each invocation, and the shared bin/<tfm>/ outputs were racing with
leftover handles (MSBuild server / lingering testhost) across serialized
invocations.

Build the VSTest project lazily once per TFM via a SemaphoreSlim+HashSet
on the fixture, then run `dotnet test ... --no-build --no-restore` so the
file-writing build targets do not run at test time at all. Keep
[DoNotParallelize] as defense in depth.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 18, 2026 07:46
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

This PR reduces TelemetryTests flakiness by pre-building the shared VSTest test asset per target framework and running VSTest invocations without rebuilding/restoring during each test.

Changes:

  • Adds a fixture-level pre-build helper guarded by a semaphore and per-TFM cache.
  • Updates VSTest run and discovery tests to call the pre-build helper and use --no-build --no-restore.
  • Keeps class-level serialization as defense in depth for shared build outputs.
Show a summary per file
File Description
test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TelemetryTests.cs Pre-builds the VSTest asset once per TFM and updates dotnet test calls to avoid per-test build/restore races.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0

Copy link
Copy Markdown
Member Author

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

The fix correctly addresses the GenerateRuntimeConfigurationFiles race by pre-building once per TFM via a SemaphoreSlim+HashSet guard and then passing --no-build --no-restore. One logic bug: the ExitCode != 0 guard in EnsureVSTestProjectBuiltAsync is unreachable dead code because DotnetCli.RunAsync defaults to failIfReturnValueIsNotZero: true and throws before the caller can inspect the exit code. See inline comment.

Generated by Expert Code Review (on open) for issue #8312 · ● 3.9M

Comment thread test/IntegrationTests/MSTest.Acceptance.IntegrationTests/TelemetryTests.cs Outdated
Copilot AI and others added 2 commits May 18, 2026 11:13
- Remove unreachable ExitCode!=0 check (DotnetCli.RunAsync already throws on non-zero exit by default)

- Use collection expression [with(comparer)] syntax for HashSet to fix IDE0028

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 18, 2026 10:10
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.

Copilot's findings

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

@Evangelink Evangelink merged commit 6e45932 into main May 18, 2026
33 of 35 checks passed
@Evangelink Evangelink deleted the evangelink/fix-telemetry-vstest-flake-nobuild branch May 18, 2026 13:03
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.

4 participants