Repository navigation
Make product performance traversal tests deterministic under parallel load - #111
Merged
Merged
Conversation
The traversal tests set the process-wide JITHUB_PERFORMANCE_FIXTURE variable and drive the static ProductPerformanceReadiness traversal. While the variable is set, product code under test in parallel classes (RepoCodePageViewModel.SelectFileAsync) records stages into the same static traversal from thread-pool threads. Those calls reached the test's List<T> handler concurrently, which lost "before.commit", threw "Collection was modified" inside Assert.Single, or corrupted the list. The class-local ReadinessGate lock only serialized the class against itself. Move the two traversal tests into a DisableParallelization collection so they run alone, and collect stages in a ConcurrentQueue so a late stage from another thread cannot corrupt the snapshot the test asserts on. Assertions are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zhuowcui
approved these changes
Oct 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
ProductPerformanceObservationTests.TraversalCommitEndsGenerationAndRejectsLaterStagesfailed once in a fullJitHub.WinUI.Testsrun on the MarkdownRenderer stack (3,125 of 3,126). The test and the product code it covers haven't changed since #89.Root cause
The traversal tests set the process-wide
JITHUB_PERFORMANCE_FIXTUREvariable and drive the staticProductPerformanceReadinesstraversal. While the variable is set, product code under test in parallel classes records stages into the same static traversal. For example,RepoCodePageViewModel.SelectFileAsynccallsRecordTraversalStage("repo_code.selection.started")from thread-pool threads. Those calls reach the test'sList<T>handler at the same time as the test's own calls. The class-localReadinessGatelock only serialized the class against itself.The flake did not show up naturally on
main: 150 full-suite runs and 300 targeted runs (this class next toRepoCodePageViewModelTests) all passed. The race window is only two calls wide. To confirm the mechanism, a temporary harness ran the real test method 20,000 times while 3 threads made that sameRecordTraversalStagecall:Assert.Single() Failure: The collection did not contain any matching items(a foreignAddoverwrotebefore.commit)NullReferenceException(corrupted list)InvalidOperationException: Collection was modified(duringAssert.Single)After the fix, the same harness gave 0 / 20,000. The harness is not committed.
Fix
ProductPerformanceReadinessTraversalTestsclass, in aDisableParallelizationcollection, so xUnit runs them alone after the parallel collections finish. This also stops the environment variable from leakingIsEnabled == trueinto other tests' product code. It follows theRequestTransportTimingCollectionprecedent from Make Phase0 service tests deterministic under parallel load #107.ConcurrentQueueand assert on one snapshot. The static event can be raised from any thread, so a late continuation from an earlier test cannot corrupt the list.Interlocked.ReadinessGatelock. The tracker tests that don't touch static state stay inProductPerformanceObservationTestsand keep running in parallel.No assertion changed, and no product code changed.
Validation
dotnet test JitHub.WinUI.Tests -c Debug -p:Platform=x64: 10 of 10 full runs passed (2,888 tests, same count as before).packages.lock.jsondrift.🤖 Generated with Claude Code