Documentation
¶
Overview ¶
Package sqltest is the scripted database/sql driver a consumer's hermetic tests run over: its connections consume scripted responses in call order and record every statement, prepare, and transaction call they receive. It supports prepare, so prepare-based verification has a harness, and it accepts any argument value unconverted, so tests see the exact Go values a runner bound. It is public because every consumer's unit tier runs over it, the library's own packages included.
It is strict where a real driver is, so a test cannot pass on a path production would reject; each refusal is one of its own errors. The one leniency it keeps is the argument set: a real driver rejects a value it cannot encode, and this one records it.
The package exports:
- Open, which returns a pool over a fresh Recorder
- Recorder, the script, the call log, and the failure switches behind the pool
- Response, the scripted outcome of one exec or query call
- WithTotal, which scripts a counted collection page
- Call, one recorded driver call, and Op with its constants OpExec, OpQuery, OpPrepare, OpBegin, OpCommit, and OpRollback, the call's kind
- ErrUnscripted, ErrArguments, and ErrScript, the driver's own failures
- Dialect, the stub dialect, and MappedError, the mark its MapError leaves on an error
- ReturningDialect, the stub dialect with the query.Returner capability
- LockingDialect, the stub dialect with the sqlate.TryLocker capability (and so sqlate.Locker), and ErrLockNotHeld, its Unlock of a name the script reports was not held
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrUnscripted = errors.New("sqltest: unscripted call") ErrScript = errors.New("sqltest: response does not fit the call") ErrArguments = errors.New("sqltest: argument count does not match the placeholders") )
The driver's own failures, each the counterpart of a failure a real driver or engine raises. A statement no response was scripted for is a statement the test did not expect to run; a response whose shape does not fit the call is a script defect. An argument count that does not match the statement's placeholders is what the engine rejects at bind time.
var ErrLockNotHeld = errors.New("sqltest: lock not held")
ErrLockNotHeld is LockingDialect's Unlock of a name the script reports was not held, the counterpart of an engine that answers false to an unlock rather than failing.
Functions ¶
This section is empty.
Types ¶
type Call ¶
Call is one recorded driver call. SQL and Args are set for exec, query, and prepare; TxOptions for begin.
type Dialect ¶
type Dialect struct{}
Dialect is the stub dialect: $N placeholders and a MapError that wraps every non-nil error in a *MappedError, so a test proves an error crossed the mapping boundary with one errors.As.
func (Dialect) MapError ¶
MapError wraps err in a *MappedError; nil stays nil. An already mapped error is returned as is, so double mapping is visible as absence of nesting rather than a crash.
func (Dialect) Placeholder ¶
type LockingDialect ¶ added in v0.6.0
type LockingDialect struct{ Dialect }
LockingDialect is the stub dialect with the sqlate.TryLocker capability, and so sqlate.Locker: each call runs one statement on the pinned connection, so the lock calls are part of the recorded script and a test scripts their outcomes like any other call.
- Lock executes "SELECT lock($1)" with the name; script an exec response, or an error for a lock that fails.
- TryLock queries "SELECT try_lock($1)" with the name and reports the one boolean row; script true for a granted lock, false for one another session holds.
- Unlock queries "SELECT unlock($1)" with the name; script true for a held lock, false for one that was not, which is ErrLockNotHeld.
It lets a consumer's unit suite cover a protocol that takes a lock, where Dialect covers a provider without the capability.
func (LockingDialect) Lock ¶ added in v0.6.0
Lock executes the scripted lock statement for name on conn.
type MappedError ¶
type MappedError struct{ Err error }
MappedError marks an error that passed through Dialect.MapError.
func (*MappedError) Error ¶
func (e *MappedError) Error() string
func (*MappedError) Unwrap ¶
func (e *MappedError) Unwrap() error
type Recorder ¶
type Recorder struct {
// FailPrepare, when set, decides whether a prepare of the given text
// fails; nil means every prepare succeeds.
FailPrepare func(query string) error
// FailBegin, FailCommit, FailRollback, FailPing inject failures into the
// transaction and ping calls.
FailBegin, FailCommit, FailRollback, FailPing error
// contains filtered or unexported fields
}
Recorder is the shared state behind every connection a connector hands out: the response queue, the call log, and the failure switches.
func (*Recorder) Pending ¶
Pending reports how many scripted responses remain unconsumed; a test asserts zero to prove every scripted call happened.
func (*Recorder) RowsLeaked ¶
RowsLeaked reports row sets opened and never closed.
type Response ¶
Response scripts the outcome of the next exec or query call: an error, or the affected count (exec) or the columns and rows (query). An exec response has no columns or rows and a query response no affected count; every row is as wide as Columns and contains driver.Value types only, as a real driver returns them. Prepare, begin, commit, and rollback do not consume responses; their failures are set on the Recorder directly.
func WithTotal ¶ added in v0.4.0
WithTotal returns r as a counted collection page returns it: with a trailing count column holding n in every row, from which a query.Projection reads its exact total and which it hides from the scan. A unit suite uses it to script a List or Continue under query.TotalExact without spelling the library's reserved column name. WithTotal leaves r unchanged. An empty r still gains the column, as an empty counted page declares it.
type ReturningDialect ¶ added in v0.3.0
type ReturningDialect struct{ Dialect }
ReturningDialect is the stub dialect with the query.Returner capability: it appends "RETURNING <columns>" to an INSERT or UPDATE, as an engine with the clause renders it, and declines any other verb. It lets a consumer's unit suite cover a returning command's single-statement form, where Dialect covers the fallback.