Repository navigation
fix(engine): order keyed NotInParallel tests by priority, not hash code - #7090
Conversation
TestGroupingService passed TestPriority.GetHashCode() to ConstraintKeyScheduler as the sort key for keyed [NotInParallel] tests. The record struct hash does not preserve ordering: with the default priority, any Order above ~894M (including the default Order) wraps negative, and different ExecutionPriority values land in arbitrary positions. Pass a dense rank derived from TestPriority's ordering instead, for both the top-level keyed list and constrained parallel groups. Fixes #7088
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 5 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
[Medium impact] The PR appears safe to merge. SummaryReplaces hash-based sort keys with ordered ranks for keyed
Reviews (1) · Last reviewed commit: "fix(engine): order keyed NotInParallel t..." · Reviewed by Greptile |
ReviewThe fix is correct and well-scoped. I found no blocking issues.
Two non-blocking notes:
LGTM. |
Fixes #7088
Root cause
TestGroupingServicesorted keyed[NotInParallel]tests correctly. It then passedTestPriority.GetHashCode()toConstraintKeyScheduleras each test'sintsort key. The scheduler sorts on that key and also uses it to choose which waiting test starts when a key is released. The compiler-generatedrecord structhash is roughly(int)Priority * -1521134295 + Order, computed with wrap-around, so it does not preserve ordering:Normalpriority, anyOrderabove about 894M wraps to a negative number. That includes the defaultOrder(int.MaxValue / 2), so keyed tests without anOrderran before tests withOrder = 1.[ExecutionPriority]values landed in arbitrary positions.Both hash sites were affected: the top-level keyed list and the keyed list of each constrained parallel group (
[ParallelGroup]+ keyed[NotInParallel]).Fix
The change is confined to
TestGroupingService;ConstraintKeyScheduleris untouched. Both keyed lists are now sorted withTestPriority.CompareTo(highest priority first, then ascendingOrder), with class name as the tie-break. Each test then gets a dense rank as itsintkey instead of the hash: tests that compare equal on priority share a rank. Because the scheduler's sort is stable on the original index, it keeps this order. The change adds no allocations: one int counter per list, and the sort lambdas are nowstatic.For the common case (default priority, small
Ordervalues), the resulting run order is the same as before, because the hash happened to be monotonic there.Tests
tests/TUnit.TestProject/Bugs/7088/KeyedNotInParallelOrderTests.cscovers keyed tests at top level and inside a[ParallelGroup]. They mixOrder = 1/2/3,Order = 1_000_000_000, the defaultOrder, and an[ExecutionPriority(High)]test. Each test checks that the tests that started before it are exactly the expected prefix.Order1000000000, DefaultOrder, HighPriority_Order50, Order1, Order2, Order3.tests/TUnit.Engine.Tests/Scheduling/KeyedNotInParallelOrderTests.csruns the above through the engine harness. Reflection passes locally; the AOT cases are CI-only.NotInParallelOrderExecutionTests,NotInParallelMixedTests,*ConstraintKey*and*NotInParallel*. The only failure under*NotInParallel*is the intentionalNotInParallelWithDependsOnTests.Step1.TUnit.UnitTestspasses (526 passed, 3 skipped). TheTUnit.Engine.TestsfiltersScheduling/*and*NotInParallel*pass, with AOT cases skipped locally.Overlap with open PRs
#7084 and #7087 both edit
src/TUnit.Engine/Scheduling/ConstraintKeyScheduler.cs. This PR does not touch that file, so there is no textual conflict. The scheduler still treatsPriorityas "lower runs first", which now holds by construction.