Repository navigation
fix(core): hold shared instances fetched while runtime tests register - #7391
Conversation
|
@codex review |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
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. |
Review of #7391I found no blocking issues. The approach matches the first option in #7263: take the reference at fetch time, so the race window is closed rather than narrowed. What looks right
Minor, non-blocking
Looks good to merge once CI passes. |
|
Codex Review: Didn't find any major issues. Keep it up! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Disposition of the two non-blocking notes in the Claude review (#7391 (comment)):
Both reviewers approved head |
Review of #7391I found no blocking issues. The approach is sound: take the reference at fetch time, under Minor points, none blocking:
Overall the PR looks good to merge. |
[Medium impact] The PR appears safe to merge; no new actionable issue remains. SummaryThe PR keeps shared instances alive while runtime tests are built and registered.
No new actionable issues were found. Validation in this review was limited to reading code; no tests were run.
|
…7263) Review on #7391: releasing a registration hold could dispose a shared value that a test failing at registration still exposes to its ITestEndEventReceiver. Track what resolved before rethrowing, so the failed test holds it until it ends. Also cover the refused registration hold, and make ReleaseRegistrationHoldsAsync internal like its neighbours.
|
Disposition of the minor notes in the second Claude review (#7391 (comment)):
85020f6 also fixes the Greptile P1 (values resolved before a sibling property throws are now tracked) and adds the refused-hold test from the Greptile P2. |
|
@codex review |
Review of #7391I reviewed the diff and found no blocking issues. I did not run the tests. The What looks right
Suggestions (non-blocking)
The change looks good overall. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 85020f6821
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
Tests that are built and registered while other tests run (
AddDynamicTest,CreateTestVariant, and expanded deferred-enumeration placeholders) could receive a cachedPerClass/PerAssembly/PerTestSession/Keyedinstance, and the last running holder of that instance could then end before registration counted it. The holder then retired and disposed the instance, and the new test ran with a disposed object.This PR makes registration take its reference before retirement can happen, which is the first option in the issue.
ObjectTracker.BeginRegistrationHolds()/ReleaseRegistrationHoldsAsync()bracket building plus registration in the three runtime paths (TestRegistry.ProcessPendingDynamicTests,TestRegistry.CreateTestVariantInternal,DeferredTestExpander.ExpandAsync). The holds live in anAsyncLocal, so they also reachParallel.ForEachAsyncregistration workers.TestDataContainer.GetOrCreatecallsObjectTracker.TryHoldForRegistrationon each fetch in such a flow. The method takess_sharedInstanceLock, re-checksIsCached, and increments the counter. This follows the same rule asTryHoldForRunningTest: an instance is either held or retired, never both. When the instance has just been retired, the fetch loops and the cache creates a new instance.finally), the holds are released. Releasing disposes only instances that no registered test kept, such as an instance created for a test whose registration failed. Before this change such an instance stayed alive until the session-end sweep.Volatile.Readof an int, so discovery-time fetches pay almost nothing. Initial discovery is not bracketed, because no tests are running while it registers.The issue's suggestion of re-resolving inside
TrackObjectswas not used. Class and method arguments are produced by the builder before registration, so there is nothing left to re-resolve at that point. Holding the instance at fetch time removes the race window entirely.Tests
New tests in
tests/TUnit.UnitTests/SharedInstanceLifetimeTests.cs, all deterministic:Test_Registered_While_The_Last_Holder_Ends_Keeps_The_InstanceTest_Registered_Between_The_Count_Reaching_Zero_And_Retirement_Keeps_The_Instance: uses the synchronousOnDisposedcallback, as the issue suggests, to fetch between the decrement and the retirement.Registration_Fetching_A_Retired_Instance_Gets_A_New_OneFetches_After_Holds_Are_Released_Are_Not_HeldWith the hold disabled, the first three fail. With it, they pass.
Validation
tests/TUnit.UnitTestsnet10.0: 689 succeeded, 0 failed (4 skipped)Bugs._7204(6/6 source-gen, 6/6--reflection),DynamicTests/Runtime(8/8),TestVariantTests(10/10),TestVariantWithClassArgsTests(2/2),DeferEnumerationTests(42/42),DeferEnumerationClassDataTests(6/6)TUnit.EngineRelease build across all TFMs: 0 warningsITestEndEventReceiverruns. NewBugs._7391regression: it fails without the fix, and 2/2 match expectations with it, in both source-gen and--reflectionmodes.Bugs._6554,_7213and_7204are unchanged in both modes, and UnitTests net10.0 passes 690/690 (4 skipped).PartialInjectionFailureDisposal7391Tests(Engine.Tests) runs in CI only.Closes #7263
Summary by CodeRabbit
Review fix (2b9f9e3): retain constructor/method arguments when argument property injection fails, and narrow the #6554 engine filter to its namespace. Added a deferred shared-argument regression; its observer fails without the fix and passes with it in source-gen and reflection modes. #7391 filter: 5 results (2 passing observers, 3 expected failures including the deferred container); #6554 filter: 2 results (1 pass, 1 expected failure), both modes. UnitTests net10.0: 691 passed, 3 skipped. Engine.Tests/AOT validation remains CI-only. Separate discoveries: #7409 and #7410.