Skip to content

test: concurrency / race-condition stress testing with Coyote (#207) - #312

Merged
Chris-Wolfgang merged 1 commit into
vNextfrom
thorough/207-concurrency-coyote
Jul 23, 2026
Merged

test: concurrency / race-condition stress testing with Coyote (#207)#312
Chris-Wolfgang merged 1 commit into
vNextfrom
thorough/207-concurrency-coyote

Conversation

@Chris-Wolfgang

Copy link
Copy Markdown
Owner

Summary

Adds systematic concurrency testing with Microsoft Coyote (issue #207). Coyote rewrites the assemblies to control the task scheduler, then replays each test under thousands of distinct interleavings — surfacing races/deadlocks that a normal single-schedule run (a million times in CI) never hits. coyote test exits non-zero on a found bug, so it's an enforced gate.

  • tests/Wolfgang.Etl.Abstractions.Tests.Concurrency — two systematic tests over the base-class concurrency:
    • concurrent per-item counter increments never lose an update (the counter is Interlocked — a non-atomic ++ would surface as a lost update on some explored schedule);
    • DisposeAsync racing an in-flight enumeration never deadlocks.
  • .github/workflows/coyote.yaml — gates PRs touching src/** (1000 iterations/test) and runs the deep exploration weekly + on dispatch (10000 iterations/test).

Targets net8.0 deliberately: the Coyote 1.7.x CLI can't load net10.0 assemblies (it predates that runtime), and the concurrency explored is runtime-agnostic.

Validation

Ran locally (rewrite + coyote test):

  • Concurrent_item_count_increments…0 bugs, 2000 paths (1360 unique).
  • Dispose_racing_enumeration…0 bugs, 2000 paths (1604 unique).

This PR touches coyote.yaml + the concurrency project, so its own CI runs the Coyote gate end to end.

Acceptance criteria (#207)

  • A tests/…Tests.Concurrency/ project instruments key public APIs with Coyote
  • A scheduled (weekly) workflow runs Coyote with a generous budget (10000 iterations/test)
  • Optional 24h soak on a self-hosted runner — not implemented (no self-hosted runner available; documented in the workflow header for when one exists)

The two required criteria are met; the soak is the issue's own "optionally also" item.

Closes #207

Adds tests/Wolfgang.Etl.Abstractions.Tests.Concurrency + .github/workflows/coyote.yaml.
Microsoft Coyote rewrites the assemblies to control the task scheduler and replays
each test under thousands of distinct interleavings, surfacing races/deadlocks a
normal single-schedule run never hits. `coyote test` exits non-zero on a found bug,
so it is an enforced gate.

Two systematic tests over the base-class concurrency:
- concurrent per-item counter increments never lose an update (the counter is
  Interlocked — a non-atomic ++ would surface as a lost update on some schedule);
- DisposeAsync racing an in-flight enumeration never deadlocks.

Both explore ~1600 unique execution paths locally with 0 bugs found.

The project targets net8.0 because the Coyote 1.7.x CLI cannot load net10.0
assemblies (it predates that runtime); the concurrency explored is
runtime-agnostic. coyote.yaml gates PRs touching src/** (1000 iterations/test) and
runs the deep exploration weekly + on dispatch (10000 iterations/test).

The optional 24h soak (leak hunting via dotnet-counters) is NOT implemented — it
needs a persistent self-hosted runner this project lacks; documented in the
workflow header for when one exists.

Closes #207

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 23, 2026 01:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

2 participants