Skip to main content

Module executors

Module executors 

Source
Expand description

An executable statement of the executor contract (I13, I14, spec §23.1).

A store proves itself against turnframe_store::conformance and a provider adapter against providers::conformance. The third thing an adopter writes is the WorkflowExecutor, and it is where optimistic concurrency and idempotency actually live: a card bound to revision N is only safe because some executor refuses a stale write, and a turn replayed after a crash is only harmless because some executor recognises the key it already committed. Those rules are prose on the trait, and prose does not fail a build.

The check nobody writes for themselves is partial-batch recovery, which is why ExecutorFactory::interrupt_after exists: the suite cannot half-commit a batch through the trait, so it asks the implementation to. docs/recipes.md describes the two shapes that defect usually takes.

Nothing here panics: every check returns a result, run_all collects them all rather than stopping at the first, and a failure names revisions, digests, error variants and check names — never a case’s state, which is the adopter’s data and is compared as a digest.

§Running it

Implement ExecutorFactory once, then hand it to run_all.

use turnframe_test::executors;
use turnframe_test::workflows::trip::conformance_case;

let report = executors::run_all(&conformance_case()).await;
assert!(report.passed(), "{report}");
assert_eq!(report.outcomes.len(), executors::CHECK_COUNT);

InMemoryCase is the reference factory: it wires the kit’s own InMemoryExecutor to any PureWorkflow, and it is the smallest complete example of what an adopter writes to point the suite at their own executor.

While an executor is still being written, run one rule at a time: every check_* function is public and takes the same factory.

§It never panics

Every check returns Result<(), ConformanceFailure> and run_all collects the results into a ConformanceReport without stopping at the first failure — a broken executor usually breaks several rules at once, and seeing all of them is faster to fix than seeing the first one seven times. Nothing here unwraps, asserts or panics, so the suite is usable outside a test harness: in a migration tool, or as a boot-time gate on a freshly written adapter.

Failure details name revisions, digests, error variants and check names. They never render a case’s state, because that state is the adopter’s data: two states are compared through canonical_digest, and a mismatch is reported as two digests.

§What is covered

CheckRule
check_stale_expected_revision_is_a_conflicta batch planned against a superseded revision is refused, and the case is not overwritten (I13)
check_commit_reports_the_revision_it_reachedthe revision in the commit is the one a later batch must be planned against
check_repeated_key_replays_the_outcomea key seen before returns the original outcome and repeats no effect (I14)
check_repeated_key_with_another_command_is_refusedthe same key carrying a different command is a mismatch, never a replay (I14)
check_per_case_batch_is_all_or_nothingone refused envelope discards the whole batch, and a PerCase batch may not span two cases
check_interrupted_batch_resumes_to_the_same_statea batch that half-committed resumes to exactly the state an uninterrupted one reaches
check_refused_command_leaves_the_case_byte_identicala refusal writes nothing at all, and stays a refusal when it is retried

Structs§

CheckOutcome
What one check concluded.
ConformanceFailure
One rule of the executor contract that an implementation broke.
ConformanceReport
The result of a whole run_all.
InMemoryCase
An ExecutorFactory over InMemoryExecutor, for any workflow whose transitions are a pure function.
SeededCase
A fresh executor, the case seeded in it, and the commands the suite drives it with.

Constants§

CHECK_COUNT
How many checks run_all runs.
CONFORMANCE_ACCOUNT
Account the reference factory seeds its case in.
CONFORMANCE_USER
User the reference factory acts as.

Traits§

ExecutorFactory
Builds a fresh executor with one case in it, once per check.

Functions§

check_commit_reports_the_revision_it_reached
The revision a commit reports is the revision the case actually reached, and the one the next batch must be planned against.
check_interrupted_batch_resumes_to_the_same_state
A batch that half-committed resumes to exactly the state an uninterrupted one reaches (spec §23.1).
check_per_case_batch_is_all_or_nothing
A PerCase batch commits entirely or not at all, and never spans two cases.
check_refused_command_leaves_the_case_byte_identical
A command the domain refuses leaves the case byte-identical, and stays a refusal when it is retried.
check_repeated_key_replays_the_outcome
A key the executor has already committed returns the original outcome and repeats no effect (I14).
check_repeated_key_with_another_command_is_refused
A key that arrives with a different command is a mismatch, never a replay (I14).
check_stale_expected_revision_is_a_conflict
A batch planned against a revision that is no longer current is refused, and the case is left exactly as it was (I13).
run_all
Runs every check against a fresh executor each and reports.

Type Aliases§

BatchOf
The batch type the suite hands to the executor under test.
CommandOf
The command type of WorkflowOf<F>.
SeedOf
The SeededCase an ExecutorFactory produces.
WorkflowOf
The workflow an ExecutorFactory builds executors for.