Skip to content

Commit

Permalink
test: sanity tests for primary and replica
Browse files Browse the repository at this point in the history
* new --replica option to `postgrest-with-postgresql-*`
* new command `postgrest-test-replica`
* new sanity tests on test_replica.py
* add postgrest-test-replica to postgrest-check and postgrest-coverage
  • Loading branch information
steve-chavez committed Apr 30, 2024
1 parent cdb8771 commit d9a51f2
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 10 deletions.
1 change: 1 addition & 0 deletions nix/tools/devTools.nix
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ let
${tests}/bin/postgrest-test-doctests
${tests}/bin/postgrest-test-io
${tests}/bin/postgrest-test-big-schema
${tests}/bin/postgrest-test-replica
${style}/bin/postgrest-lint
${style}/bin/postgrest-style-check
'';
Expand Down
26 changes: 23 additions & 3 deletions nix/tools/tests.nix
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ let
''
${cabal-install}/bin/cabal v2-build ${devCabalOptions}
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} -f test/io/fixtures.sql \
${ioTestPython}/bin/pytest --ignore=test/io/test_big_schema.py -v test/io "''${_arg_leftovers[@]}"
${ioTestPython}/bin/pytest --ignore=test/io/test_big_schema.py --ignore=test/io/test_replica.py -v test/io "''${_arg_leftovers[@]}"
'';

testBigSchema =
Expand All @@ -102,6 +102,21 @@ let
${ioTestPython}/bin/pytest -v test/io/test_big_schema.py "''${_arg_leftovers[@]}"
'';

testReplica =
checkedShellScript
{
name = "postgrest-test-replica";
docs = "Run a pytest-based IO test on a replica. Add -k to run tests that match a given expression.";
args = [ "ARG_LEFTOVERS([pytest arguments])" ];
workingDir = "/";
withEnv = postgrest.env;
}
''
${cabal-install}/bin/cabal v2-build ${devCabalOptions}
${cabal-install}/bin/cabal v2-exec -- ${withTools.withPg} --replica -f test/io/replica.sql \
${ioTestPython}/bin/pytest -v test/io/test_replica.py "''${_arg_leftovers[@]}"
'';

dumpSchema =
checkedShellScript
{
Expand Down Expand Up @@ -150,12 +165,16 @@ let
# collect all tests
HPCTIXFILE="$tmpdir"/io.tix \
${withTools.withPg} -f test/io/fixtures.sql \
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest --ignore=test/io/test_big_schema.py -v test/io
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest --ignore=test/io/test_big_schema.py --ignore=test/io/test_replica.py -v test/io
HPCTIXFILE="$tmpdir"/big_schema.tix \
${withTools.withPg} -f test/io/big_schema.sql \
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest -v test/io/test_big_schema.py
HPCTIXFILE="$tmpdir"/replica.tix \
${withTools.withPg} --replica -f test/io/replica.sql \
${cabal-install}/bin/cabal v2-exec ${devCabalOptions} -- ${ioTestPython}/bin/pytest -v test/io/test_replica.py
HPCTIXFILE="$tmpdir"/spec.tix \
${withTools.withPg} -f test/spec/fixtures/load.sql \
${cabal-install}/bin/cabal v2-run ${devCabalOptions} test:spec
Expand All @@ -164,7 +183,7 @@ let
# collect all the tix files
${ghc}/bin/hpc sum --union --exclude=Paths_postgrest --output="$tmpdir"/tests.tix \
"$tmpdir"/io*.tix "$tmpdir"/big_schema*.tix "$tmpdir"/spec.tix
"$tmpdir"/io*.tix "$tmpdir"/big_schema*.tix "$tmpdir"/replica*.tix "$tmpdir"/spec.tix
# prepare the overlay
${ghc}/bin/hpc overlay --output="$tmpdir"/overlay.tix test/coverage.overlay
Expand Down Expand Up @@ -220,6 +239,7 @@ buildToolbox
testSpecIdempotence
testIO
testBigSchema
testReplica
dumpSchema
coverage
coverageDraftOverlay;
Expand Down
47 changes: 40 additions & 7 deletions nix/tools/withTools.nix
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ let
"ARG_USE_ENV([PGRST_DB_SCHEMAS], [test], [Schema to expose])"
"ARG_USE_ENV([PGTZ], [utc], [Timezone to use])"
"ARG_USE_ENV([PGOPTIONS], [-c search_path=public,test], [PG options to use])"
"ARG_OPTIONAL_BOOLEAN([replica],, [Enable a replica for the database])"
];
positionalCompletion = "_command";
workingDir = "/";
Expand Down Expand Up @@ -61,6 +62,7 @@ let
HBA_FILE="$tmpdir/pg_hba.conf"
echo "local $PGDATABASE some_protected_user password" > "$HBA_FILE"
echo "local $PGDATABASE all trust" >> "$HBA_FILE"
echo "local replication all trust" >> "$HBA_FILE"
log "Initializing database cluster..."
# We try to make the database cluster as independent as possible from the host
Expand All @@ -74,19 +76,50 @@ let
pg_ctl -l "$tmpdir/db.log" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $PGHOST -c log_statement=\"all\" " \
>> "$setuplog"
log "Creating a minimally privileged $PGUSER connection role..."
createuser "$PGUSER" -U postgres --host="$tmpdir/socket" --no-createdb --no-inherit --no-superuser --no-createrole --no-replication --login
>&2 echo "${commandName}: You can connect with: psql 'postgres:///$PGDATABASE?host=$PGHOST' -U postgres"
>&2 echo "${commandName}: You can tail the logs with: tail -f $tmpdir/db.log"
if test "$_arg_replica" = "on"; then
replica_slot="replica_$RANDOM"
replica_dir="$tmpdir/$replica_slot"
replica_host="$tmpdir/socket_$replica_slot"
mkdir -p "$replica_host"
replica_dblog="$tmpdir/db_$replica_slot.log"
log "Running pg_basebackup for $replica_slot"
pg_basebackup -v -h "$PGHOST" -U postgres --wal-method=stream --create-slot --slot="$replica_slot" --write-recovery-conf -D "$replica_dir" \
>> "$setuplog" 2>&1
log "Starting replica on $replica_host"
pg_ctl -D "$replica_dir" -l "$replica_dblog" -w start -o "-F -c listen_addresses=\"\" -c hba_file=$HBA_FILE -k $replica_host -c log_statement=\"all\" " \
>> "$setuplog"
>&2 echo "${commandName}: Replica enabled. You can connect to it with: psql 'postgres:///$PGDATABASE?host=$replica_host' -U postgres"
>&2 echo "${commandName}: You can tail the replica logs with: tail -f $replica_dblog"
export PGREPLICAHOST="$replica_host"
export PGREPLICASLOT="$replica_slot"
fi
# shellcheck disable=SC2317
stop () {
log "Stopping the database cluster..."
pg_ctl stop -m i >> "$setuplog"
pg_ctl stop --mode=immediate >> "$setuplog"
rm -rf "$tmpdir/db"
if test "$_arg_replica" = "on"; then
log "Stopping the replica cluster..."
pg_ctl -D "$replica_dir" stop --mode=immediate >> "$setuplog"
rm -rf "$replica_dir"
fi
}
trap stop EXIT
log "Creating a minimally privileged $PGUSER connection role..."
createuser "$PGUSER" -U postgres --host="$tmpdir/socket" --no-createdb --no-inherit --no-superuser --no-createrole --no-replication --login
>&2 echo "${commandName}: You can connect with: psql 'postgres:///$PGDATABASE?host=$tmpdir/socket' -U postgres"
>&2 echo "${commandName}: You can tail the logs with: tail -f $tmpdir/db.log"
fi
if test "$_arg_fixtures"; then
Expand Down
21 changes: 21 additions & 0 deletions test/io/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,27 @@ def defaultenv(baseenv):
}


@pytest.fixture
def replicaenv(defaultenv):
"Default environment for a PostgREST replica."
conf = {
"PGRST_DB_ANON_ROLE": "postgrest_test_anonymous",
"PGRST_DB_SCHEMAS": "replica",
}
return {
"primary": {
**defaultenv,
**conf,
},
"replica": {
**defaultenv,
**conf,
"PGHOST": os.environ["PGREPLICAHOST"],
"PGREPLICASLOT": os.environ["PGREPLICASLOT"],
},
}


@pytest.fixture
def slow_schema_cache_env(defaultenv):
"Slow schema cache load environment PostgREST."
Expand Down
21 changes: 21 additions & 0 deletions test/io/replica.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
create schema replica;

create or replace function replica.is_replica() returns bool as $$
select pg_is_in_recovery();
$$ language sql;

create or replace function replica.get_replica_slot() returns name as $$
select slot_name from pg_replication_slots limit 1;
$$ language sql;

create table replica.items as select x as id from generate_series(1, 10) x;

DROP ROLE IF EXISTS postgrest_test_anonymous;
CREATE ROLE postgrest_test_anonymous;

GRANT postgrest_test_anonymous TO :PGUSER;

GRANT USAGE ON SCHEMA replica TO postgrest_test_anonymous;

GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA replica
TO postgrest_test_anonymous;
28 changes: 28 additions & 0 deletions test/io/test_replica.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"IO tests for PostgREST started on replicas"

import pytest

from config import *
from util import *
from postgrest import *


def test_sanity_replica(replicaenv):
"Test that primary and replica are working as intended"

with run(env=replicaenv["primary"]) as postgrest:
response = postgrest.session.get("/rpc/is_replica")
assert response.text == "false"

response = postgrest.session.get("/rpc/get_replica_slot")
assert response.text == '"' + replicaenv["replica"]["PGREPLICASLOT"] + '"'

response = postgrest.session.get("/items?select=count")
assert response.text == '[{"count":10}]'

with run(env=replicaenv["replica"]) as postgrest:
response = postgrest.session.get("/rpc/is_replica")
assert response.text == "true"

response = postgrest.session.get("/items?select=count")
assert response.text == '[{"count":10}]'

0 comments on commit d9a51f2

Please sign in to comment.