testutil

package
v0.3.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package testutil is the integration-test harness: a real PostgreSQL in a container plus per-test throwaway schemas. Integration tests are the workhorse of this repo — core logic is validated against a real database, not mocks.

Index

Constants

View Source
const DefaultPGVersion = "16"

DefaultPGVersion is the major used when PG_VERSION is unset. CI overrides it across the full supported matrix (14 → 18).

View Source
const DifferenceLimit = 20

DifferenceLimit bounds how many differing keys one direction reports; a diverged table is diagnosed from its lowest keys, not enumerated.

Variables

This section is empty.

Functions

func AssertConverged added in v0.3.2

func AssertConverged(t *testing.T, pool *pgxpool.Pool, source, shadow RelationRef, opts ConvergeOptions)

AssertConverged requires that source and shadow contain equal rows.

func NewCatalogShadowingPool added in v0.3.2

func NewCatalogShadowingPool(t *testing.T, serverURL, schema string) *pgxpool.Pool

NewCatalogShadowingPool returns a pool whose every session has schema ahead of pg_catalog on search_path, so impostor relations, views, functions, and operators created in schema answer unqualified catalog names. It is a raw pgx pool on purpose: pools from pkg/dbconn remove a shadowed pg_catalog entry on connect, which would make the impostors unreachable, and the tests that use this pool prove that the queries themselves stay pg_catalog-qualified for a pool the library caller built. It carries none of pkg/dbconn's session defaults.

func NewDatabase

func NewDatabase(t *testing.T, serverURL string) string

NewDatabase creates a unique throwaway database on the server at serverURL, sets it up for cleanup, and returns a URL that connects to it. Throwaway schemas do not isolate pg_stat_activity, so a test that must observe an exact session set (e.g. none) on a shared server gets a database of its own. serverURL must be in URL form (postgres://...), which StartPostgres always returns.

func NewPublicTable

func NewPublicTable(t *testing.T, pool *pgxpool.Pool, columns string) string

NewPublicTable creates a uniquely named throwaway table in the public schema — for tests that exercise unqualified-statement resolution, where a dedicated schema would defeat the point — and returns its name. The unique name keeps a shared PG_DSN database safe; cleanup drops the table.

func NewRole

func NewRole(t *testing.T, pool *pgxpool.Pool, options string) string

NewRole creates a throwaway cluster-level role with the given options and registers its drop. Roles are cluster-scoped, so names are unique per process the same way throwaway schemas are.

func NewSchema

func NewSchema(t *testing.T, pool *pgxpool.Pool) string

NewSchema creates a unique throwaway schema on pool, sets it up for cleanup, and returns its name. Tests qualify their objects with it so parallel tests on one container never collide.

func PGVersion

func PGVersion() string

PGVersion returns the PostgreSQL major version under test.

func RunDuringDDL added in v0.3.2

func RunDuringDDL(t *testing.T, pool *pgxpool.Pool, event DDLEvent, tag, schema, table, sql string)

RunDuringDDL installs an event trigger that executes sql from inside the next DDL command with the given tag whose text names schema.table, at the given event. It is the fault-injection seam for the windows a single-statement DDL leaves open — between a probe and the server's choice of names, or between a commit and the read that verifies it — made deterministic. The trigger is server-wide (event triggers are), so the schema qualifier scopes it to the test's own objects; the trigger and its function are dropped when the test ends.

func StartPostgres

func StartPostgres(t *testing.T) string

StartPostgres returns a PostgreSQL connection URL for the test.

By default it starts a disposable container (terminated when the test ends). When PG_DSN is set, that external server is used instead and no container is started — the compose/ workflow and CI variants that run a long-lived server use this. Set SKIP_INTEGRATION=1 to skip tests that need a database entirely.

func StartPostgresBehindPgBouncer added in v0.3.3

func StartPostgresBehindPgBouncer(t *testing.T, mode PoolMode) (pooledURL string)

StartPostgresBehindPgBouncer starts a PostgreSQL server with a PgBouncer in front of it in the given pool mode and returns the pooled connection URL — the one a hosted platform would hand an operator.

It always starts its own containers: the pooling mode is the fixture, so an external PG_DSN cannot substitute for it.

Types

type ConvergeOptions added in v0.3.2

type ConvergeOptions struct{ IgnoreColumns []string }

ConvergeOptions controls convergence comparison.

type DDLEvent added in v0.3.2

type DDLEvent string

DDLEvent is the point in a DDL command at which an event trigger fires.

const (
	// DDLCommandStart fires before the command runs: the objects it will
	// create do not exist yet, so a name can still be taken from under it.
	DDLCommandStart DDLEvent = "ddl_command_start"
	// DDLCommandEnd fires after the command has run but inside its
	// transaction: the objects it created exist and can be altered before
	// the caller sees the commit.
	DDLCommandEnd DDLEvent = "ddl_command_end"
)

type DirectionDiff added in v0.3.2

type DirectionDiff struct {
	Direction string
	Keys      []int64
}

DirectionDiff reports differing primary keys in one EXCEPT direction.

type LoadGenerator added in v0.3.2

type LoadGenerator struct {
	// contains filtered or unexported fields
}

LoadGenerator owns running workload workers.

func StartLoad added in v0.3.2

func StartLoad(t *testing.T, pool *pgxpool.Pool, table WorkloadTable, spec LoadSpec) *LoadGenerator

StartLoad starts bounded, cancellable workload workers. An invalid spec fails the test immediately rather than starting a generator that writes nothing.

func (*LoadGenerator) Stop added in v0.3.2

func (g *LoadGenerator) Stop() (Summary, error)

Stop promptly cancels workers and waits a bounded time for completion. It always returns the summary accumulated so far; when workers do not stop in time the error joins the deadline with any worker error already recorded, so a wedged worker's cause is not lost behind the timeout.

type LoadSpec added in v0.3.2

type LoadSpec struct {
	Seed                 int64
	Workers              int
	RatePerSecond        int
	Mix                  Mix
	HotRowFraction       float64
	ToastRewriteFraction float64
}

LoadSpec configures a deterministic concurrent workload.

RatePerSecond is the mutation rate of each worker, so the aggregate rate is Workers × RatePerSecond. HotRowFraction is the share of updates aimed at the ten lowest ids (contention on a hot set); ToastRewriteFraction is the share of updates that rewrite the out-of-line blob column — the rest leave it unchanged, so their change records omit it.

type Mix added in v0.3.2

type Mix struct {
	Insert     int
	Update     int
	Delete     int
	UniqueMove int
}

Mix gives relative weights to workload mutations.

type PoolMode added in v0.3.3

type PoolMode string

PoolMode is a connection pooler's pooling granularity, which is what decides whether a client connection keeps one server session.

const (
	// TransactionPooling returns the backend to the pooler's own pool at
	// the end of every transaction, so a client connection has no stable
	// server session. It is the default on hosted PostgreSQL platforms.
	TransactionPooling PoolMode = "transaction"
	// SessionPooling gives a client connection its own backend for the
	// connection's lifetime, which is all a session-scoped lock needs.
	SessionPooling PoolMode = "session"
)

type RelationRef added in v0.3.2

type RelationRef struct {
	Schema string
	Table  string
}

RelationRef identifies a relation.

type Report added in v0.3.2

type Report struct {
	SourceCount int64
	ShadowCount int64
	Differences []DirectionDiff
}

Report contains row counts and bounded symmetric differences, all read from one REPEATABLE READ snapshot so the numbers describe one instant.

func Diff added in v0.3.2

func Diff(ctx context.Context, pool *pgxpool.Pool, source, shadow RelationRef, opts ConvergeOptions) (Report, error)

Diff compares source against the shadow's visible column contract.

Every catalog read, both counts, and both difference queries run in one read-only REPEATABLE READ transaction, so a Report is a single snapshot: a count difference and a row difference can never disagree about the instant they describe.

func (Report) Converged added in v0.3.2

func (r Report) Converged() bool

Converged reports whether the relations hold equal rows. The counts are diagnostic only: the primary key is always projected and both counts come from the same snapshot as the differences, so any count skew necessarily surfaces as a differing key.

type Summary added in v0.3.2

type Summary struct {
	Inserts     int
	Updates     int
	Deletes     int
	UniqueMoves int
	Races       int
	InsertedIDs []int64
	DeletedIDs  []int64
}

Summary reports committed operations, inserted and deleted IDs, and the number of mutations that aborted on an expected race (a unique-key collision, a serialization failure, a deadlock, or a vanished row) and were dropped rather than retried. A run whose Races dwarf its committed counts wrote far less than its spec suggests.

type TLSPostgres

type TLSPostgres struct {
	// URL is the connection URL without an sslmode parameter, so the
	// caller's TLS configuration decides the handshake.
	URL string
	// CACertPath is the PEM CA certificate that signed the server
	// certificate — the trust anchor for verify-full connections.
	CACertPath string
	// UntrustedCACertPath is a valid CA certificate that did NOT sign the
	// server certificate, for negative verification tests.
	UntrustedCACertPath string
}

TLSPostgres describes a TLS-only PostgreSQL started by StartPostgresTLS.

func StartPostgresTLS

func StartPostgresTLS(t *testing.T) TLSPostgres

StartPostgresTLS starts a disposable PostgreSQL container that accepts only TLS connections, using a CA generated for this test. Unlike StartPostgres it never uses PG_DSN — the whole point is controlling the server's TLS posture. Set SKIP_INTEGRATION=1 to skip.

type WorkloadTable added in v0.3.2

type WorkloadTable struct {
	Schema string
	Table  string
	// contains filtered or unexported fields
}

WorkloadTable is the fixed-shape table used by copy convergence tests.

func NewWorkloadTable added in v0.3.2

func NewWorkloadTable(t *testing.T, pool *pgxpool.Pool) WorkloadTable

NewWorkloadTable creates an empty workload relation in a unique schema.

The shape exercises every convergence race the copy path must survive: an identity primary key, a unique secondary key whose values tests swap between rows, a numeric column for widening changes, and a text column that is always stored out of line so an update leaving it unchanged produces a change record with that column omitted. Compression is turned off for that column: pglz would otherwise keep a repetitive value inline and the omission would never occur.

func (WorkloadTable) Qualified added in v0.3.2

func (w WorkloadTable) Qualified() string

Qualified returns the safely quoted relation name.

func (WorkloadTable) SeedRows added in v0.3.2

func (w WorkloadTable) SeedRows(ctx context.Context, n int) error

SeedRows inserts n deterministic rows.

func (WorkloadTable) ToastBytes added in v0.3.2

func (w WorkloadTable) ToastBytes(ctx context.Context) (int64, error)

ToastBytes returns the on-disk size of the table's TOAST relation, so a test can prove that the blob column really is stored out of line.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL