fix(worker): StaWaitHelper regression tests + full-drain contract notes; consolidate wait P/Invoke
This commit is contained in:
+18
-10
@@ -113,25 +113,33 @@ public sealed class MxAccessWriteCompletionCacheTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the wait is message/signal-driven rather than sleep-polled:
|
||||
/// with a poll interval far longer than the deadline, a completion
|
||||
/// recorded from another thread still wakes the wait and is returned well
|
||||
/// inside the deadline. The sleep-polled loop this replaced would have sat
|
||||
/// blind for the whole 10 s interval — on the STA that means 10 s with no
|
||||
/// Verifies the wait slice stays bounded no matter what poll interval the
|
||||
/// caller asks for: with a 10 s interval and a 3 s deadline, a completion
|
||||
/// recorded 50 ms in is still returned in time, because every slice is
|
||||
/// capped at the 50 ms fallback tick. The blind <c>Thread.Sleep</c> this
|
||||
/// replaced would have slept the full interval — on the STA, 10 s with no
|
||||
/// Windows messages dispatched — and then reported a timeout.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Scope: this proves the cadence bound, not the signal path. The clamp
|
||||
/// alone would satisfy it, so it stays green if the <c>Record</c>-side
|
||||
/// <c>Set()</c> is deleted. <c>StaWaitHelperTests</c> owns the signal
|
||||
/// path, where a five-second wait with no clamp in play makes the handle
|
||||
/// the only thing that can end it early.
|
||||
/// </remarks>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public void TryWaitForCompletion_WakesOnCrossThreadRecord_DespiteLongPollInterval()
|
||||
public async Task TryWaitForCompletion_CompletesWithinDeadline_WhenPollIntervalExceedsTheFallbackTick()
|
||||
{
|
||||
MxAccessWriteCompletionCache cache = new();
|
||||
using ManualResetEventSlim waitEntered = new(false);
|
||||
|
||||
Task recorder = Task.Run(() =>
|
||||
Task recorder = Task.Run(async () =>
|
||||
{
|
||||
// Handshake so the completion cannot land before the wait starts —
|
||||
// otherwise the first check would satisfy it and prove nothing.
|
||||
waitEntered.Wait(TimeSpan.FromSeconds(5));
|
||||
Thread.Sleep(50);
|
||||
await Task.Delay(50, CancellationToken.None);
|
||||
cache.Record(7, 21, BuildStatuses(detail: 8080));
|
||||
});
|
||||
|
||||
@@ -145,13 +153,13 @@ public sealed class MxAccessWriteCompletionCacheTests
|
||||
out RepeatedField<MxStatusProxy> statuses,
|
||||
pollIntervalMs: 10_000);
|
||||
elapsed.Stop();
|
||||
recorder.Wait(TimeSpan.FromSeconds(5));
|
||||
await recorder;
|
||||
|
||||
Assert.True(found);
|
||||
Assert.Equal(8080, Assert.Single(statuses).Detail);
|
||||
Assert.True(
|
||||
elapsed.Elapsed < TimeSpan.FromSeconds(2),
|
||||
$"The wait should have woken on the recorded completion, not slept out the poll interval; took {elapsed.ElapsedMilliseconds} ms.");
|
||||
$"The wait should have re-checked within the fallback tick, not slept out the poll interval; took {elapsed.ElapsedMilliseconds} ms.");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Record stores an independent clone of the caller's rows.</summary>
|
||||
|
||||
Reference in New Issue
Block a user