PgClone Testing

PgClone has a comprehensive test suite that runs across PostgreSQL versions 14–18 using pgTAP, Docker Compose, and GitHub Actions CI.

Test Suite Overview

The test suite is organized into three test groups:

1. pgTAP Sync Tests (33 tests)

Located in test/pgclone_test.sql, these cover core synchronous functionality:

Group Tests What It Covers
1. Extension loading 3 Extension installs, version string
2. Table clone (data) 3 Clone table with data, verify rows
3. Table rename 3 Clone with different target name
4. Structure only 3 Clone without data, verify 0 rows
5. Schema clone 5 Full schema with tables + verify data
6. Indexes 2 Verify indexes are cloned
7. Constraints 3 PK, FK verification
8. Views 2 Regular views cloned
9. Functions 2 Functions cloned with correct signatures
10. Selective columns 3 Column filtering, verify column count
11. WHERE filter 2 Row filtering, verify filtered count

2. Database Create Tests

Located in test/test_database_create.sh — verifies pgclone_database_create() creates a new database, clones data into it, and supports idempotent re-cloning.

3. Async Tests

Located in test/test_async.sh — covers background worker operations:

  • pgclone_table_async — basic async table clone
  • pgclone_table_async — with target rename
  • pgclone_schema_async — full schema async clone
  • pgclone_progress / pgclone_jobs / pgclone_jobs_view — progress tracking
  • pgclone_clear_jobs — cleanup

Running Tests Locally

Prerequisites

  • Docker and Docker Compose installed
  • Repository cloned locally

Run all tests on a specific PostgreSQL version

docker compose down -v
docker compose up source-db -d
docker compose run --rm test-pg17

Filter test output

docker compose run --rm test-pg17 2>&1 | grep -E "(ok|not ok|WARNING|ERROR|PASSED|FAILED)"

Run on all PostgreSQL versions

for pg in 14 15 16 17 18; do
    echo "=== PostgreSQL $pg ==="
    docker compose down -v
    docker compose up source-db -d
    docker compose run --rm test-pg$pg 2>&1 | tail -5
done

Clean up

docker compose down -v

Docker Test Architecture

Source Database (source-db)

  • Uses postgres:18 image
  • Seeded with test/fixtures/seed.sql containing test schemas, tables, indexes, constraints, triggers, views, materialized views, functions, and sample data
  • Exposed via Docker Compose networking (no host port mapping needed)

Test Containers (test-pg14 through test-pg18)

Each test container:

  1. Builds from the project Dockerfile with a PG_VERSION build arg
  2. Installs build dependencies, pgTAP, and compiles pgclone
  3. Configures shared_preload_libraries = 'pgclone' and max_worker_processes = 32
  4. Runs test/run_tests.sh as an initdb script, which:
    • Waits for the source database to be ready
    • Creates extensions (pgtap, pgclone)
    • Sets the source connection info as a PostgreSQL GUC (app.source_conninfo)
    • Runs pgTAP tests, database create tests, and async tests
    • Reports pass/fail and exits

Why Docker Compose Instead of Host-Based CI?

The extension installs a .so file into PostgreSQL’s pkglibdir. When the target database runs inside a Docker container but the extension is built on the host, the container can’t find the .so. Docker Compose ensures the extension is built inside the same container that runs the target PostgreSQL, solving this path mismatch.


GitHub Actions CI

The CI pipeline (.github/workflows/ci.yml) runs on every push to main, fix/**, and feature/** branches, and on PRs to main.

Matrix Strategy

Tests run in parallel across PostgreSQL 14, 15, 16, 17, and 18 with fail-fast: false — so a failure on one version doesn’t cancel the others.

CI Steps

  1. Install PostgreSQL — from PGDG APT repository
  2. Build pgclonemake PG_CONFIG=... with version-specific pg_config
  3. Start target PostgreSQL — separate instance on port 5434 with shared_preload_libraries = 'pgclone'
  4. Seed source database — GitHub Actions service container on port 5433
  5. Install pgTAP — built against the same PG version
  6. Run sync tests — 33 pgTAP tests
  7. Run database_create tests — creates/clones/verifies/cleans up
  8. Run async tests — background worker tests with polling
  9. Show logs on failure — dumps PostgreSQL server log for debugging

Service Container

The source database runs as a GitHub Actions service container (postgres:${{ matrix.pg_version }}), which provides a fresh source database for each matrix job.


Test Data

The test fixture (test/fixtures/seed.sql) creates:

  • Schema: test_schema
  • Tables: customers (10 rows), orders (10 rows), order_items (10 rows)
  • Indexes: 5 indexes including expression index (lower(name)) and DESC index
  • Constraints: PK on all tables, FK (orders → customers, order_items → orders), UNIQUE (email), CHECK (score)
  • Triggers: 2 triggers with trigger functions
  • Sequences: invoice_seq
  • Views: active_customers, order_summary
  • Materialized View: customer_stats with unique index
  • Functions: update_timestamp(), log_order_change(), get_customer_orders(int)
  • Public schema table: simple_test (5 rows) for basic clone tests

Adding New Tests

pgTAP test

Add to test/pgclone_test.sql, increment the plan count:

SELECT plan(34);  -- was 33

-- Your new test
SELECT lives_ok(
    format('SELECT pgclone_table(%L, %L, %L, true)',
        current_setting('app.source_conninfo'),
        'public', 'new_table'),
    'description of what this tests'
);

Shell-based test

Create a new script in test/ and add it to test/run_tests.sh:

bash /build/pgclone/test/test_your_feature.sh 2>&1
YOUR_EXIT=$?
if [ $YOUR_EXIT -ne 0 ]; then
    TEST_EXIT=1
fi