fix(worker): StaWaitHelper regression tests + full-drain contract notes; consolidate wait P/Invoke
This commit is contained in:
@@ -179,27 +179,35 @@ public sealed class MxAccessValueCacheTests
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the wait is message/signal-driven rather than sleep-polled:
|
||||
/// with a poll interval far longer than the deadline, a value set 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 Windows
|
||||
/// 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 value set
|
||||
/// 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, so the OnDataChange being waited for could not
|
||||
/// have arrived at all — 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>Set</c>-side
|
||||
/// signal 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 TryWaitForUpdate_WakesOnCrossThreadSet_DespiteLongPollInterval()
|
||||
public async Task TryWaitForUpdate_CompletesWithinDeadline_WhenPollIntervalExceedsTheFallbackTick()
|
||||
{
|
||||
MxAccessValueCache cache = new();
|
||||
Timestamp sourceTimestamp = Timestamp.FromDateTime(DateTime.UtcNow);
|
||||
using ManualResetEventSlim waitEntered = new(false);
|
||||
|
||||
Task setter = Task.Run(() =>
|
||||
Task setter = Task.Run(async () =>
|
||||
{
|
||||
// Handshake so the value 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.Set(7, 21, BuildEvent(7, 21, intValue: 8080, quality: 192, sourceTimestamp));
|
||||
});
|
||||
|
||||
@@ -213,13 +221,13 @@ public sealed class MxAccessValueCacheTests
|
||||
out MxAccessValueCache.CachedValue value,
|
||||
pollIntervalMs: 10_000);
|
||||
elapsed.Stop();
|
||||
setter.Wait(TimeSpan.FromSeconds(5));
|
||||
await setter;
|
||||
|
||||
Assert.True(found);
|
||||
Assert.Equal(8080, value.Value.Int32Value);
|
||||
Assert.True(
|
||||
elapsed.Elapsed < TimeSpan.FromSeconds(2),
|
||||
$"The wait should have woken on the cached value, 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>
|
||||
|
||||
Reference in New Issue
Block a user