test(winc): make the abandoned-open tests deterministic instead of timing-based - #430
Conversation
…ming-based Both abandoned-open tests raced a 150ms fault against a 50ms openTimeout and asserted an exact exception type. Task.WaitAsync(timeout) only times out when its timer fires before the task completes, so a contended runner that slipped the 50ms timer past 150ms saw the fault land first and caught InvalidOperationException instead of TimeoutException. Gate the fault on an explicit signal the test releases only after it has observed the timeout, so the ordering is guaranteed rather than likely. The behaviour under test - observing the abandoned open's fault, and disposing the port even when the logger throws - is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
PR Summary by QodoMake WINC abandoned-open tests deterministic (remove timing race)
AI Description
Diagram
High-Level Assessment
Files changed (1)
|
Code Review by Qodo
1.
|
…bal Trace state Trace.Listeners is process-global, so a test that installs a throwing listener can be reached by anything else running in the same process. This was the only Trace.Listeners usage in the repo, and it was added to a suite that is concurrently being destabilised by exactly that class of problem (#430). The test now proves the property that actually ships — a throwing StreamFrameDiscarded subscriber does not break the frame pipeline, and the next frame still decodes — using only a throwing subscriber, with a call counter so it cannot pass vacuously. SafeTrace stays in production, where it is the real fix; the codebase already treats its twin, DaqifiDevice.SafeLog, as covered through an injected logger rather than global state. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The 30s fallback outlived the tests' 10s waits, so a test that failed before releasing left the abandoned open parked on a pool thread for ~20s after the test finished - extra contention in the suite whose load sensitivity is the reason for this change. Cap at 10s and fail loudly with a distinct message so a missing ReleaseFault is diagnosed rather than mistaken for the fault under test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
/agentic_review |
Why
Two tests in
WincFlasherTestsfail on CI at random and are currently blocking every open PR in this repo — #427, #428 and #429 all went red on them, and none of those PRs touch WINC code at all. They pass when you run them on your own machine, which is the worst kind of failure: it looks like the PR broke something, and the natural next step is to start changing working code to appease it.What
The two tests now pass reliably. Nothing about the behaviour they check has changed — this is a test-only fix, no production code is touched.
How
Both tests set up a fake serial port that fails 150 ms after you open it, against an inspector that gives up waiting after 50 ms, and then assert that you get the "gave up waiting" error. That only holds if the 50 ms clock actually fires first, and on a busy CI machine running 2,485 tests it often doesn't — .NET's
WaitAsynconly reports a timeout if its timer goes off before the task finishes, so a delayed timer means the port's failure gets reported instead, and the test fails on the wrong exception type.Instead of a 150 ms delay, the fake port now waits for the test to explicitly tell it to fail, and the test only does that after it has already seen the timeout. So the order is guaranteed by construction rather than by hoping one clock beats another. The wait is capped at 30 s so a genuinely broken test reports its own failure instead of hanging.
Evidence
Inspector_ObservesTheFaultOfAnAbandonedOpen(net9.0), thenInspector_DisposesTheAbandonedPort_EvenWhenObservingTheFaultThrows(net10.0) on re-runInspector_DisposesTheAbandonedPort_EvenWhenObservingTheFaultThrows(net10.0), twicefeature/native-winc-flasher, the branch that introduced the tests, failed it on its own branch tooAssert.Throws() Failure: Exception type was not an exact matchmain@ 359bf74 passes locally 5/5 in isolation and 5/5 full-suite — it does not reproduce on an idle machine, which is why it slipped throughIntroduced by #423 (
359bf74).Not merging — for review.