Summary
ElevatedDatabaseToolsRunnerTests.RunAsync_WhenHelperKillSucceedsAfterCancel_ReportsForceKilled intermittently fails during full (parallel) runs of the EventLogExpert.Runtime.Tests suite, but passes deterministically when run in isolation. This is a test-infrastructure flake, not a product defect.
Location
tests/Unit/EventLogExpert.Runtime.Tests/DatabaseTools/Elevation/ElevatedDatabaseToolsRunnerTests.cs (method starts at line 499).
Evidence
- Full suite run:
Failed: 1, Passed: 1330 — the failure unwinds through the finally block (line ~542).
- Same test in isolation (
--filter "FullyQualifiedName~RunAsync_WhenHelperKillSucceedsAfterCancel_ReportsForceKilled"): Passed: 1 in ~0.7s, repeatedly.
Why it's flaky (hypothesis)
The test drives a cancel → force-kill → outcome handshake over named-pipe IPC and then awaits the run task with a wall-clock timeout:
cts.Cancel() triggers the runner to kill the fake helper; FakeElevatedHelperProcess.OnKilled disposes the client pipe.
- The result is awaited via
await runTask.WaitAsync(TimeSpan.FromSeconds(10), ct) and asserts Outcome == Cancelled and FailureSummary contains "force-killed".
Under CPU contention from concurrently executing tests, the cancellation → kill → outcome propagation (and/or the pipe disposal racing the reader/writer) can slip the expected window, surfacing as an intermittent timeout or assertion mismatch. With no contention (isolation) the timing is deterministic and it passes.
Suggested direction
De-flake by removing the wall-clock dependence and making the cancel → kill → outcome handshake deterministic — e.g., await explicit completion signals instead of timed waits — mirroring the earlier de-flake of DatabaseCoordinationEffectsReloadTests (deterministic cancel-on-dispatch rather than a timer race). The companion "unkillable" test in the same file shares the IPC/cancellation pattern and may warrant the same treatment.
Notes
Surfaced during full-suite runs while iterating on PR #592 (unrelated change — LogTable reducers). The failing test exercises the elevated DB-tools runner and shares no code with that change.
Summary
ElevatedDatabaseToolsRunnerTests.RunAsync_WhenHelperKillSucceedsAfterCancel_ReportsForceKilledintermittently fails during full (parallel) runs of theEventLogExpert.Runtime.Testssuite, but passes deterministically when run in isolation. This is a test-infrastructure flake, not a product defect.Location
tests/Unit/EventLogExpert.Runtime.Tests/DatabaseTools/Elevation/ElevatedDatabaseToolsRunnerTests.cs(method starts at line 499).Evidence
Failed: 1, Passed: 1330— the failure unwinds through thefinallyblock (line ~542).--filter "FullyQualifiedName~RunAsync_WhenHelperKillSucceedsAfterCancel_ReportsForceKilled"):Passed: 1in ~0.7s, repeatedly.Why it's flaky (hypothesis)
The test drives a cancel → force-kill → outcome handshake over named-pipe IPC and then awaits the run task with a wall-clock timeout:
cts.Cancel()triggers the runner to kill the fake helper;FakeElevatedHelperProcess.OnKilleddisposes the client pipe.await runTask.WaitAsync(TimeSpan.FromSeconds(10), ct)and assertsOutcome == CancelledandFailureSummarycontains"force-killed".Under CPU contention from concurrently executing tests, the cancellation → kill → outcome propagation (and/or the pipe disposal racing the reader/writer) can slip the expected window, surfacing as an intermittent timeout or assertion mismatch. With no contention (isolation) the timing is deterministic and it passes.
Suggested direction
De-flake by removing the wall-clock dependence and making the cancel → kill → outcome handshake deterministic — e.g., await explicit completion signals instead of timed waits — mirroring the earlier de-flake of
DatabaseCoordinationEffectsReloadTests(deterministic cancel-on-dispatch rather than a timer race). The companion "unkillable" test in the same file shares the IPC/cancellation pattern and may warrant the same treatment.Notes
Surfaced during full-suite runs while iterating on PR #592 (unrelated change — LogTable reducers). The failing test exercises the elevated DB-tools runner and shares no code with that change.