test(act): property-based suite covering five framework invariants#647
Merged
Conversation
…riants Introduces fast-check + @fast-check/vitest as workspace dev deps and adds 5 property suites under libs/act/test/property/ targeting the framework's load-bearing contracts. 100 cases per property by default (50 for the heavier action()-driven suites), no flakiness across 5 consecutive soak runs locally. Suites: - commit-version.property — per-stream `version` is strictly monotonic starting at 0 regardless of cross-stream interleaving; expectedVersion enforcement throws and commits no events on mismatch. - claim-lifecycle.property — every successful claim() reaches ack() or block() (no leaks); ack monotonically advances per-stream watermarks; blocked streams cannot be re-claimed. - cache-coherence.property — after any random sequence of action()s, cached load() equals fresh-load (cache cleared) state-and-version for every stream; ConcurrencyError invalidates the cached entry; snapshot.version equals the head event's version. - correlate-drain.property — every committed reactive event is delivered to exactly one handler invocation after enough drains (no losses, no duplicates); drain is idempotent once settled. - close.property — close() with restart=false makes subsequent action() throw StreamClosedError; close() is idempotent on already- tombstoned streams; close() with restart=true preserves observable state. These complement the existing 957 imperative tests by covering combinatorial input space the hand-written tests can't reach. The 2 deferred suites from the original PR-B1 plan (correlate-drain and close) are included here; B1 lands as a single comprehensive PR rather than the originally-proposed staged rollout. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
🎉 This PR is included in version @rotorsoft/act-v0.33.1 🎉 The release is available on:
Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
PR-B1 from the architectural plan. Adds
fast-check+@fast-check/vitestand 5 property suites that exercise the framework's load-bearing contracts under combinatorially-generated input.The 5 suites cover what hand-written tests can't reach: arbitrary commit interleavings, lease lifecycle traces, sequences of
action()s with cache invalidation, exhaustive correlate→drain delivery, and close idempotency.Suites added
commit-version.property.spec.tsversionis strictly monotonic from 0 regardless of cross-stream interleaving; (2)expectedVersionenforcement throws and commits no events on mismatchclaim-lifecycle.property.spec.tsclaim()reachesack()orblock()(no leaks); (2)ack()advances per-stream watermarks monotonically; (3) blocked streams cannot be re-claimedcache-coherence.property.spec.tsload()equals fresh-load (cache cleared) state-for-state and version-for-version; (2)ConcurrencyErrorinvalidates the cached entry; (3)snapshot.versionequals the head event's versioncorrelate-drain.property.spec.tsclose.property.spec.tsclose({restart:false})makes subsequentaction()throwStreamClosedError; (2)close()is idempotent on already-tombstoned streams; (3)close({restart:true})preserves observable state13 properties total, ~750 generated cases per CI build (100 per
commit-versionandclaim-lifecycleproperties; 50 per the heavieraction()-driven ones).Why all 5 in one PR
Originally I proposed staging this as 3-now / 2-later. But:
target()helper,beforeEach/afterEachports setup) is the same across suitesYou explicitly asked for all 5 in one PR; this delivers that.
Verification
Property failed after 1 tests { seed: -1219815470, path: "0:1:0:2:2:3:3", endOnFailure: true }) — caught one bug in my initial cache-coherence assertion logic during developmentWhat's intentionally NOT in this PR
InMemoryStore. Same suites againstact-pg/act-sqlitebelongs in PR-C1 (concurrency stress harness).🤖 Generated with Claude Code