Skip to content

feat: add load-testing/stress-testing suite#370

Merged
jwilger merged 5 commits intomainfrom
feat/stress-testing-suite
Apr 15, 2026
Merged

feat: add load-testing/stress-testing suite#370
jwilger merged 5 commits intomainfrom
feat/stress-testing-suite

Conversation

@jwilger-ai-bot
Copy link
Copy Markdown
Collaborator

Summary

  • Add eventcore-stress binary crate with 5 stress test scenarios (contention, throughput, transfers, projection, pool-saturation) measuring sustained concurrent load against all EventStore backends
  • Upgrade rand 0.9→0.10 and mutants 0.0.3→0.0.4; bump rustls-webpki to resolve RUSTSEC-2026-0098/0099
  • Binary is excluded from CI (no #[test] fns), mutation testing, and cargo nextest run --workspace

Test plan

  • cargo clippy --workspace --all-targets --all-features passes
  • cargo nextest run --workspace — 193 tests pass, stress tests not discovered
  • cargo run -p eventcore-stress -- run-all --backend memory — all scenarios PASS correctness
  • cargo run -p eventcore-stress -- contention --backend sqlite — SQLite backend works
  • cargo audit — no vulnerabilities

🤖 Generated with Claude Code

Add eventcore-stress, a binary crate for sustained concurrent load
testing against all EventStore backends. Unlike the existing Criterion
micro-benchmarks (eventcore-bench) which measure single-operation
latency, this suite measures system behavior under concurrent load:
throughput, tail latencies (p50/p95/p99), retry rates, and correctness.

Five scenarios exercise different contention patterns:
- contention: N tasks deposit to one shared stream (version conflicts)
- throughput: per-task streams measuring raw store throughput
- transfers: multi-stream atomic transfers with conservation checks
- projection: batch-mode projection catch-up after concurrent writes
- pool-saturation: postgres-only pool exhaustion under high concurrency

The binary is never discovered by cargo nextest/test (no #[test] fns),
compiles cleanly under cargo clippy --workspace, and is excluded from
mutation testing. Run via: cargo run -p eventcore-stress -- <scenario>

Also bumps rustls-webpki 0.103.10 -> 0.103.12 to resolve
RUSTSEC-2026-0098 and RUSTSEC-2026-0099.
Bump rand to 0.10 across eventcore, eventcore-testing, and
eventcore-stress. The Rng trait methods (random_range, random_bool)
moved to RngExt in 0.10, so imports are updated accordingly.

Bump mutants dev-dependency to 0.0.4 in eventcore-postgres (used only
for #[mutants::skip] attributes).

rusqlite remains at 0.32: upgrading to 0.39 is blocked by a
libsqlite3-sys links conflict between rusqlite and sqlx-sqlite, which
both require different major versions of the sys crate.
The projection stress test scenario reported Correctness: FAIL on
PostgreSQL because the database contained stale events from contract
tests and previous runs. The first batch of events (LIMIT 1000) was
entirely non-stress-test events that failed deserialization silently.

Add clean_postgres_database() that truncates eventcore_events and
eventcore_subscription_versions before each stress test run when using
the postgres backend. TRUNCATE is used instead of DELETE to bypass the
row-level delete-prevention trigger.

Closes #371
The projection scenario needs a clean database for its correctness
check (expects exactly N streams). Previous scenarios in run-all
(contention, throughput, transfers) fill the table with unrelated
BankAccountEvents. Batch-mode projection reads only the first 1000
events which were all from the contention scenario, finding 1 stream
instead of 50.

Add a truncation step before the projection scenario within run-all
so it starts from a clean slate, matching the behavior of in-memory
and SQLite backends which create fresh stores per scenario.
@jwilger jwilger enabled auto-merge (squash) April 15, 2026 19:40
@jwilger jwilger merged commit dac41b5 into main Apr 15, 2026
18 checks passed
@jwilger jwilger deleted the feat/stress-testing-suite branch April 15, 2026 19:41
@jwilger jwilger mentioned this pull request Apr 15, 2026
jwilger-ai-bot pushed a commit that referenced this pull request Apr 17, 2026
## 🤖 New release

* `eventcore-macros`: 0.7.0 -> 0.7.1
* `eventcore-types`: 0.7.0 -> 0.7.1 (✓ API compatible changes)
* `eventcore-postgres`: 0.7.0 -> 0.7.1 (✓ API compatible changes)
* `eventcore-sqlite`: 0.7.0 -> 0.7.1 (✓ API compatible changes)
* `eventcore`: 0.7.0 -> 0.7.1 (✓ API compatible changes)
* `eventcore-memory`: 0.7.0 -> 0.7.1 (✓ API compatible changes)
* `eventcore-testing`: 0.7.0 -> 0.7.1 (✓ API compatible changes)
* `eventcore-examples`: 0.7.0 -> 0.7.1

<details><summary><i><b>Changelog</b></i></summary><p>

## `eventcore-macros`

<blockquote>

##
[0.7.0](eventcore-macros-v0.6.0...eventcore-macros-v0.7.0)
- 2026-04-13

### Bug Fixes

- improve error message consistency, context, and safety across all
crates ([#352](#352))

### Features

- enhance require! macro to accept typed error values
([#335](#335))
- add required event_type_name() to Event trait for stable storage
([#344](#344))

### Miscellaneous Tasks

- adopt han plugins, blueprints, and project conventions
([#330](#330))
- consolidate workspace lints and enforce strict lint policy
([#351](#351))

### Refactoring

- expose projection config via free function API, then reduce public
surface ([#357](#357))
</blockquote>

## `eventcore-types`

<blockquote>

##
[0.7.1](eventcore-types-v0.7.0...eventcore-types-v0.7.1)
- 2026-04-15

### Bug Fixes

- filter read_events by event_type to prevent projection stalls
([#373](#373))
</blockquote>

## `eventcore-postgres`

<blockquote>

##
[0.7.1](eventcore-postgres-v0.7.0...eventcore-postgres-v0.7.1)
- 2026-04-15

### Bug Fixes

- filter read_events by event_type to prevent projection stalls
([#373](#373))

### Features

- add load-testing/stress-testing suite
([#370](#370))
</blockquote>

## `eventcore-sqlite`

<blockquote>

##
[0.7.1](eventcore-sqlite-v0.7.0...eventcore-sqlite-v0.7.1)
- 2026-04-15

### Bug Fixes

- filter read_events by event_type to prevent projection stalls
([#373](#373))
</blockquote>

## `eventcore`

<blockquote>

##
[0.7.1](eventcore-v0.7.0...eventcore-v0.7.1)
- 2026-04-15

### Bug Fixes

- filter read_events by event_type to prevent projection stalls
([#373](#373))

### Features

- add load-testing/stress-testing suite
([#370](#370))
</blockquote>

## `eventcore-memory`

<blockquote>

##
[0.7.1](eventcore-memory-v0.7.0...eventcore-memory-v0.7.1)
- 2026-04-15

### Bug Fixes

- filter read_events by event_type to prevent projection stalls
([#373](#373))
</blockquote>

## `eventcore-testing`

<blockquote>

##
[0.7.1](eventcore-testing-v0.7.0...eventcore-testing-v0.7.1)
- 2026-04-15

### Features

- add load-testing/stress-testing suite
([#370](#370))
</blockquote>

## `eventcore-examples`

<blockquote>

##
[0.7.0](eventcore-examples-v0.6.0...eventcore-examples-v0.7.0)
- 2026-04-13

### Bug Fixes

- improve error message consistency, context, and safety across all
crates ([#352](#352))

### Features

- add required event_type_name() to Event trait for stable storage
([#344](#344))
- add TestScenario GWT testing helpers to eventcore-testing
([#346](#346))

### Miscellaneous Tasks

- consolidate workspace lints and enforce strict lint policy
([#351](#351))

### Refactoring

- replace into_inner() with into() for nutype domain types
([#334](#334))
- expose projection config via free function API, then reduce public
surface ([#357](#357))
</blockquote>


</p></details>

---
This PR was generated with
[release-plz](https://github.com/release-plz/release-plz/).
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