Documentation
¶
Overview ¶
Package storetest provides a conformance suite every store.Store implementation must pass, plus constructors for each backend.
Memory and SQLite run in process and need no setup. Postgres and Mongo read a DSN from the environment and skip when it is absent, so `go test ./...` stays runnable with nothing installed.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func NewMemory ¶
func NewMemory(t *testing.T) ledgerstore.Store
NewMemory returns an in-memory store. It never skips.
func NewMongo ¶
func NewMongo(t *testing.T) ledgerstore.Store
NewMongo returns a migrated MongoDB store, or skips the test when LEDGER_TEST_MONGO_URI is unset.
func NewPostgres ¶
func NewPostgres(t *testing.T) ledgerstore.Store
NewPostgres returns a migrated PostgreSQL store, or skips the test when LEDGER_TEST_POSTGRES_DSN is unset.
The DSN's database is migrated in place and not torn down, so point it at a scratch database and not at anything you care about.
func NewSQLite ¶
func NewSQLite(t *testing.T) ledgerstore.Store
NewSQLite returns a migrated SQLite store backed by a file under the test's temp directory.
":memory:" cannot be used here: sqlitedriver opens the database through database/sql's pooled *sql.DB, and modernc.org/sqlite treats ":memory:" as a fresh, independent database on every new connection the pool opens. A concurrency test that expects two goroutines' connections to see each other's writes (a unique-constraint race, for instance) would silently pass or fail for the wrong reason against ":memory:" - the two writes would land in two different databases and never conflict at all. A file under t.TempDir() is shared by every connection the pool opens, and a busy_timeout pragma makes a losing writer wait for the lock instead of failing immediately with SQLITE_BUSY. The DSN query parameter form (rather than a one-off PRAGMA exec after Open) matters too: modernc's driver re-parses the DSN for every new pooled connection, so this is the only way to guarantee busy_timeout is set on connections opened later in the pool's life, not just the first one.
This deliberately does NOT set _txlock=immediate. An earlier version of RedeemCoupon opened its transaction with a SELECT before writing, which only takes a SHARED lock going in; two such transactions racing the same coupon could both hold SHARED and then both try to upgrade to RESERVED at their first write, which SQLite resolves as SQLITE_BUSY immediately rather than queuing the upgrade behind busy_timeout. That version relied on _txlock=immediate here to mask the problem - but the documented production DSN (docs/content/docs/stores/sqlite.mdx) does not set it, so the tests were passing against a configuration production does not run. RedeemCoupon's transactions now open with a write (the application INSERT) as their first statement instead, which takes the RESERVED lock up front with no later upgrade to fail, so this harness runs the same DSN shape production does and still exercises the real lock behavior.
Types ¶
This section is empty.