Documentation
¶
Overview ¶
Package cockroachtest spins up an in-memory single-node CockroachDB cluster (via `cockroach demo --background`) for use by integration tests in this module. It is the only place in the codebase that shells out to a real cockroach binary; integration tests under `//go:build integration` consume it through Shared / RunTests.
Lifecycle:
Start launches a demo cluster, blocks until it has written its listening URL, and returns a *Cluster whose DSN field is a usable postgres URL. Stop sends SIGINT, waits up to 10s for graceful exit, then escalates to SIGKILL. On a Start failure the harness has already killed any partially-started process and removed the temp directory before returning.
Shared and RunTests provide the per-test-binary pattern used by integration test packages: one cluster is started on the first Shared call and torn down by RunTests when the test binary exits. Shared fails the test (rather than skipping) when no cluster is reachable; see "Binary resolution" below for the opt-out.
Binary resolution (in order):
- COCKROACH_BIN environment variable.
- `cockroach` on $PATH.
If neither resolves to an executable file, Start returns ErrBinaryNotFound. Shared turns that into t.Fatalf by default so a silent skip can never masquerade as a passing integration test; environments that legitimately lack a cockroach binary (today: the GitHub Actions CI job) opt back into the old skip behavior by setting CRDB_INTEGRATION_OPTIONAL=1.
CRDB_TEST_DSN bypass: when CRDB_TEST_DSN is set, Shared returns a Cluster with only DSN populated and a no-op Stop. This lets a developer point integration tests at an already-running cluster without paying the demo startup cost.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrBinaryNotFound = errors.New(
"cockroach binary not found (set COCKROACH_BIN or put cockroach on PATH)")
ErrBinaryNotFound is returned by Start when no cockroach binary can be located via COCKROACH_BIN or $PATH. Shared turns this into t.Fatalf by default so missing-binary cases fail loudly, or into t.Skipf when CRDB_INTEGRATION_OPTIONAL holds a strconv.ParseBool-truthy value (the CI escape hatch — falsy or unparseable values still Fatal, so a typo can't accidentally enable skipping). Shared callers also have CRDB_TEST_DSN as a third option (point at an already-running cluster); Start itself does not honor that var because its job is to spawn a process, not to wrap an existing one.
Functions ¶
func RunTests ¶
RunTests is the TestMain helper for integration test packages. It runs the standard test suite via m.Run and then tears down any shared cluster that Shared created. Call from each integration test package as:
func TestMain(m *testing.M) { cockroachtest.RunTests(m) }
RunTests calls os.Exit, mirroring the standard TestMain contract. Teardown errors are written to stderr before os.Exit because m.Run has already returned and t.Log is unavailable; without this, a hung-shutdown or tmpdir-cleanup failure would silently exit 0.
Types ¶
type Cluster ¶
type Cluster struct {
// DSN is the postgres connection string for the running demo node.
// Populated by Start before it returns; never modified afterward.
DSN string
// contains filtered or unexported fields
}
Cluster represents a running `cockroach demo` instance owned by the test process. Construct with Start; release with Stop. The exported DSN field is the postgres URL the demo cluster wrote to its listening-url-file and is safe to read after Start returns.
A Cluster is single-use: once Stop has been called, the cluster cannot be restarted. Tests that need multiple clusters call Start multiple times (each invocation gets its own tempdir and process).
Concurrency: a single monitor goroutine started by Start owns cmd.Wait() and signals process exit via the waitDone channel. All other code paths (premature-exit detection during startup, Stop's graceful-shutdown wait) observe exit by selecting on waitDone, so there is exactly one Wait caller and no double-wait race.
func Shared ¶
Shared returns the per-test-binary cluster, starting one on the first call. CRDB_TEST_DSN takes precedence: if set at first-call time, Shared returns a Cluster whose DSN is the env value and whose Stop is a no-op.
Env-read timing: CRDB_TEST_DSN and the binary-resolution variables (COCKROACH_BIN, $PATH) are read only on the first call; the result is cached. CRDB_INTEGRATION_OPTIONAL is the exception — it is re-read on every call so a test that flips the opt-in mid-run gets the new behavior on subsequent calls, not the value captured at first-call time.
Behavior on missing binary: when neither CRDB_TEST_DSN nor a resolvable cockroach binary is available, Shared calls t.Fatalf by default. Setting CRDB_INTEGRATION_OPTIONAL to a strconv.ParseBool truthy value (e.g. "1", "true") converts the failure into t.Skipf — this is the escape hatch for environments (today: the GitHub Actions job) that legitimately have no cockroach installed. A falsy or unparseable value Fatals just like the unset case, so a typo can't accidentally enable skipping.
Behavior on cached failure: a Shared call that follows a failed Shared call replays the Skip/Fatal decision against the *current* CRDB_INTEGRATION_OPTIONAL value, but only for ErrBinaryNotFound. A generic Start failure cached on the first call always Fatals — never skips — because CRDB_INTEGRATION_OPTIONAL is meant only for the missing-binary case.
On a real *testing.T, both Fatalf and Skipf invoke runtime.Goexit, so the nil return is only observable to test doubles that override them (e.g. the recordingTB used in cluster_test.go). Production callers can rely on Shared either returning a usable *Cluster or never returning.
Tests using Shared must wire their TestMain through RunTests so the cluster is cleanly torn down at exit.
func Start ¶
Start launches an in-memory single-node demo cluster in the background. It blocks until the cluster has written its listening URL to a private temp file (default 30s timeout, configurable via WithStartTimeout). On success the returned Cluster's DSN is a valid postgres URL and the caller is responsible for invoking Stop. On failure, any partially-started process has been killed and the temp directory removed before Start returns.
Start honors COCKROACH_BIN; if unset, it looks up `cockroach` on $PATH. Returns ErrBinaryNotFound when neither resolves.
func (*Cluster) Logs ¶
Logs returns a snapshot of the demo process's combined stdout and stderr. For clusters constructed via the CRDB_TEST_DSN bypass (which never spawns a subprocess) it returns an empty string with no special marker; callers diagnosing a failure should treat empty output as "no subprocess to capture from". When the buffer is present, Logs is safe to call concurrently with the running subprocess: writes from the cmd's stdout/stderr-copy goroutines are mutex-serialized in lockedBuf.
func (*Cluster) Stop ¶
Stop sends SIGINT to the demo process and waits up to 10s for it to exit. If the process does not exit in time, Stop sends SIGKILL and the returned error reports that the graceful shutdown deadline was exceeded. Stop also removes the cluster's tempdir; either failure (shutdown or tmpdir removal) is surfaced via errors.Join so neither is silently lost. Stop is idempotent: subsequent calls return the original error without re-executing the teardown. The captured stdout/stderr remains accessible via Logs() after Stop returns.
type Option ¶
type Option interface {
// contains filtered or unexported methods
}
Option configures Start.
func WithExtraArgs ¶
WithExtraArgs appends additional command-line arguments to the `cockroach demo` invocation, after the harness's own flags. Use this for tests that need a non-default demo configuration; do not pass any flag that Start already sets (see the args slice in Start). Multiple WithExtraArgs calls accumulate; arguments appear in call order.
func WithSecure ¶
func WithSecure() Option
WithSecure drops `--insecure` from the cockroach demo invocation. In secure mode demo provisions a self-signed CA and a node certificate into a tempdir, then writes a TLS-enabled DSN whose query string includes at least `sslmode` and `sslrootcert` pointing at the demo-issued CA. Demo authenticates the SQL session with a generated password rather than a client certificate, so the DSN does not carry `sslcert`/`sslkey` — tests exercising the client-cert auth path need their own `cockroach cert create-*` setup.
Secure clusters cannot be served by Shared, which caches an insecure cluster — call Start directly and Stop in defer/cleanup.
func WithStartTimeout ¶
WithStartTimeout overrides the default 30s timeout Start uses while polling for the demo cluster's listening-url-file. This governs only URL-file appearance, not full SQL readiness — that readiness is the caller's concern (typically a Ping retry loop). Demo startup on a loaded CI machine can be slower than 30s; bump this if Start times out.