Documentation
¶
Overview ¶
Package pgtest hands each PostgreSQL integration test its own isolated database, cloned from a single migrated template with CREATE DATABASE ... TEMPLATE.
Cloning a small database is a file-level copy, far cheaper than replaying the full ent migration per test, and it removes the shared-schema contention that used to force the whole suite to run serially (go test -p 1).
Lifecycle, and the "the template has no resident connection" invariant it protects:
- One maintenance connection is opened lazily against the maintenance database (postgres by default, C3API_TEST_MAINT_DB to override) and reused for template bookkeeping and clone DDL. It never points at the template.
- pg_advisory_lock serialises template (re)creation across every test binary on the instance.
- The template name embeds the content hash of the schema/migration sources, so checkouts sharing the same sources agree on it. Readiness is not "the database exists" alone: a template is reused only when it also carries a build-complete marker (a database COMMENT, templateReadyMarker) written as the final step of a successful build. A database whose name matches but whose marker is absent or wrong — an empty/half-built template left by a killed build, or an unmarked override — is dropped and rebuilt, so a half-built template can never masquerade as fresh. This supersedes the earlier clone spec's "an existing template is reused without reading inside it" invariant (clone-spec §2.2/§8.2).
- The template build opens its own database/sql connection and closes it before returning, so no connection is pointing at the template by the time any CREATE DATABASE ... TEMPLATE runs.
pgtest is a normal (non _test.go) package in the production tree. Nothing but tests and test tooling imports it, so it never reaches a production binary.
Data-layer wiring: the two steps that must talk to the ent/repository data layer — migrating a fresh template and topping up a clone's day partitions — are injected via RegisterDataLayerHooks by package pgrepo (which imports the repository). Keeping this file free of the repository import lets internal (package repository) tests import pgtest without the "import cycle not allowed in test" error; those tests only use CloneEmpty, which needs no hook.
Index ¶
- func Clone(t testing.TB) string
- func CloneEmpty(t testing.TB) string
- func DSN(t testing.TB) string
- func OpenPool(t testing.TB, dsn string) *pgxpool.Pool
- func Precheck() error
- func RegisterDataLayerHooks(migrate, cloneDaily func(ctx context.Context, dsn string) error)
- func SweepStaleTemplates(ctx context.Context) ([]string, error)
- func TemplateName() (string, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Clone ¶
Clone creates an isolated database cloned from the migrated template and returns its DSN. It is idempotent per test: repeated calls within the same test return the same clone, so a test that needs several handles (a pooled repository plus a pool-less one, or a second pool for a different session TimeZone) shares one database. The clone is dropped when the test finishes (kept, with its DSN logged, when the test failed).
func CloneEmpty ¶
CloneEmpty creates an isolated, empty database (a plain CREATE DATABASE, no template) and returns its DSN. It exists for the migration, partition and EXPLAIN tests that must start from an empty database and apply their own migration. The database is dropped at cleanup like Clone's.
func DSN ¶
DSN returns the base PostgreSQL DSN from TEST_DATABASE_URL, skipping the test when it is unset. Most tests want Clone or CloneEmpty instead; DSN is for the rare caller that needs the raw configured URL.
func OpenPool ¶
OpenPool opens a pgx connection pool on dsn with MaxConns=dbPoolMax and a lock_timeout, registering t.Cleanup(pool.Close).
A caller that additionally builds a *sql.DB on this pool (stdlib.OpenDBFromPool) MUST register its db.Close AFTER OpenPool returns: cleanup runs LIFO, so the *sql.DB closes first and the pool second. Closing the pool while a *sql.DB still borrows from it would block.
func Precheck ¶
func Precheck() error
Precheck verifies the configured role may create databases, failing fast before any clone is attempted. It is the pre-flight behind scripts/test.sh.
func RegisterDataLayerHooks ¶
RegisterDataLayerHooks installs the repository-dependent steps pgtest cannot perform itself: migrateTemplate builds a fresh template database, and ensureCloneDaily tops up a clone's day partitions (a template only carries the partitions that existed when it was built). Both are idempotent.
func SweepStaleTemplates ¶
SweepStaleTemplates drops every template database whose content hash differs from the current sources'. Only c3api_test_template_* databases are considered; per-test clones are never touched, so a concurrent run's clones are safe. It is the cross-run cleanup behind scripts/test.sh.
func TemplateName ¶
TemplateName returns the name of the template the current sources build. The name embeds the content hash of the schema/migration sources, so checkouts sharing the same sources agree on it.
Types ¶
This section is empty.