Add framework for executing tests against multiple postgresql versions using docker compose.

This commit is contained in:
eelke 2026-10-18 12:09:54 +02:00
parent 655c6fceb1
commit c3bf9e88e4
13 changed files with 457 additions and 0 deletions

View file

@ -0,0 +1,43 @@
---
name: pg-integration-tests
description: Write and run pgLab tests against a real PostgreSQL server (14–17) using the pgintegration harness (DbTest fixture, template database, REQUIRE_PG_AT_LEAST). Use whenever a test needs a live server, e.g. catalog introspection, generated SQL that must be executed, version-specific behaviour, or when the user mentions integration tests, IntegrationTests, docker-compose Postgres or TEST_DATABASE_URL.
---
# Integration tests against real PostgreSQL
Build/run commands live in `AGENTS.md` (Build and test); don't duplicate them here.
## When to use
Use for behaviour that depends on a real server: catalog queries, `pg_get_*` output, executing generated SQL, version differences. Pure string/logic tests belong in `PgsqlTests` / `pglabtests` instead.
## Layout
- `tests/pgintegration/` – static lib: `PgEnv` (global environment, builds template DB `tmpl_<pid>` from `fixtures/schema.sql`), `DbTest` fixture, helpers.
- `tests/integration/` – `IntegrationTests` executable, `tst_*.cpp`, `fixtures/schema.sql`, `docker-compose.yml`.
- The binary only reads `TEST_DATABASE_URL`; unset means every `DbTest` skips.
## Writing a test
```cpp
#include "DbTest.h"
#include "PgTestEnvironment.h"
class MyFeature : public pgtest::DbTest {};
TEST_F(MyFeature, Works)
{
REQUIRE_PG_AT_LEAST(15); // skip on older servers
auto r = conn().query("SELECT 1"); // Pgsql::Connection, throws on SQL error
EXPECT_EQ(r.rows(), 1);
}
```
- Derive from `pgtest::DbTest`. Each test gets a fresh database (`t_<n>_<pid>`) cloned from the template and dropped afterwards, so never rely on state from another test and freely modify data/schema.
- `conn()` is the test connection, `dbUrl()` gives a URL for code under test that opens its own connection (close those before the test ends; teardown uses `DROP DATABASE ... WITH (FORCE)`).
- Gate version-specific features with `REQUIRE_PG_AT_LEAST(v)`; use `pgtest::serverVersionNum()` for finer checks. Also test graceful behaviour on PG 14.
- `query()` throws on error; use `EXPECT_THROW` for expected failures.
## Adding things
- New test file: add it to the `add_executable(IntegrationTests ...)` list in `tests/integration/CMakeLists.txt` (no globbing).
- Shared schema: extend `tests/integration/fixtures/schema.sql` (plain multi-statement SQL, loaded once per process into the template). Keep it small; it must work on all of 14–17. Version-specific schema should be created inside the test.
- Cluster-wide objects (roles, tablespaces) are not isolated by cloning: use unique names (include `pgtest::processId()`) and drop them in `TearDown`.
## Running and checking
- One version manually: set `TEST_DATABASE_URL` and use `--gtest_filter` (see AGENTS.md); start servers with `docker compose -f tests/integration/docker-compose.yml up -d --wait pg16`, stop with `down -v`.
- After a run no `t_*` or `tmpl_*` databases should remain: `psql <url> -Atc "select datname from pg_database where datname ~ '^(t|tmpl)_'"`.