saga/storage/conformance
Checks a storage adapter against the saga/storage contract.
Use this module from an adapter’s own tests; it needs no test framework.
run gives each scenario a fresh fixture and fresh execution ids, and
checks atomic creation, unchanged data after refused writes, claims as
values (any holder may commit; a rebuilt claim with another token is
refused), revision and generation checks, cancellation races, release,
that a live owner keeps its claim, that a lost owner’s claim ends within
owner_loss_within, the unfinished listing, and that a
saga/durable drive whose runner is killed frees the execution at once
for the next drive, which resumes from the checkpoint. One
fixture may serve several executions, as a database pool does. The
memory, file and PostgreSQL adapters pass the same checks.
A pass covers the storage protocol from one VM; it does not certify cross-node fencing, media durability or power-loss behavior.
import gleam/time/duration
import saga/storage/conformance
let result =
conformance.run(
fn() {
let assert Ok(store) = memory.start()
Ok(conformance.fixture(memory.storage(store), cleanup: fn() {
memory.stop(store)
}))
},
timeout: duration.seconds(5),
owner_loss_within: duration.milliseconds(500),
)
owner_loss_within is the adapter’s declared window for noticing that
an owner is gone: near zero for the memory adapter, which watches the
claiming process, and the lease duration for a lease-based adapter.
Types
Why the suite failed. The union is closed.
pub type Failure {
SetupFailed(String)
UnexpectedResult(check: String)
AdapterCrashed(String)
TimedOut
InvalidTimeout
}
Constructors
-
SetupFailed(String)The fixture factory returned this error.
-
UnexpectedResult(check: String)The named check saw an unexpected result.
-
AdapterCrashed(String)An adapter operation raised; the formatted exception, for logs.
-
TimedOutA scenario did not finish in time.
-
InvalidTimeouttimeoutorowner_loss_withinwas below 1 millisecond.
Values
pub fn fixture(
storage: storage.Storage,
cleanup cleanup: fn() -> Nil,
) -> Fixture
Builds a fixture.
pub fn run(
fresh: fn() -> Result(Fixture, String),
timeout timeout: duration.Duration,
owner_loss_within owner_loss_within: duration.Duration,
) -> Result(Nil, Failure)
Runs each scenario on a fresh fixture. timeout bounds each scenario’s
storage work, and scenarios that wait for an owner to be lost get
owner_loss_within on top. The factory and cleanup run in the caller;
adapter operations run in test workers. Cleanup runs after the scenario
worker exits, including on failure or timeout.