Skip to content

Stabilize flaky TimeOutTask timing test under parallel/coverage (#191) - #192

Merged
drmoisan merged 1 commit into
mainfrom
bug/timeout-task-flaky-timing
Jun 13, 2026
Merged

Stabilize flaky TimeOutTask timing test under parallel/coverage (#191)#192
drmoisan merged 1 commit into
mainfrom
bug/timeout-task-flaky-timing

Conversation

@drmoisan

Copy link
Copy Markdown
Owner

Stabilize flaky TimeOutTask timing test under parallel/coverage execution

Summary

  • Fixes the intermittent failure of TimeOutTask_Tests.RunWithTimeout_FuncT1TResult_ShouldReturnResult under class-level parallelism and code-coverage instrumentation.
  • Test-only change: no production code is modified and UtilitiesCS/Threading/TimeOutTask.cs is untouched.
  • Applies two established repository patterns together: [DoNotParallelize] on the test class plus a generous success-path timeout.
  • Determinism demonstrated across 13/13 parallel + coverage runs with zero TimeoutException.

Why

The test runs a trivial synchronous function (arg => $"result-{arg}") but asserts completion within a 200 ms wall-clock window via RunWithTimeout(..., milliseconds: 200, strict: true). The function is scheduled on the thread pool and raced against that timeout. Under Workers=0 class-level parallelism — aggravated by coverage instrumentation overhead — thread-pool starvation can push the trivial work past 200 ms, the timeout wins, and strict mode throws TimeoutException. The production RunWithTimeout is correct (timing out under genuine starvation is the intended behavior); the defect is the test's wall-clock/thread-pool sensitivity. TimeOutTask.cs is already ~775 lines, so a production TimeProvider refactor across every overload would be disproportionate.

What Changed

  • UtilitiesCS.Test/Threading/TimeOutTask_Tests.cs — added [DoNotParallelize] beneath [TestClass] on the single attributed partial declaration, which governs the whole TimeOutTask_Tests partial class (mirrors ApplicationIdleTimer_Tests / TimerWrapper_Tests).
  • UtilitiesCS.Test/Threading/TimeOutTask_AdditionalTests.cs — widened the success-path timeout in RunWithTimeout_FuncT1TResult_ShouldReturnResult from milliseconds: 200 to milliseconds: 5000 (mirrors the existing generous-timeout precedent in TimeOutTask_Tests). The assertion result.Should().Be("result-42") and maxAttempts: 0, strict: true are unchanged.

Both mitigations are applied together: [DoNotParallelize] removes intra-class contention, and the generous timeout removes the residual cross-class thread-pool-starvation race for trivially-completing work. The assertion's intent (result correctness) is preserved — only the wall-clock race is removed, so this is not a latency assertion being masked.

Verification

Completed:

  • Determinism: 12 parallel runs + 1 coverage run of the affected test all passed (13/13), zero TimeoutException.
  • C# toolchain for the changed assembly: CSharpier check clean on the two .cs files; .NET analyzers 0 errors and zero diagnostics on changed files; zero nullable diagnostics on changed files; MSTest run shows the affected test passing and UtilitiesCS.dll line coverage 85.31% (>= 80%).

Notes (pre-existing, out of scope):

  • A separate pre-existing flaky test (IdleAsyncQueue_Tests.AddEntry_UseUiThreadTrue_DequeuesEntryAndSuppressesDispatcherException) failed in the full parallel run but passes in isolation; it is unrelated to this change and not in the diff.
  • The whole-solution nullable/TreatWarningsAsErrors build fails only because of the pre-existing vendored-project breakage excluded by .claude/rules/csharp.md; the changed files introduce zero diagnostics.

Backward Compatibility / Migration Notes

  • No production or public API change. Test behavior only: the TimeOutTask_Tests class now runs non-parallel, and one success-path test uses a larger timeout bound.

Risks and Mitigations

  • Risk: [DoNotParallelize] slightly increases wall-clock time for this class. Mitigation: the class is small; the determinism gain outweighs the cost.
  • Rollback: revert this PR; the change is confined to two test files.

Review Guide

  • UtilitiesCS.Test/Threading/TimeOutTask_Tests.cs (one-line attribute) and TimeOutTask_AdditionalTests.cs (one-argument change) are the entire functional diff. The remaining files are the governance/audit trail under docs/features/active/2026-06-12-timeout-task-flaky-timing-191/.

Follow-ups

  • Out of scope, noted during execution: CSharpier v1 format . reformats .csproj files; consider adding *.csproj/*.props/*.targets to .csharpierignore so the formatter does not touch project files.

GitHub Auto-close

…verage (#191)

RunWithTimeout_FuncT1TResult_ShouldReturnResult ran a trivial synchronous
function but asserted completion within a 200ms wall-clock window; under
class-level parallelism (Workers=0) aggravated by coverage instrumentation,
thread-pool starvation breached the window and strict mode threw
TimeoutException. Production RunWithTimeout behaves correctly; the defect was
the test's wall-clock/thread-pool sensitivity.

Test-only fix applying two established repo patterns together:
- [DoNotParallelize] on the TimeOutTask_Tests partial class (mirrors
  ApplicationIdleTimer_Tests / TimerWrapper_Tests).
- Widen the success-path timeout 200ms -> 5000ms (mirrors the existing
  TimeOutTask_Tests generous-timeout precedent). Assertion result == "result-42"
  and maxAttempts: 0, strict: true are preserved.

No production file changed; TimeOutTask.cs untouched. Determinism demonstrated:
13/13 parallel + coverage runs passed with zero TimeoutException. C# toolchain
clean for the changed assembly (zero new analyzer/nullable diagnostics).

Closes #191

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@drmoisan
drmoisan force-pushed the bug/timeout-task-flaky-timing branch from 365690b to af57ca3 Compare June 13, 2026 01:22
@drmoisan
drmoisan merged commit 4a21a5b into main Jun 13, 2026
2 checks passed
@drmoisan
drmoisan deleted the bug/timeout-task-flaky-timing branch June 13, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: timeout-task-flaky-timing

1 participant