embeddedpostgres

package module
v2.0.0-alpha.3 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: MIT Imports: 30 Imported by: 0

README

embedded-postgres gopher

embedded-postgres v2

Run real PostgreSQL in your tests. Each test gets its own database, an available port, and automatic cleanup. A CLI provides the same lifecycle for other languages. The production Go packages have zero third-party dependencies.

v2 is available as an alpha release. Requires Go 1.26 or newer. Upgrading from v1? Start with the migration guide.

A database scoped to a test

go get github.com/fergusstrange/embedded-postgres/v2@v2.0.0-alpha.1
package app_test

import (
    "testing"

    "github.com/fergusstrange/embedded-postgres/v2/eptest"
)

func TestRepository(t *testing.T) {
    pg := eptest.Start(t)
    connectionURL := pg.ConnectionURL()
    _ = connectionURL // Open your chosen Go driver/pool here.
    // Register pool cleanup after eptest.Start, so the pool closes first.
}

The first start downloads PostgreSQL and the matching supervisor; later starts reuse the cache. PostgreSQL needs the native libraries for your OS. Choose your own SQL driver, and close connection pools before test cleanup.

For configuration, import github.com/fergusstrange/embedded-postgres/v2 as postgres and pass postgres.DefaultConfig().Port(0).Database("app_test") to eptest.Start. Use eptest.Run to share one instance across TestMain. See testing patterns for parallel tests and suite setup. Source checkouts, local replacements and vendored tests need an explicitly selected supervisor; see the migration guide.

Use the CLI with any test runner

curl -fsSL https://raw.githubusercontent.com/fergusstrange/embedded-postgres/master/install/install.sh | bash
export PATH="$HOME/.local/bin:$PATH"
embedded-postgres exec -- npm test

exec starts PostgreSQL, supplies DATABASE_URL and the usual PG* variables, runs your command, then stops the database and returns the command's exit code. Replace npm test with your test command. The CLI chooses an available port and a random password. See the CLI guide for foreground and background instances, Windows installation, configuration files and wrapper integration.

Direct lifecycle use

pg := postgres.NewDatabase(postgres.DefaultConfig().Port(0))
if err := pg.StartContext(ctx); err != nil {
    return err
}
defer pg.Close()
// pg.ConnectionURL() and pg.GetPort() now contain the actual endpoint.

Canceling the lifetime context also closes the server. Close is idempotent; Start and Stop preserve the familiar v1 calling pattern. StopContext can stop waiting when its context expires while cleanup continues. Done closes when cleanup finishes, Err reports a lifecycle failure, and Logs retains a bounded, password-redacted tail for diagnostics.

An independent supervisor watches a dedicated owner pipe. An unrecovered panic, os.Exit, or forced owner termination closes that pipe and triggers PostgreSQL shutdown. The library installs no process-wide signal handlers. Userspace cannot guarantee graceful shutdown after whole-machine failure or simultaneous forced termination of the supervisor and PostgreSQL. Persistent data still requires the same care as any PostgreSQL cluster.

Storage and extension points

config := postgres.DefaultConfig().Port(0).Storage(postgres.Storage{
    CacheDir: "/path/to/shared-cache",
    WorkDir:  "/path/to/temporary-parent",
    DataDir:  "/path/to/persistent-cluster", // Omit for disposable test data.
})
  • CacheDir holds verified, immutable installations shared under process leases. Stopping an instance retains reusable binaries. PruneCache removes unused recognized entries and preserves active installations and unknown files.
  • WorkDir is a parent for private, uniquely named temporary children. The caller's parent is never erased. Each normal lifecycle removes its own child.
  • DataDir is persistent and never automatically removed. A nonempty unrelated directory or a cluster from a different PostgreSQL major is rejected.

Replace the whole acquisition policy with BinaryProvider, use LocalProvider for preinstalled PostgreSQL, or customize DownloadProvider for mirrors, HTTP transports and offline caches. Lifecycle hooks support preparation and migrations with reverse-order cleanup. Native extensions such as pgvector/PostGIS can live in caller-owned distributions without becoming core dependencies. See provider and hook contracts and compiled reference implementations.

Root callers must select an existing non-root Unix identity with RunAs(postgres.User{UID: 10001, GID: 10001}). The caller retains its identity; PostgreSQL and its utilities run as the selected account. Windows uses a restricted token and process Job Objects. Follow the non-root reference guide for container setup, directory ownership, and native library requirements.

Defaults and supported versions

Setting Library default
PostgreSQL V18 / 18.6.0
Role, password, database postgres
Port 5432; use Port(0) for parallel tests
Locale / encoding C / UTF8
Startup / shutdown 2 minutes / 10 seconds
Data / workspace Private disposable instance
Cache os.UserCacheDir()/embedded-postgres/v2

V15, V16, V17, V18 pin 15.19.0, 16.15.0, 17.11.0, 18.6.0. PostgreSQL 14 and older are excluded. PostgreSQL uses a five-year major-version support policy, not a separate LTS edition. Binary checksums are pinned in the reviewed manifest; automatic library releases do not silently change those pins.

Native CI covers Linux and macOS AMD64/ARM64, Windows AMD64, and Windows ARM64 with x64 PostgreSQL emulation. Alpine 3.21 AMD64 has a separate musl integration job (the upstream bundle requires ICU 74; see the platform guide). Other Linux architectures can use a source-built companion when a pinned bundle exists. FreeBSD needs a custom distribution and companion; it is not in the supported release matrix.

Development

Contributing explains local tests and coverage. Build and release policy describes the native GitHub Actions matrix, 90% production coverage gate, security checks and automatic master releases. Download published binaries and read release notes on the releases page.

Thanks to theseus-rs/postgresql-binaries for gzip distributions, the PostgreSQL project, and zonkyio/embedded-postgres-binaries for powering v1. The logo uses Gopherize Me.

Documentation

Overview

Package embeddedpostgres runs an isolated PostgreSQL server for tests. Production packages use only the Go standard library. PostgreSQL and the companion supervisor are native executables acquired separately.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrServerNotStarted     = errors.New("server has not been started")
	ErrServerAlreadyStarted = errors.New("server is already started")
	ErrDataVersion          = errors.New("persistent data belongs to a different PostgreSQL major version")
)
View Source
var ReleaseVersion = "v2.0.0-dev"

ReleaseVersion is set for CLI builds; Go consumers use module build metadata.

Functions

func PruneCache

func PruneCache(ctx context.Context, dir string) (int, error)

PruneCache removes unused installations. Active leases and unknown entries are preserved. Lock files remain so waiters never lock a different inode.

Types

type BinaryProvider

type BinaryProvider interface {
	Acquire(context.Context, BinaryRequest) (*Installation, error)
}

BinaryProvider supplies PostgreSQL plus initdb, pg_ctl, psql, and createdb. Implementations must support concurrent calls and honour cancellation.

type BinaryRequest

type BinaryRequest struct {
	Version      PostgresVersion
	GOOS, GOARCH string
}

BinaryRequest identifies a requested PostgreSQL installation.

type Config

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

Config uses value builders. Maps and slices are copied at API boundaries.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig retains port 5432 for existing callers. Use Port(0) for automatic allocation. Test helpers and the CLI choose Port(0) by default.

func (Config) BinariesPath

func (c Config) BinariesPath(v string) Config

BinariesPath is deprecated: use LocalProvider. The distribution must include psql and createdb; legacy minimal Zonky bundles do not contain them.

func (Config) BinaryRepositoryURL

func (c Config) BinaryRepositoryURL(v string) Config

BinaryRepositoryURL is deprecated: use DownloadProvider.BaseURL. v2 mirrors use /VERSION/ASSET.tar.gz, not the v1 Maven/JAR layout.

func (Config) CachePath

func (c Config) CachePath(v string) Config

CachePath is deprecated: use Storage.CacheDir.

func (Config) DataPath

func (c Config) DataPath(v string) Config

DataPath is deprecated: use Storage.DataDir. Existing data is preserved.

func (Config) Database

func (c Config) Database(v string) Config

func (Config) Encoding

func (c Config) Encoding(v string) Config

func (Config) Environment

func (c Config) Environment(v ...string) Config

Environment appends explicit subprocess environment overrides. Identity does not inherit root-only HOME/PG variables; connection settings are set separately.

func (Config) GetConnectionURL

func (c Config) GetConnectionURL() string

GetConnectionURL describes static configuration. For Port(0), use the running instance's ConnectionURL instead; this method deliberately does no I/O.

func (Config) Hooks

func (c Config) Hooks(v Hooks) Config

func (Config) Locale

func (c Config) Locale(v string) Config

func (Config) Logger

func (c Config) Logger(v io.Writer) Config

func (Config) Password

func (c Config) Password(v string) Config

func (Config) Port

func (c Config) Port(v uint32) Config

func (Config) Provider

func (c Config) Provider(v BinaryProvider) Config

func (Config) RunAs

func (c Config) RunAs(v User) Config

RunAs sets the Unix identity for the supervisor and every PostgreSQL command. Root callers must set both UID and GID to nonzero values explicitly.

func (Config) RuntimePath

func (c Config) RuntimePath(v string) Config

RuntimePath is deprecated: use Storage.WorkDir. The path is now a parent and is never erased; each instance receives a uniquely named child.

func (Config) StartParameters

func (c Config) StartParameters(v map[string]string) Config

func (Config) StartTimeout

func (c Config) StartTimeout(v time.Duration) Config

func (Config) StopTimeout

func (c Config) StopTimeout(v time.Duration) Config

func (Config) Storage

func (c Config) Storage(v Storage) Config

func (Config) Supervisor

func (c Config) Supervisor(path string) Config

Supervisor selects the companion CLI executable. Released library versions can download their matching companion automatically. Source builds must set it.

func (Config) UnixSocket

func (c Config) UnixSocket(dir string) Config

UnixSocket selects a private Unix socket directory and disables TCP.

func (Config) Username

func (c Config) Username(v string) Config

func (Config) Version

func (c Config) Version(v PostgresVersion) Config

type DownloadProvider

type DownloadProvider struct {
	CacheDir, BaseURL, Target string
	Client                    *http.Client
	Offline                   bool
}

DownloadProvider downloads pinned gzip bundles and shares extracted binaries. BaseURL mirrors the upstream /VERSION/ASSET layout. Target overrides automatic platform detection (for custom musl systems, for example). Client supports authenticated mirrors. Offline refuses network requests.

func (DownloadProvider) Acquire

type EmbeddedPostgres

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

EmbeddedPostgres serialises lifecycle transitions. Separate instances run in parallel and may share immutable binaries. Inspection methods serialise behind an in-flight Start or Close; StopContext bounds its caller's wait even then. Do not copy after first use.

func NewDatabase

func NewDatabase(config ...Config) *EmbeddedPostgres

NewDatabase constructs an instance without doing I/O. If supplied, the first config is used, preserving the v1 calling convention.

func (*EmbeddedPostgres) Close

func (ep *EmbeddedPostgres) Close() error

func (*EmbeddedPostgres) ConnectionURL

func (ep *EmbeddedPostgres) ConnectionURL() string

ConnectionURL returns the actual endpoint after Start succeeds.

func (*EmbeddedPostgres) Done

func (ep *EmbeddedPostgres) Done() <-chan struct{}

Done closes when an instance has been fully cleaned up. Before Start it is already closed.

func (*EmbeddedPostgres) Err

func (ep *EmbeddedPostgres) Err() error

Err reports the most recent lifecycle or unexpected-process error.

func (*EmbeddedPostgres) GetConnectionURL

func (ep *EmbeddedPostgres) GetConnectionURL() string

func (*EmbeddedPostgres) GetPort

func (ep *EmbeddedPostgres) GetPort() uint32

func (*EmbeddedPostgres) Info

func (ep *EmbeddedPostgres) Info() InstanceInfo

func (*EmbeddedPostgres) Logs

func (ep *EmbeddedPostgres) Logs() string

Logs returns the recent server output with the configured password redacted. A bounded tail remains available after Close for test-failure diagnostics. Temporary files are still removed. Errors also include startup diagnostics.

func (*EmbeddedPostgres) Start

func (ep *EmbeddedPostgres) Start() error

func (*EmbeddedPostgres) StartContext

func (ep *EmbeddedPostgres) StartContext(ctx context.Context) (err error)

StartContext starts a server whose lifetime is bound to ctx. Cancellation after readiness also closes the server, using an independent cleanup timeout.

func (*EmbeddedPostgres) Stop

func (ep *EmbeddedPostgres) Stop() error

Stop preserves the v1 error when no server is active. Close is idempotent.

func (*EmbeddedPostgres) StopContext

func (ep *EmbeddedPostgres) StopContext(ctx context.Context) error

StopContext requests cleanup and bounds how long the caller waits. If ctx expires, bounded process shutdown and resource cleanup continue independently.

type Hook

type Hook func(context.Context, InstanceInfo) (cleanup func(context.Context) error, err error)

Hook runs synchronously. It must honour ctx and must not call Start/Stop/Close on its own instance. Return cleanup for resources acquired before any error.

type Hooks

type Hooks struct{ BeforeStart, Ready []Hook }

Hooks are ordered phases. BeforeStart runs after initdb, Ready after an authenticated query. Returned cleanups run in reverse order after shutdown, including when a later hook or startup fails. Panics are cleaned up then rethrown.

type Installation

type Installation struct {
	Dir     string
	Release func() error
}

Installation is immutable while acquired. Release is called once, after all owned processes stop. It must release leases, not delete caller-owned data.

type InstanceInfo

type InstanceInfo struct {
	WorkDir, DataDir, BinariesDir, ConnectionURL string
	Port                                         uint32
}

InstanceInfo is a snapshot. Hooks may change only their instance's private work/data files, never the shared binary installation.

type LocalProvider

type LocalProvider string

LocalProvider uses a preinstalled distribution without modifying it.

func (LocalProvider) Acquire

type PostgresVersion

type PostgresVersion string

PostgresVersion identifies a pinned distribution release. Its first two components are the PostgreSQL version; the third is the packaging revision.

const (
	V18 PostgresVersion = "18.6.0"
	V17 PostgresVersion = "17.11.0"
	V16 PostgresVersion = "16.15.0"
	V15 PostgresVersion = "15.19.0"
)

type ProviderFunc

type ProviderFunc func(context.Context, BinaryRequest) (*Installation, error)

ProviderFunc adapts a function to BinaryProvider.

func (ProviderFunc) Acquire

type Storage

type Storage struct{ CacheDir, WorkDir, DataDir string }

Storage separates reusable binaries, disposable work, and persistent data. WorkDir is a parent: the library creates its own child and never deletes it. DataDir, when set, is persistent and is never automatically removed.

type User

type User = platform.Identity

User identifies an existing OS account. It is separate from Username.

Directories

Path Synopsis
cmd
embedded-postgres command
embedded-postgres runs PostgreSQL for tests and supervises its process tree.
embedded-postgres runs PostgreSQL for tests and supervises its process tree.
Package eptest binds an embedded PostgreSQL instance to Go tests and suites.
Package eptest binds an embedded PostgreSQL instance to Go tests and suites.
examples
custom
Package custom contains compiled extension patterns; it adds no core dependencies.
Package custom contains compiled extension patterns; it adds no core dependencies.
internal
archive
Package archive extracts bounded gzip archives beneath a private directory.
Package archive extracts bounded gzip archives beneath a private directory.
binaries
Package binaries contains the audited, release-pinned PostgreSQL catalogue.
Package binaries contains the audited, release-pinned PostgreSQL catalogue.
cli
Package cli implements the stable command-line and JSON protocol surface.
Package cli implements the stable command-line and JSON protocol surface.
filelock
Package filelock provides process-scoped shared/exclusive cache leases.
Package filelock provides process-scoped shared/exclusive cache leases.
platform
Package platform contains the small OS boundary for process ownership.
Package platform contains the small OS boundary for process ownership.
supervisor
Package supervisor owns a PostgreSQL process independently of its Go caller.
Package supervisor owns a PostgreSQL process independently of its Go caller.

Jump to

Keyboard shortcuts

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