Skip to content

fix(tests): disable MSBuild node reuse for spawned builds - #2

Merged
teneko merged 2 commits into
mainfrom
fix/msbuild-node-reuse-hang
Oct 9, 2026
Merged

teneko merged 2 commits into
mainfrom
fix/msbuild-node-reuse-hang

Conversation

@teneko

@teneko teneko commented Oct 9, 2026 •

Copy link
Copy Markdown
Member

Problem

RefProjectBuildTests and PackageLayoutFixture spawn dotnet build / dotnet pack with redirected stdout/stderr and read both streams to the end. MSBuild worker nodes started with nodeReuse:true outlive the build and inherit those pipes, so EOF never arrives until the orphaned nodes hit their idle timeout.

Locally this made dotnet test hang indefinitely (verified with lsof: the orphaned node, re-parented to PID 1, held the write ends of the pipes the testhost was reading). It most likely also explains why the Coverage workflow went from ~1 min to ~31 min per run starting with the push on 2026-02-15 (the old job logs have expired, so this part is inferred, not proven).

Separately, the Coverage workflow currently fails before any test runs: the mcr.microsoft.com/dotnet/sdk:10.0 image only ships the .NET 10 runtime, so the net8.0 test host cannot start ("You must install or update .NET to run this application").

Fix

  • Set MSBUILDDISABLENODEREUSE=1 on the spawned processes in both helpers.
  • In PackageLayoutFixture, drain stderr concurrently instead of after stdout, avoiding a deadlock when the stderr pipe buffer fills up.
  • Set RollForward=Major in the test project so the net8.0 tests run on the newest installed runtime. The test target framework stays net8.0; the shipped generator (netstandard2.0) is unaffected.

Verification

From a clean state (dotnet build-server shutdown, ref project bin/ + obj/ removed), without setting the variable externally:

  • With the fix: 107/107 tests passed, ~5 s total, no leftover MSBuild nodes.
  • Without the fix (control run): no result after 90 s; an orphaned nodeReuse:true MSBuild node was present again.

With only the .NET 10 runtime installed (same situation as the CI image), the CI test command (dotnet test --nologo /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura /p:CoverletOutput=TestResults/coverage/) passes 107/107 without any environment overrides and writes coverage.cobertura.xml.

🤖 Generated with Claude Code

teneko and others added 2 commits October 9, 2026 05:05
The ref project build tests and the package layout fixture spawn
`dotnet build`/`dotnet pack` with redirected stdout/stderr. MSBuild worker
nodes started with node reuse outlive the build and inherit those pipes, so
reading the streams to the end blocked until the nodes hit their idle timeout.

Set MSBUILDDISABLENODEREUSE=1 for the spawned processes and drain stderr
concurrently in PackageLayoutFixture to avoid a full-pipe deadlock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Coverage workflow runs the tests in the mcr.microsoft.com/dotnet/sdk:10.0
image, which only ships the .NET 10 runtime. The net8.0 test host could not
start there ("You must install or update .NET to run this application").

Keep net8.0 as the test target framework and set RollForward=Major so the
tests run on the newest installed runtime.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@teneko
teneko merged commit 3026530 into main Oct 9, 2026
1 check passed
@codecov

codecov Bot commented Oct 9, 2026

Copy link
Copy Markdown

Welcome to Codecov 🎉

Once you merge this PR into your default branch, you're all set! Codecov will compare coverage reports and display results in all future pull requests.

ℹ️ You can also turn on project coverage checks and project coverage reporting on Pull Request comment

Thanks for integrating Codecov - We've got you covered ☂️

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.

1 participant