Documentation
¶
Overview ¶
Package seamster provides two test-only instrumentation seams that a white-box test uses to exercise a host's recovery and race paths deterministically, without forging state or hammering on timing. Both are inert unless the host constructs the Seamster enabled:
- Fault injection makes a site MISBEHAVE: a test arms a named fault, the host consults it at the exact point it affects, and simulates an error, drop, or stale write that is otherwise hard to trigger on demand.
- Execution checkpoints make a site OBSERVABLE and PAUSABLE: a test rendezvouses with the host's progress (Seamster.Wait) or freezes the host at an exact point (Seamster.Break / Seamster.Resume).
A "seam" is a place where a test can alter or observe behavior without editing the code in place; a Seamster is the object that works a host's seams. The host embeds one Seamster, plants consult sites (Seamster.IsFault / Seamster.Checkpoint) at the points they affect, and names the valid fault/checkpoint set next to those sites so a test cannot arm a fault no site consumes.
Production inertness is by construction: every consult short-circuits on the enabled bool the host passes to New (typically testing.Testing()), so a disabled Seamster pays a single lock-free bool read per site and neither seam can ever fire. The package imports only the standard library, so a host may embed it on a production hot path without dragging in test-only dependencies.
Index ¶
- type Seamster
- func (s *Seamster) Break(checkpointName string)
- func (s *Seamster) Checkpoint(ctx context.Context, checkpointName string)
- func (s *Seamster) Enabled() bool
- func (s *Seamster) Inject(faultName string, scope ...string)
- func (s *Seamster) InjectN(n int, faultName string, scope ...string)
- func (s *Seamster) IsFault(faultName string, scope ...string) bool
- func (s *Seamster) Resume(checkpointName string)
- func (s *Seamster) Visits(checkpointName string) int
- func (s *Seamster) Wait(checkpointName string)
- func (s *Seamster) Withdraw(faultName string, scope ...string)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Seamster ¶
type Seamster struct {
// contains filtered or unexported fields
}
Seamster works one host's instrumentation seams. It is safe for concurrent use. The zero value is a disabled Seamster; construct one with New. A single Seamster is meant to be embedded per host instance (one per engine, one per connector, ...), not shared as a package global, so distinct hosts arm and consult independently.
func New ¶
New returns a Seamster. When enabled is false every consult is inert, so a host passes its own under-test signal - most commonly testing.Testing() - and embeds the result unconditionally.
func (*Seamster) Break ¶
Break arms a breakpoint so the host blocks the next time it reaches the named checkpoint, until Resume releases it. The breakpoint holds every goroutine that reaches the checkpoint while it is armed, not only the first, so a fan-out can be gathered at one point and released together by a single Resume; Wait returns as soon as the first of them arrives.
func (*Seamster) Checkpoint ¶
Checkpoint is the host-side consult at an instrumented site. Free in production (returns on the enabled bool read). When enabled it wakes any Wait(name) waiters and, if a breakpoint is armed for name, blocks until Resume(name) - or until ctx is done, so a stuck test or a shutdown can never wedge the host goroutine forever. Waking waiters and marking the breakpoint hit happen under one lock hold, so a Wait racing the host's arrival is woken or sees hit - never lost between the two.
func (*Seamster) Enabled ¶
Enabled reports whether the seams are live. A host uses it to skip building a scoped consult (a state read, a key concatenation) that would only feed IsFault, so the setup work is also elided in production.
func (*Seamster) Inject ¶
Inject arms the named fault to fire once (additive: calling twice fires twice). Optional scope args target it, joined the same way Seamster.IsFault joins its scope.
func (*Seamster) InjectN ¶
InjectN arms the named fault to fire n more times, added to any current count. Optional scope args target it, joined the same way Seamster.IsFault joins its scope. A non-positive n is a no-op.
func (*Seamster) IsFault ¶
IsFault reports whether the named fault is armed, consuming one fire. It is the only consult entry point and is free in production: it returns on the enabled bool read before any lock or key build. Optional scope args target the fault (a task name, a URL, ...) and are joined into the key, but only once the enabled gate has passed, so a scoped consult on a disabled Seamster allocates no throwaway key. To keep a fault armed for the rest of a test (until Seamster.Withdraw), inject a large count, e.g. s.InjectN(math.MaxInt, name).
func (*Seamster) Resume ¶
Resume releases the host frozen at the named breakpoint and disarms it. A no-op if none is armed.
func (*Seamster) Visits ¶ added in v0.2.0
Visits reports how many times the host has passed the named checkpoint - each Checkpoint(name) call counts one, including a call that then blocked on a breakpoint (reaching the checkpoint is the visit; blocking comes after). It is a passive counter for assertions: it never blocks, consumes nothing, and can be read repeatedly. The count is monotonic for the Seamster's lifetime (never reset), so capture a baseline first if a test asserts on visits accrued only within a window. Zero for a checkpoint never reached, and always zero on a disabled Seamster (Checkpoint counts nothing when inert).