Repository navigation
Tests: the ManagedConf crash hook and the Lite time settings are no longer shared between parallel test classes (#4773, #4776) - #4817
Merged
Conversation
4 of 5 tasks
erikdarlingdata
marked this pull request as ready for review
September 29, 2026 13:01
… not one that clears it (#4773) The pattern matched '= null' (the second whitespace run backtracked to nothing, so the lookahead saw the space rather than 'null') and '== null', although its doc says an assignment of anything but null. It now refuses '==' and looks past all the whitespace before it checks for null. A theory runs the pattern on strings: '= null', '=null', an extra space, a line break before null, and '== null' do not match; an assignment of a lambda does.
… member that reads the shared settings (#4776) ConvertForDisplay, DisplayTimeToServerTime and GetTimezoneLabel read the shared offset but were missing from the member list, so a test class that called only one of them was never asked to join the server-time-helper collection. They are in the list now. The two-argument DisplayTimeToServerTime reads the offset; the three-argument overload takes it as an argument and reads nothing, but the pattern cannot tell them apart, which the doc comment says. Every test file that calls one of the added members already carries the collection, so no attribute or exemption was needed.
The comment said every test class clears the hook in its constructor; only the two ManagedConf classes do. It now says what the cases protect: a class that only clears or compares the hook must not be counted as arming it.
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.
Fixes #4773
Fixes #4776
Two test-only fixes for tests that fail because another test class changes process-wide state while they run. Commits are grouped by issue.
#4773: the two ManagedConf migration classes shared a crash hook
Why
ManagedConfMigrationSteps.FailBetweenStepsis one static field for the whole test process.ManagedConfMigrationStepsTestsandManagedConfMigrationRunnerTestsboth set it to throw a simulated crash, and neither had a[Collection], so xUnit could run them at the same time. When they overlapped, a test in one class threw the other class's crash: in a full runManagedConfMigrationRunnerTests.RunStepA_Mismatch_RestoresAndListsTheKeyfailed with "simulated crash between steps", a message that only exists in the steps class.What changes
ManagedConfCrashHookCollection:[CollectionDefinition("managed-conf-crash-hook", DisableParallelization = true)], the same shape asPgFileSettingsStaticsCollection. Both classes now carry[Collection("managed-conf-crash-hook")].DisableParallelizationalso keeps every other class off the hook while these run, including a class that reachesWriteTwoStepsonly throughDarlingManagedPostgres.ManagedConfCrashHookCollectionTests(two tests, plus the theory in the next bullet): both classes carry that collection and the collection disables parallelization; and every test file in Darling.Tests that assigns a non-null value toFailBetweenStepscarries the collection, so a third class added later cannot arm the hook outside it.= nulland== nulltoo, although its doc says an assignment of anything butnull: the whitespace after=backtracked to nothing, so the lookahead saw a space instead ofnull, and==was not excluded. A test file that only clears or compares the hook would have been counted as arming it and told to join the collection. The pattern is nowFailBetweenSteps\s*=(?!=)\s*(?!\s|null\b), and a new theory,ArmsTheHook_MatchesAnAssignmentThatArms_NotOneThatClearsOrComparesTheHook(8 cases), runs it on strings:= null;,=null;,= null;, a line break beforenulland== nulldo not match;= () => throw new IOException(),= _ => throw new IOException()and a line break before the lambda do.Reproduction
I ran the two classes together 10 times in one process before the fix (45 tests each). All 10 passed: the whole pair finishes in about 0.4 s, so the two rarely overlap. The failure is not reproduced here. Instead, the shared state was put back and the new guard shown to catch it (below).
RED plants
Each plant was applied on top of the fix, the guard class was run, and the plant was removed.
[Collection("managed-conf-crash-hook")]removed fromManagedConfMigrationRunnerTests(the shared state back)EveryTestFileThatArmsTheHook_CarriesTheCollection:These test files arm ManagedConfMigrationSteps.FailBetweenSteps without [Collection("managed-conf-crash-hook")], so they can crash another class's WriteTwoSteps call: ManagedConfMigrationRunnerTests.cs.TheClassesThatArmTheHook_ShareOneCollection_ThatRunsAlone:ManagedConfMigrationRunnerTests sets ManagedConfMigrationSteps.FailBetweenSteps, a static shared by the whole test process, so it must carry [Collection("managed-conf-crash-hook")]; found no [Collection] attribute.DisableParallelization = trueremoved from the collection definitionTheClassesThatArmTheHook_ShareOneCollection_ThatRunsAlone:The "managed-conf-crash-hook" collection must disable parallelization: without it the two classes are serialized against each other only, and any other class that reaches WriteTwoSteps can still meet a crash that was armed for someone else.#4776: QueryWindowTruncationTests depended on another class's time settings
Why
SetWindowTruncatedBanner_Truncated_ShowsSinceEffectiveStartformats the same time twice withServerTimeHelper.FormatServerTime: once insideServerTab.SetWindowTruncatedBannerand once in its assertion.FormatServerTimereadsServerTimeHelper.UtcOffsetMinutesandServerTimeHelper.CurrentDisplayMode, settings shared by the whole test process. The classes that change them are in[Collection("server-time-helper")], butQueryWindowTruncationTestswas not, so a writer could run between the two calls and the two texts differed.What changes
QueryWindowTruncationTestsnow carries[Collection("server-time-helper")]. Every assertion stays.ServerTimeHelperCollectionTests(two tests):QueryWindowTruncationTestscarries the collection; and every Lite.Tests source file that usesServerTimeHelper.UtcOffsetMinutes,CurrentDisplayMode,ToServerTime,ConvertForDisplay,DisplayTimeToServerTime,GetTimezoneLabel,FormatServerTimeorFormatServerClockin code (comments are ignored) carries it. One file,ComparisonWindowUtcTests.cs, is allowed because it only namesUtcOffsetMinutesinside a string it searches product source for; the allowance states why. The scan foundQueryWindowTruncationTests.csand no other file outside the collection.ConvertForDisplay,DisplayTimeToServerTimeandGetTimezoneLabel. Each reads_utcOffsetMinutes(ConvertForDisplayin the local-time and UTC modes,GetTimezoneLabelin the server-time mode, the two-argumentDisplayTimeToServerTimealways) but was missing from the list, so a test class that called only one of them was never asked to join the collection. The pattern cannot tell the twoDisplayTimeToServerTimeoverloads apart, and the three-argument one reads no setting, so a file that calls only that one belongs in the allowance; the doc comment on the pattern says so. No test file needed the attribute or an allowance: the only file that calls an added member,AlertBadgeServerOffsetTests, already carries the collection.Reproduction
Before the fix,
QueryWindowTruncationTestswas run 10 times together with four classes that write the settings (ServerClockRendererArithmeticTests,McpServerLocalOffsetTests,AlertBadgeServerOffsetTests,TimeHonestyRungTests). One of the 10 runs (run 3) failed:Before the fix the new guard also failed on the real code (2 of 2):
QueryWindowTruncationTests_IsInTheServerTimeHelperCollection:QueryWindowTruncationTests formats one time twice with ServerTimeHelper.FormatServerTime, which reads settings shared by the whole test process, so it must carry [Collection("server-time-helper")]; found no [Collection] attribute.EveryTestFileThatReadsTheSettings_CarriesTheCollection:These test files use ServerTimeHelper's shared settings without [Collection("server-time-helper")], so a class that changes them can run between two of their reads: QueryWindowTruncationTests.csAfter the fix the same 10-run loop, plus the two new guard tests (42 tests per run), passed 10 of 10.
Test plan
ManagedConfMigrationStepsTests,ManagedConfMigrationRunnerTests,ManagedConfCrashHookCollectionTestsandDocCommentHygienetogether with the otherManagedConf*classes: 265 total, 0 failed, 9 skipped (live tests that needDARLING_TEST_PGor a runtime).QueryWindowTruncationTests,ServerTimeHelperCollectionTestsand the four writer classes after merging origin/dev: 42 total, 0 failed.ArmsTheHook_MatchesAnAssignmentThatArms_NotOneThatClearsOrComparesTheHook. RED on the old pattern: 4 of 8 cases fail withAssert.Equal() Failure: Values differ, Expected: False, Actual: True(= null;,= null;, a line break beforenull, and== null;=null;passed even then). After the change: 8 of 8 pass, andManagedConfCrashHookCollectionTestspasses 10 of 10.ServerTimeHelper.GetTimezoneLabeland carries no collection: with the old member listServerTimeHelperCollectionTestspassed 2 of 2 (the guard could not see the class); with the new listEveryTestFileThatReadsTheSettings_CarriesTheCollectionfailed (1 of 2) and named only the temporary file:These test files use ServerTimeHelper's shared settings without [Collection("server-time-helper")], so a class that changes them can run between two of their reads: PlantedTimezoneLabelTemp.cs. The temporary file was deleted and is in no commit. Without it the guard passes 2 of 2.ManagedConfCrashHookCollectionTests,ManagedConfMigrationStepsTests,ManagedConfMigrationRunnerTestsandDocCommentHygiene: 132 total, 0 failed. LiteServerTimeHelperCollectionTests: 2 total, 0 failed.CHANGELOG
SECTION: None