From 1a209f6960b10d6bb476b2c19aa16b46d8ef40aa Mon Sep 17 00:00:00 2001 From: yukkop Date: Thu, 30 Apr 2026 22:12:09 +0000 Subject: [PATCH] test(`postgres-hooks`): retarget hectic bundle tests to migrator init + db-tool hydrate Move postgres-init-hectic-inheritance test (13 cases) to migrator/init-hectic-bundle since the bundle is now applied by `migrator init` instead of `postgres-init`. Drop init-migrator-with-inherits since `--inherits` is now a deprecation warning, not an error. Add db-tool hydrate-hook test (5 cases) covering --no-hook skip, default apply, idempotency, and HECTIC_DOTENV_FILE. Augment init-migrator with hectic.version and hectic.secret table assertions. --- .../test/postgresql/hydrate-hook/run.sh | 72 +++++++++++++++ .../postgresql/init-hectic-bundle}/run.sh | 90 +++++++++---------- .../postgresql/init-migrator-with-inherits.sh | 64 ------------- .../migrator/test/postgresql/init-migrator.sh | 10 +++ 4 files changed, 126 insertions(+), 110 deletions(-) create mode 100644 test/package/db-tool/test/postgresql/hydrate-hook/run.sh rename test/package/{db-tool/test/postgresql/postgres-init-hectic-inheritance => migrator/test/postgresql/init-hectic-bundle}/run.sh (58%) delete mode 100644 test/package/migrator/test/postgresql/init-migrator-with-inherits.sh diff --git a/test/package/db-tool/test/postgresql/hydrate-hook/run.sh b/test/package/db-tool/test/postgresql/hydrate-hook/run.sh new file mode 100644 index 0000000..d8ba3c8 --- /dev/null +++ b/test/package/db-tool/test/postgresql/hydrate-hook/run.sh @@ -0,0 +1,72 @@ +# shellcheck shell=dash + +HECTIC_NAMESPACE=test-db-tool-hydrate-hook + +PG_WORKING_DIR=$(mktemp -d) +export PG_WORKING_DIR PG_DATABASE=testdb PG_PORT=5432 PG_SHARED_PRELOAD_LIBRARIES='' + +cleanup() { + postgres-cleanup >/dev/null 2>&1 || : + rm -rf "$PG_WORKING_DIR" "$LOCAL_DIR" +} +trap 'cleanup' EXIT INT TERM + +LOCAL_DIR=$(mktemp -d) +export LOCAL_DIR + +mkdir -p "${LOCAL_DIR}/db/src" +: > "${LOCAL_DIR}/db/src/entrypoint.sql" + +if ! postgres-init; then + log error "postgres-init failed" + exit 1 +fi + +PGURL="postgresql://$(id -un)@/testdb?host=${PG_WORKING_DIR}/sock&port=5432" +export PGURL + +count_hectic_objects() { + psql "$PGURL" -v ON_ERROR_STOP=1 -tAc \ + "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='hectic';" +} + +log notice "case 1: postgres-init alone does not create hectic schema" +got=$(psql "$PGURL" -v ON_ERROR_STOP=1 -tAc "SELECT count(*) FROM pg_namespace WHERE nspname='hectic';") || exit 1 +[ "$got" = 0 ] || { log error "hectic schema must not exist after pure postgres-init (got: $got)"; exit 1; } + +log notice "case 2: hydrate --no-hook does not apply bundle" +if ! database hydrate --no-hook; then + log error "database hydrate --no-hook failed" + exit 1 +fi +got=$(psql "$PGURL" -v ON_ERROR_STOP=1 -tAc "SELECT count(*) FROM pg_namespace WHERE nspname='hectic';") || exit 1 +[ "$got" = 0 ] || { log error "hectic schema unexpectedly created with --no-hook (got: $got)"; exit 1; } + +log notice "case 3: hydrate (default) applies bundle" +if ! database hydrate; then + log error "database hydrate failed" + exit 1 +fi +got=$(count_hectic_objects) || exit 1 +[ "$got" -ge 6 ] || { log error "expected >=6 hectic objects after hydrate, got: $got"; exit 1; } + +got=$(psql "$PGURL" -v ON_ERROR_STOP=1 -tAc "SELECT count(*) FROM hectic.version;") || exit 1 +[ "$got" = 1 ] || { log error "hectic.version row missing (got: $got)"; exit 1; } + +log notice "case 4: hydrate is idempotent" +if ! database hydrate; then + log error "second database hydrate failed" + exit 1 +fi + +log notice "case 5: HECTIC_DOTENV_FILE is honored" +dotenv_file=$(mktemp) +printf 'TEST_SECRET=hello-world\n' > "$dotenv_file" +HECTIC_DOTENV_FILE="$dotenv_file" database hydrate || { + log error "hydrate with HECTIC_DOTENV_FILE failed" + rm -f "$dotenv_file" + exit 1 +} +rm -f "$dotenv_file" + +log notice "test passed" diff --git a/test/package/db-tool/test/postgresql/postgres-init-hectic-inheritance/run.sh b/test/package/migrator/test/postgresql/init-hectic-bundle/run.sh similarity index 58% rename from test/package/db-tool/test/postgresql/postgres-init-hectic-inheritance/run.sh rename to test/package/migrator/test/postgresql/init-hectic-bundle/run.sh index df0d12a..9313c79 100644 --- a/test/package/db-tool/test/postgresql/postgres-init-hectic-inheritance/run.sh +++ b/test/package/migrator/test/postgresql/init-hectic-bundle/run.sh @@ -1,53 +1,49 @@ # shellcheck shell=dash -HECTIC_NAMESPACE=test-db-tool-hectic-inheritance +HECTIC_NAMESPACE=test-init-hectic-bundle -PG_WORKING_DIR=$(mktemp -d) -export PG_WORKING_DIR PG_DATABASE=testdb PG_PORT=5432 PG_SHARED_PRELOAD_LIBRARIES='' -export PG_HECTIC_INHERITANCE=1 - -cleanup() { - postgres-cleanup >/dev/null 2>&1 || : - rm -rf "$PG_WORKING_DIR" -} -trap 'cleanup' EXIT INT TERM - -if ! postgres-init; then - log error "postgres-init with PG_HECTIC_INHERITANCE=1 failed" +if ! migrator --db-url "$DATABASE_URL" init; then + log error "migrator init failed" exit 1 fi -sockdir="$PG_WORKING_DIR/sock" -user=$(id -un) -pgurl="postgresql://${user}@/testdb?host=${sockdir}&port=5432" - run_sql() { - psql "$pgurl" -v ON_ERROR_STOP=1 -tAc "$1" + psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -tAc "$1" } run_sql_expect_fail() { - if psql "$pgurl" -v ON_ERROR_STOP=1 -c "$1" >/dev/null 2>&1; then + if psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c "$1" >/dev/null 2>&1; then return 1 fi return 0 } -log notice "case 1: hectic schema and parent tables exist" +log notice "case 1: hectic schema, version/secret/migration/parent tables exist" got=$(run_sql "SELECT count(*) FROM pg_namespace WHERE nspname='hectic';") || exit 1 [ "$got" = 1 ] || { log error "hectic schema missing"; exit 1; } -got=$(run_sql "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='hectic' AND c.relname IN ('created_at','updated_at','immutable');") || exit 1 -[ "$got" = 3 ] || { log error "parent tables missing"; exit 1; } +got=$(run_sql "SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='hectic' AND c.relname IN ('version','secret','migration','created_at','updated_at','immutable');") || exit 1 +[ "$got" = 6 ] || { log error "expected 6 hectic tables (version,secret,migration,created_at,updated_at,immutable), got: $got"; exit 1; } -log notice "case 2: CREATE TABLE without inheritance is rejected" +log notice "case 2: hectic.version row populated" +got=$(run_sql "SELECT count(*) FROM hectic.version;") || exit 1 +[ "$got" = 1 ] || { log error "hectic.version row missing (got: $got)"; exit 1; } + +log notice "case 3: re-running migrator init is idempotent" +if ! migrator --db-url "$DATABASE_URL" init; then + log error "second migrator init failed" + exit 1 +fi + +log notice "case 4: CREATE TABLE without inheritance is rejected" if ! run_sql_expect_fail 'CREATE TABLE public.bad_table (id int);'; then log error "non-inheriting CREATE TABLE was accepted" exit 1 fi -log notice "case 3: CREATE TABLE inheriting hectic.created_at is accepted" +log notice "case 5: CREATE TABLE inheriting hectic.created_at is accepted" run_sql 'CREATE TABLE public.good_table (id int) INHERITS ("hectic"."created_at");' || exit 1 -log notice "case 4: tables inheriting hectic.updated_at get auto BEFORE UPDATE trigger" +log notice "case 6: tables inheriting hectic.updated_at get auto BEFORE UPDATE trigger" run_sql 'CREATE TABLE public.with_updated (id int, val text) INHERITS ("hectic"."created_at", "hectic"."updated_at");' || exit 1 got=$(run_sql "SELECT count(*) FROM pg_trigger WHERE tgrelid='public.with_updated'::regclass AND tgname='hectic_set_updated_at' AND NOT tgisinternal;") || exit 1 [ "$got" = 1 ] || { log error "auto updated_at trigger missing"; exit 1; } @@ -58,39 +54,31 @@ run_sql "UPDATE public.with_updated SET val='b' WHERE id=1;" || exit 1 got=$(run_sql "SELECT (updated_at > created_at)::int FROM public.with_updated WHERE id=1;") || exit 1 [ "$got" = 1 ] || { log error "updated_at not bumped on UPDATE (got: $got)"; exit 1; } -log notice "case 5: GUC hectic.inheritance_extra_excluded_schemas exempts schemas" +log notice "case 7: GUC hectic.inheritance_extra_excluded_schemas exempts schemas" run_sql 'CREATE SCHEMA legacy;' || exit 1 if ! run_sql_expect_fail 'CREATE TABLE legacy.t1 (id int);'; then log error "legacy.t1 should be rejected before GUC set" exit 1 fi -run_sql "ALTER DATABASE testdb SET hectic.inheritance_extra_excluded_schemas = 'legacy';" || exit 1 -psql "$pgurl" -v ON_ERROR_STOP=1 -c 'CREATE TABLE legacy.t1 (id int);' || { +run_sql "ALTER DATABASE \"$PGDATABASE\" SET hectic.inheritance_extra_excluded_schemas = 'legacy';" || exit 1 +psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c 'CREATE TABLE legacy.t1 (id int);' || { log error "legacy.t1 rejected even after GUC exclusion" exit 1 } -log notice "case 6: declarative partitions are exempt" -run_sql 'CREATE TABLE public.parted (id int, region text) PARTITION BY LIST (region) INHERITS ("hectic"."created_at");' && { - log error "PARTITION BY combined with INHERITS unexpectedly succeeded" - exit 1 -} || : -run_sql 'CREATE TABLE public.events (id int, region text, created_at timestamptz NOT NULL DEFAULT NOW()) PARTITION BY LIST (region);' && { - log error "partitioned parent without inheritance unexpectedly succeeded" - exit 1 -} || : -run_sql "ALTER DATABASE testdb SET hectic.inheritance_extra_excluded_schemas = 'legacy,parts';" || exit 1 +log notice "case 8: declarative partitions are exempt" +run_sql "ALTER DATABASE \"$PGDATABASE\" SET hectic.inheritance_extra_excluded_schemas = 'legacy,parts';" || exit 1 run_sql 'CREATE SCHEMA parts;' || exit 1 -psql "$pgurl" -v ON_ERROR_STOP=1 -c 'CREATE TABLE parts.events (id int, region text) PARTITION BY LIST (region);' || { +psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c 'CREATE TABLE parts.events (id int, region text) PARTITION BY LIST (region);' || { log error "partitioned parent in excluded schema rejected" exit 1 } -psql "$pgurl" -v ON_ERROR_STOP=1 -c "CREATE TABLE parts.events_us PARTITION OF parts.events FOR VALUES IN ('us');" || { +psql "$DATABASE_URL" -v ON_ERROR_STOP=1 -c "CREATE TABLE parts.events_us PARTITION OF parts.events FOR VALUES IN ('us');" || { log error "declarative partition was rejected (should be exempt via relispartition)" exit 1 } -log notice "case 7: hectic.immutable inheritors are blocked from DML outside migration_mode" +log notice "case 9: hectic.immutable inheritors are blocked from DML outside migration_mode" run_sql 'CREATE TABLE public.frozen (id int, label text) INHERITS ("hectic"."created_at", "hectic"."immutable");' || exit 1 got=$(run_sql "SELECT count(*) FROM pg_trigger WHERE tgrelid='public.frozen'::regclass AND tgname IN ('hectic_block_immutable_dml','hectic_block_immutable_truncate') AND NOT tgisinternal;") || exit 1 @@ -113,8 +101,8 @@ if ! run_sql_expect_fail "TRUNCATE public.frozen;"; then exit 1 fi -log notice "case 8: SET LOCAL hectic.migration_mode='on' allows DML" -psql "$pgurl" -v ON_ERROR_STOP=1 <<'SQL' || { log error "migration_mode tx failed"; exit 1; } +log notice "case 10: SET LOCAL hectic.migration_mode='on' allows DML" +psql "$DATABASE_URL" -v ON_ERROR_STOP=1 <<'SQL' || { log error "migration_mode tx failed"; exit 1; } BEGIN; SET LOCAL hectic.migration_mode = 'on'; INSERT INTO public.frozen (id, label) VALUES (1, 'x'); @@ -124,14 +112,14 @@ SQL got=$(run_sql "SELECT label FROM public.frozen WHERE id=1;") || exit 1 [ "$got" = y ] || { log error "expected label=y after migration tx, got: $got"; exit 1; } -log notice "case 9: GUC does not leak past COMMIT" +log notice "case 11: GUC does not leak past COMMIT" if ! run_sql_expect_fail "INSERT INTO public.frozen (id, label) VALUES (2, 'z');"; then log error "INSERT accepted after migration_mode tx committed (GUC leaked)" exit 1 fi -log notice "case 10: TRUNCATE allowed under migration_mode" -psql "$pgurl" -v ON_ERROR_STOP=1 <<'SQL' || { log error "truncate under migration_mode failed"; exit 1; } +log notice "case 12: TRUNCATE allowed under migration_mode" +psql "$DATABASE_URL" -v ON_ERROR_STOP=1 <<'SQL' || { log error "truncate under migration_mode failed"; exit 1; } BEGIN; SET LOCAL hectic.migration_mode = 'on'; TRUNCATE public.frozen; @@ -140,4 +128,14 @@ SQL got=$(run_sql "SELECT count(*) FROM public.frozen;") || exit 1 [ "$got" = 0 ] || { log error "frozen not truncated"; exit 1; } +log notice "case 13: --inherits emits deprecation warning but still succeeds" +warn_output=$(migrator --inherits some_table --db-url "$DATABASE_URL" init 2>&1) || { + log error "migrator init with deprecated --inherits failed" + exit 1 +} +if ! echo "$warn_output" | grep -q "deprecated"; then + log error "--inherits did not emit deprecation warning" + exit 1 +fi + log notice "test passed" diff --git a/test/package/migrator/test/postgresql/init-migrator-with-inherits.sh b/test/package/migrator/test/postgresql/init-migrator-with-inherits.sh deleted file mode 100644 index 832941d..0000000 --- a/test/package/migrator/test/postgresql/init-migrator-with-inherits.sh +++ /dev/null @@ -1,64 +0,0 @@ -#!/bin/dash - -HECTIC_NAMESPACE=test-init-migrator - -### CASE 2 -log notice "test case: ${WHITE}error: table inherit tables that not exists" - -set +e -migrator --inherits tablename --inherits 'table name' init --db-url "$DATABASE_URL" -error_code=$? -set -e - -if [ "$error_code" = 0 ]; then - log error "test failed: ${WHITE}no error handler" - exit 1 -elif [ "$error_code" != 5 ]; then - log error "test failed: ${WHITE}unexpected error code" - exit 1 -fi - -### CASE 3 -log notice "test case: ${WHITE}error: not provided --db-url" -set +e -migrator --inherits tablename --inherits 'table name' init -error_code=$? -set -e - -if [ "$error_code" = 0 ]; then - log error "test failed: ${WHITE}no error handler" - exit 1 -elif [ "$error_code" != 3 ]; then - log error "test failed: ${WHITE}unexpected error code" - exit 1 -fi - -### CASE 4 -log notice "test case: ${WHITE}normal" - -psql "$DATABASE_URL" -c 'CREATE TABLE "table name"(); CREATE TABLE tablename();' - -if ! migrator --inherits tablename --inherits 'table name' init --db-url "$DATABASE_URL"; then - log error "test failed: ${WHITE}error on init sql" - exit 1 -fi - -if ! psql -v ON_ERROR_STOP=1 "$DATABASE_URL" -c 'SELECT * FROM hectic.migration'; then - log error "test failed: ${WHITE} tabe hectic.migration was not created" - exit 1 -fi - -### CASE 5 -log notice "test case: ${WHITE}reinit (must just be ignored)" - -if ! migrator --inherits tablename --inherits 'table name' init --db-url "$DATABASE_URL"; then - log error "test failed: ${WHITE}error on init sql" - exit 1 -fi - -if ! psql -v ON_ERROR_STOP=1 "$DATABASE_URL" -c 'SELECT * FROM hectic.migration'; then - log error "test failed: ${WHITE} tabe hectic.migration was not created" - exit 1 -fi - -log notice "test passed" diff --git a/test/package/migrator/test/postgresql/init-migrator.sh b/test/package/migrator/test/postgresql/init-migrator.sh index c2ac8e4..f3453e9 100644 --- a/test/package/migrator/test/postgresql/init-migrator.sh +++ b/test/package/migrator/test/postgresql/init-migrator.sh @@ -38,6 +38,16 @@ if ! psql -v ON_ERROR_STOP=1 "$DATABASE_URL" -c 'SELECT * FROM hectic.migration' exit 1 fi +if ! psql -v ON_ERROR_STOP=1 "$DATABASE_URL" -c 'SELECT * FROM hectic.version'; then + log error "test failed: ${WHITE} table hectic.version was not created" + exit 1 +fi + +if ! psql -v ON_ERROR_STOP=1 "$DATABASE_URL" -c 'SELECT * FROM hectic.secret'; then + log error "test failed: ${WHITE} table hectic.secret was not created" + exit 1 +fi + ### CASE 5 log notice "test case: ${WHITE}reinit (must just be ignored)"