#!/bin/sh # # Test Postgres 15 -> 17 upgrade for self-hosted Supabase. # # Seeds test data on a running Postgres 15 stack, runs the upgrade script, # and verifies data integrity + service connectivity using pgTAP. # # Usage: # cd docker/ # sudo bash tests/test-pg17-upgrade.sh # # Prerequisites: # - Running self-hosted Supabase with a clean, tests-only Postgres 15. # Postgres 17 is now the default, so start PG 15 explicitly via the override: # docker compose -f docker-compose.yml -f docker-compose.pg15.yml up -d # - .env file with POSTGRES_PASSWORD, ANON_KEY # set -eu DB_CONTAINER="supabase-db" if [ ! -f .env ]; then echo "Error: .env file not found. Run from the docker/ directory." exit 1 fi pg_password=$(grep '^POSTGRES_PASSWORD=' .env | cut -d '=' -f 2-) anon_key=$(grep '^ANON_KEY=' .env | cut -d '=' -f 2- || true) if [ -z "$pg_password" ]; then echo "Error: POSTGRES_PASSWORD not set in .env" exit 1 fi run_sql() { docker exec -i \ -e PGPASSWORD="$pg_password" \ "$DB_CONTAINER" \ psql -h localhost -U supabase_admin -d postgres -v ON_ERROR_STOP=1 "$@" } echo "" echo "=== Postgres 15 -> 17 Upgrade Test ===" echo "" # --- Verify we're starting from Postgres 15 -------------------------------- current_version=$(run_sql -A -t -c "SHOW server_version;" | head -1) case "$current_version" in 15.*) echo "Starting version: PostgreSQL $current_version" ;; 17.*) echo "Error: Already on Postgres 17. Start with a PG 15 stack."; exit 1 ;; *) echo "Error: Unexpected version: $current_version"; exit 1 ;; esac # --- Seed test data -------------------------------------------------------- # Note: this script is designed to run against a fresh docker-compose stack, # not an existing database with user data. echo "" echo "Seeding test data on Postgres 15..." run_sql <<'EOSQL' -- Test table with various column types CREATE TABLE IF NOT EXISTS public._upgrade_test ( id serial PRIMARY KEY, name text NOT NULL, value numeric(10,2), created_at timestamptz DEFAULT now(), metadata jsonb ); TRUNCATE public._upgrade_test; INSERT INTO public._upgrade_test (name, value, metadata) VALUES ('alpha', 1.50, '{"tag": "a"}'), ('bravo', 2.75, '{"tag": "b"}'), ('charlie', 3.00, '{"tag": "c"}'), ('delta', 4.25, '{"tag": "d"}'), ('echo', 5.99, '{"tag": "e"}'); -- Index CREATE INDEX IF NOT EXISTS _upgrade_test_name_idx ON public._upgrade_test (name); -- Function CREATE OR REPLACE FUNCTION public._upgrade_test_fn(n int) RETURNS int LANGUAGE sql IMMUTABLE AS $$ SELECT n * 2; $$; -- Grant access so PostgREST can read it GRANT SELECT ON public._upgrade_test TO anon, authenticated; -- pg_cron: created here as supabase_admin (the common manually-enabled case), -- so the extension is owned by supabase_admin, NOT postgres. complete.sh's -- drop+recreate only fires for postgres-owned pg_cron, so this exercises the -- version reconcile in the upgrade script: Supabase PG 15 registers pg_cron -- as '1.6', while the target image packages it as '1.6.4' with no update -- path between them. CREATE EXTENSION IF NOT EXISTS pg_cron; DO $$ BEGIN IF EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'upgrade_test_job') THEN PERFORM cron.unschedule('upgrade_test_job'); END IF; END $$; SELECT cron.schedule('upgrade_test_job', '5 4 * * *', 'SELECT 1'); EOSQL pre_count=$(run_sql -A -t -c "SELECT count(*) FROM public._upgrade_test;" | tr -d '[:space:]') pre_checksum=$(run_sql -A -t -c "SELECT md5(string_agg(name || value::text, ',' ORDER BY id)) FROM public._upgrade_test;" | tr -d '[:space:]') echo " Rows: $pre_count" echo " Checksum: $pre_checksum" # --- Seed a Vault secret --------------------------------------------------- # Verifies the pgsodium root key survives the volume swap/chown AND that Vault # secrets still decrypt on Postgres 17. For legacy (key_id-based) secrets this # also exercises complete.sh's pgsodium->Vault re-encryption; on a stock # self-hosted stack the secret is already pgsodium-less, so this confirms the # round-trip and the post-upgrade invariant (key_id IS NULL). VAULT_SECRET_NAME="upgrade_test_secret" VAULT_SECRET_VALUE="upgrade-test-secret-value-42" vault_available="f" if [ "$(run_sql -A -t -c "SELECT EXISTS (SELECT 1 FROM pg_available_extensions WHERE name = 'supabase_vault');" | tr -d '[:space:]')" = "t" ]; then echo "" echo "Seeding Vault secret on Postgres 15..." run_sql <&2 fi vault_available="t" else echo "" echo "Skipping Vault seed: supabase_vault extension not available." fi # --- Run upgrade ----------------------------------------------------------- echo "" echo "Running upgrade script..." echo "" bash utils/upgrade-pg17.sh --yes echo "" # --- Verify with pgTAP ---------------------------------------------------- echo "Running pgTAP verification..." echo "" # Optional Vault assertions, only when a secret was seeded above. vault_plan=0 vault_tests="" if [ "$vault_available" = "t" ]; then vault_plan=3 vault_tests=$(cat </dev/null) || rest_status="000" check "PostgREST connectivity" "200" "$rest_status" fi # Auth health (needs apikey header through the API gateway) if [ -n "$anon_key" ]; then auth_status=$(curl -s -o /dev/null -w "%{http_code}" \ -H "apikey: $anon_key" \ "http://localhost:8000/auth/v1/health" 2>/dev/null) || auth_status="000" check "Auth service health" "200" "$auth_status" fi echo "" echo " Services: $pass passed, $fail failed" # --- Clean up test artifacts ---------------------------------------------- echo "" echo "Cleaning up test artifacts..." run_sql <<'EOSQL' || true DROP FUNCTION IF EXISTS public._upgrade_test_fn(int); DROP TABLE IF EXISTS public._upgrade_test; DROP EXTENSION IF EXISTS pgtap; DO $$ BEGIN IF EXISTS (SELECT 1 FROM cron.job WHERE jobname = 'upgrade_test_job') THEN PERFORM cron.unschedule('upgrade_test_job'); END IF; END $$; DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_extension WHERE extname = 'supabase_vault') THEN DELETE FROM vault.secrets WHERE name = 'upgrade_test_secret'; END IF; END $$; EOSQL # --- Summary -------------------------------------------------------------- echo "" if [ "$fail" -gt 0 ]; then echo "=== SOME TESTS FAILED ===" exit 1 fi echo "=== Upgrade test passed ===" echo "" echo "To reclaim disk space:" echo " rm -rf ./volumes/db/data.bak.pg15 ./volumes/db/pg17_upgrade_bin_*.tar.gz" echo ""