pg_embedded_setup_unpriv::TestCluster wraps bootstrap_for_tests() with a
Resource Acquisition Is Initialization (RAII) lifecycle. Constructing the guard
starts PostgreSQL using the discovered settings, applies the environment
produced by the bootstrap helper, and exposes the configuration to callers.
Dropping the guard stops the instance and restores the prior process
environment, so subsequent tests start from a clean slate.
use pg_embedded_setup_unpriv::{TestCluster, error::BootstrapResult};
fn exercise_cluster() -> BootstrapResult<()> {
let cluster = TestCluster::new()?;
let url = cluster.settings().url("app_db");
// Issue queries using any preferred client here.
drop(cluster); // PostgreSQL shuts down automatically.
Ok(())
}
The guard keeps PGPASSFILE, TZ, TZDIR, and the XDG directories populated
for the duration of its lifetime, making synchronous tests usable without extra
setup. Unit and behavioural tests assert that postmaster.pid disappears after
drop, demonstrating that no orphaned processes remain.
Using the `rstest` fixture
pg_embedded_setup_unpriv::test_support::test_cluster exposes an rstest
fixture that constructs the RAII guard on demand. Import the fixture so it is
in scope and declare a test_cluster: TestCluster parameter inside an
#[rstest] function; the macro injects the running cluster automatically.
use pg_embedded_setup_unpriv::{test_support::test_cluster, TestCluster};
use rstest::rstest;
#[rstest]
fn runs_migrations(test_cluster: TestCluster) {
let metadata = test_cluster.connection().metadata();
assert!(metadata.port() > 0);
}
The fixture integrates with rstest-bdd v0.1.0-alpha4 so behaviour tests can
remain declarative as well:
use pg_embedded_setup_unpriv::{test_support::test_cluster, TestCluster};
use rstest_bdd_macros::scenario;
#[scenario(path = "tests/features/test_cluster_fixture.feature", index = 0)]
fn coverage(test_cluster: TestCluster) {
let _ = test_cluster.environment();
}
If PostgreSQL cannot start, the fixture panics with a
SKIP-TEST-CLUSTER-prefixed message that retains the original error. Unit
tests fail immediately, while behaviour tests can convert known transient
conditions into soft skips via the shared skip_message helper.
Connection helpers and Diesel integration
TestCluster::connection() exposes TestClusterConnection, a lightweight view
over the running cluster's connection metadata. Use it to read the host, port,
superuser name, generated password, or the .pgpass path without cloning the
entire bootstrap struct. When you need to persist those values beyond the guard
you can call metadata() to obtain an owned ConnectionMetadata.
Enable the diesel-support feature to call diesel_connection() and obtain a
ready-to-use diesel::PgConnection. The default feature set keeps Diesel
optional for consumers, while make test already enables --all-features so
the helper is exercised by the smoke tests.
use diesel::prelude::*;
use pg_embedded_setup_unpriv::TestCluster;
# fn main() -> pg_embedded_setup_unpriv::BootstrapResult<()> {
let cluster = TestCluster::new()?;
let connection = cluster.connection();
let url = connection.database_url("postgres");
assert!(url.starts_with("postgresql://"));
#[cfg(feature = "diesel-support")]
{
let mut diesel_conn = connection.diesel_connection("postgres")?;
#[derive(QueryableByName)]
struct ValueRow {
#[diesel(sql_type = diesel::sql_types::Integer)]
value: i32,
}
let rows: Vec<ValueRow> = diesel::sql_query("SELECT 1 AS value")
.load(&mut diesel_conn)?;
assert_eq!(rows[0].value, 1);
}
# Ok(())
# }