test: fix: migrator: multifile test

This commit is contained in:
2025-11-17 01:57:32 +00:00
parent 00f05cc3db
commit 5b1f05589d
6 changed files with 153 additions and 53 deletions

View File

@@ -1,5 +1,15 @@
#!/bin/dash #!/bin/dash
# error codes
# 1 - generic error
# 2 - ambiguous, when you try to use something that cannot be used in same time
# 3 - missing required argument / variable
# 4 -
# 5 - provided table that not exists
# 9 - argument or command not found
# 13 - program bug / unexpected system / database incompatibles
# 127 - command not found (dependency)
set -eu set -eu
if ! command -v psql >/dev/null; then if ! command -v psql >/dev/null; then
@@ -20,12 +30,13 @@ sha256sum() {
} }
INHERITS_LIST= INHERITS_LIST=
VARIABLE_LIST=
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
log debug "$1" log debug "$1"
case $1 in case $1 in
migrate|create|fetch|list|init) migrate|create|fetch|list|init)
[ "${SUBCOMMAND+x}" ] && { printf 'ambiguous subcommand, decide %s or %s\n' "$SUBCOMMAND" "$1"; exit 1; } [ "${SUBCOMMAND+x}" ] && { printf 'ambiguous subcommand, decide %s or %s\n' "$SUBCOMMAND" "$1"; exit 2; }
SUBCOMMAND=$1 SUBCOMMAND=$1
shift shift
;; ;;
@@ -56,40 +67,66 @@ init() {
DB_URL="$2" DB_URL="$2"
shift 2 shift 2
;; ;;
--set|-v)
VARIABLE_LIST="${VARIABLE_LIST:+$VARIABLE_LIST }$2"
shift 2
;;
--*|-*) --*|-*)
printf 'init argument %s does not exists' "$1" printf 'init argument %s does not exists' "$1"
exit 1 exit 9
;; ;;
*) *)
printf 'init command %s does not exists' "$1" printf 'init command %s does not exists' "$1"
exit 1 exit 9
;; ;;
esac esac
done done
error_handler_no_db_url
[ "${INIT_DRY_RUN+x}" ] && { printf '%s\n' "$(init_sql)"; exit; } [ "${INIT_DRY_RUN+x}" ] && { printf '%s\n' "$(init_sql)"; exit; }
error_handler_no_db_url
psql_args="$(form_psql_args)" psql_args="$(form_psql_args)"
oldIFS="$IFS"
IFS=','
check_inherits=
for table in $INHERITS_LIST; do
check_inherits="$(printf '%s\nSELECT 1 FROM %s LIMIT 1;' "$check_inherits" "$table")"
done
IFS="$oldIFS"
check_inherits=$(printf '%s\n' \
'BEGIN;' \
"$check_inherits" \
'COMMIT;')
# shellcheck disable=SC2086 # shellcheck disable=SC2086
if ! printf '%s' "$(init_sql)" | psql $psql_args; then if ! psql $psql_args -c "$check_inherits"; then
log error "Migration failed: ${WHITE}$fs_migration${NC}" log error "init failed: ${WHITE}one of inherits table does not exists: ${CYAN}$INHERITS_LIST"
return 3 exit 5
fi
# shellcheck disable=SC2086
if ! psql $psql_args -c "$(init_sql)"; then
log error "init failed"
exit 13
fi fi
} }
# error_handler_no_db_url() # error_handler_no_db_url()
error_handler_no_db_url() { error_handler_no_db_url() {
[ "${DB_URL+x}" ] || { log error "no ${WHITE}DB_URL${NC} or ${WHITE}--db-url${NC} specified"; exit 1; } [ "${DB_URL+x}" ] || { log error "no ${WHITE}DB_URL${NC} or ${WHITE}--db-url${NC} specified"; exit 3; }
} }
init_sql() { init_sql() {
log debug "inherits: ${WHITE}${INHERITS_LIST}${NC}" log debug "inherits: ${WHITE}${INHERITS_LIST}${NC}"
local create_table local sql
create_table="$(printf '%s\n' \ sql="$(printf '%s\n' \
"BEGIN;" \ "BEGIN;" \
'' \
'CREATE SCHEMA IF NOT EXISTS hectic;' \
'' \
"CREATE DOMAIN hectic.migration_name AS TEXT CHECK (VALUE ~ '^[0-9]{15}-.*$');" \ "CREATE DOMAIN hectic.migration_name AS TEXT CHECK (VALUE ~ '^[0-9]{15}-.*$');" \
'' \ '' \
"CREATE DOMAIN hectic.sha256 AS CHAR(64) CHECK (VALUE ~ '^[0-9a-f]{64}$');" \ "CREATE DOMAIN hectic.sha256 AS CHAR(64) CHECK (VALUE ~ '^[0-9a-f]{64}$');" \
@@ -101,20 +138,22 @@ init_sql() {
'END;' \ 'END;' \
'$$ LANGUAGE plpgsql;' \ '$$ LANGUAGE plpgsql;' \
'' \ '' \
'CREATE TRIGGER hectic.t_sha256_lower' \
'BEFORE INSERT OR UPDATE ON hectic.migration' \
'FOR EACH ROW EXECUTE FUNCTION sha256_lower();' \
'' \
'CREATE SCHEMA IF NOT EXISTS hectic;' \ 'CREATE SCHEMA IF NOT EXISTS hectic;' \
'CREATE TABLE IF NOT EXISTS hectic.migration (' \ 'CREATE TABLE IF NOT EXISTS hectic.migration (' \
' id SERIAL PRIMARY KEY,' \ ' id SERIAL PRIMARY KEY,' \
' name hectic.migration_name UNIQUE NOT NULL,'\ ' name hectic.migration_name UNIQUE NOT NULL,'\
' hash hectic.sha256 UNIQUE NOT NULL,'\ ' hash hectic.sha256 UNIQUE NOT NULL,'\
' applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()' \ ' applied_at TIMESTAMPTZ NOT NULL DEFAULT NOW()' \
')' \ ')')"
'COMMIT;')"
printf '%s INHERITS(%s)' "$create_table" "$INHERITS_LIST" sql="$(printf '%s INHERITS(%s);\n' "$sql" "$INHERITS_LIST")"
printf '%s\n' \
"$sql" \
'CREATE TRIGGER hectic_t_sha256_lower' \
'BEFORE INSERT OR UPDATE ON hectic.migration' \
'FOR EACH ROW EXECUTE FUNCTION hectic.sha256_lower();' \
'COMMIT;'
} }
[ "${SUBCOMMAND+x}" ] || { log error "no subcomand specified"; exit 1; } [ "${SUBCOMMAND+x}" ] || { log error "no subcomand specified"; exit 1; }
@@ -187,6 +226,7 @@ migrate_to() {
migrate() { migrate() {
local fs_migrations db_migrations db_migration fs_migration psql_args var #target_migration local fs_migrations db_migrations db_migration fs_migration psql_args var #target_migration
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
case $1 in case $1 in
up|down|to) up|down|to)
@@ -278,8 +318,8 @@ INSERT INTO hectic.migration (name) VALUES ('$escaped_name');
COMMIT; COMMIT;
SQL SQL
then then
log error "Migration failed: ${WHITE}$fs_migration${NC}" log error "migration failed: ${WHITE}$fs_migration${NC}"
return 3 exit 4
fi fi
done done
} }
@@ -296,16 +336,16 @@ create() {
;; ;;
--*|-*) --*|-*)
log error "create argument $1 does not exists" log error "create argument $1 does not exists"
exit 1 exit 9
;; ;;
*) *)
log error "create subcommand $1 does not exists" log error "create subcommand $1 does not exists"
exit 1 exit 9
;; ;;
esac esac
done done
mkdir -p "$MIGRATION_DIR" 2>/dev/null [ -d "$MIGRATION_DIR" ] || mkdir -p "$MIGRATION_DIR"
time_stamp="$(date '+%Y%m%d%H%M%S')" time_stamp="$(date '+%Y%m%d%H%M%S')"
name="${MIGRATION_NAME:-$(generate_word)}" name="${MIGRATION_NAME:-$(generate_word)}"
@@ -349,8 +389,8 @@ generate_word() {
printf '%s' "$w" printf '%s' "$w"
} }
log debug "subcommand: $SUBCOMMAND" log debug "subcommand: $WHITE$SUBCOMMAND"
log debug "subcommand args: $REMAINING_ARS" log debug "subcommand args: $WHITE$REMAINING_ARS"
eval "set -- $REMAINING_ARS" eval "set -- $REMAINING_ARS"
"$SUBCOMMAND" "$@" "$SUBCOMMAND" "$@"

View File

@@ -62,7 +62,10 @@ export DATABASE_URL
log info "run test ${WHITE}${test_name}${NC}" log info "run test ${WHITE}${test_name}${NC}"
# run test # run test
. "${test}/run.sh" mkdir './test'
cp -r "$test"/* './test/'
cd './test'
. './run.sh'
HECTIC_NAMESPACE=test-laucher HECTIC_NAMESPACE=test-laucher

View File

@@ -2,63 +2,65 @@
HECTIC_NAMESPACE=test-create-migration HECTIC_NAMESPACE=test-create-migration
log notice "case: ${WHITE}first migration" log notice "test case: ${WHITE}first migration"
if ! migrator create; then if ! migrator create; then
log error "test failed: error on migration creation" log error "test failed: ${WHITE}error on migration creation"
exit 1 exit 1
fi fi
if ! [ -d ./migration ]; then if ! [ -d ./migration ]; then
log error "test failed: migration directory not created" log error "test failed: ${WHITE}migration directory not created"
exit 1 exit 1
fi fi
if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 0 ]; then if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 0 ]; then
log error "test failed: migration not created" log error "test failed: ${WHITE}migration not created"
exit 1 exit 1
fi fi
log notice "case: ${WHITE}next migration" log notice "test case: ${WHITE}next migration"
if ! migrator create; then if ! migrator create; then
log error "test failed: error on migration creation" log error "test failed: ${WHITE}error on migration creation"
exit 1 exit 1
fi fi
if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 1 ]; then if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 1 ]; then
log error "test failed: migration not created" log error "test failed: ${WHITE}migration not created"
exit 1 exit 1
fi fi
log notice "case: ${WHITE}migration with custom name" log notice "test case: ${WHITE}migration with custom name"
if ! migrator create --name test; then if ! migrator create --name test; then
log error "test failed: error on migration creation" log error "test failed: ${WHITE}error on migration creation"
exit 1 exit 1
fi fi
if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 2 ]; then if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 2 ]; then
log error "test failed: migration not created" log error "test failed: ${WHITE}migration not created"
exit 1 exit 1
fi fi
if ! find ./migration -maxdepth 1 -type f -name '*test.sql' \ if ! find ./migration -maxdepth 1 -type f -name '*test.sql' \
| grep -Eq '/[0-9]{14}-test\.sql$'; then | grep -Eq '/[0-9]{14}-test\.sql$'; then
log eror "test failed: migration have unexpected name" log eror "test failed: ${WHITE}migration have unexpected name"
exit 1
fi fi
log notice "case: ${WHITE}migration with custom name that contains space" log notice "test case: ${WHITE}migration with custom name that contains space"
if ! migrator create --name 'test name'; then if ! migrator create --name 'test name'; then
log error "test failed: error on migration creation" log error "test failed: ${WHITE}error on migration creation"
exit 1 exit 1
fi fi
if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 3 ]; then if [ "$(find ./migration -maxdepth 1 -type f | wc -l)" -eq 3 ]; then
log error "test failed: migration not created" log error "test failed: ${WHITE}migration not created"
exit 1 exit 1
fi fi
if ! find ./migration -maxdepth 1 -type f -name '*test name.sql' \ if ! find ./migration -maxdepth 1 -type f -name '*test name.sql' \
| grep -Eq '/[0-9]{14}-test name\.sql$'; then | grep -Eq '/[0-9]{14}-test name\.sql$'; then
log eror "test failed: migration have unexpected name" log eror "test failed: ${WHITE}migration have unexpected name"
exit 1
fi fi
log notice "test passed" log notice "test passed"

View File

@@ -2,17 +2,57 @@
HECTIC_NAMESPACE=test-init-migrator HECTIC_NAMESPACE=test-init-migrator
log info "hectic.migration table inheritance" ### CASE 1
log notice "test case: ${WHITE}table inherit tables that not exists"
if ! migration_table_sql="$(migrator --inherits tablename --inherits 'table name' init --dry-run)"; then if ! migration_table_sql="$(migrator --inherits tablename --inherits 'table name' init --dry-run)"; then
log error "test failed: error on migration table init dry run" log error "test failed: ${WHITE}error on migration table init dry run"
exit 1
fi fi
printf '%s' "$migration_table_sql" | grep -Eq 'INHERITS[[:space:]]*\([[:space:]]*"tablename"[[:space:]]*,[[:space:]]*"table name"[[:space:]]*\)' || printf '%s' "$migration_table_sql" | grep -Eq 'INHERITS[[:space:]]*\([[:space:]]*"tablename"[[:space:]]*,[[:space:]]*"table name"[[:space:]]*\)' ||
{ log error "not correct migration table inherits"; exit 1; } { log error "test failed: ${WHITE}not correct migration table inherits"; exit 1; }
log info "init" ### CASE 2
if ! migrator --inherits tablename --inherits 'table name' init; then log notice "test case: ${WHITE}error: table inherit tables that not exists"
log error "test failed: error on init sql"
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 fi
printf 'SELECT * FROM hectic.migration' | psql -v ON_ERROR_STOP=1 "$DATABASE_URL" ### 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 init"
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"
fi
psql -v ON_ERROR_STOP=1 "$DATABASE_URL" -c 'SELECT * FROM hectic.migration'
log notice "test passed"

View File

@@ -2,4 +2,15 @@
HECTIC_NAMESPACE=test-migration-list HECTIC_NAMESPACE=test-migration-list
#migrator list log notice "test case: ${WHITE}getting list of local migrations"
if ! list="$(migrator list)"; then
log error "test failed: ${WHITE}error during execution"
exit 1
fi
ls
ls migration
exit 1
log notice "test passed"

View File

@@ -2,6 +2,8 @@
HECTIC_NAMESPACE=test-missing-psql HECTIC_NAMESPACE=test-missing-psql
log notice "test case: ${WHITE}error: run migrator without postgresql tools installed"
# remove psql from $PATH # remove psql from $PATH
dir=$(dirname -- "$(command -v psql)") dir=$(dirname -- "$(command -v psql)")
PATH=$(printf '%s' "$PATH" | awk -v RS=: -v ORS=: -v d="$dir" '$0!=d{print}') PATH=$(printf '%s' "$PATH" | awk -v RS=: -v ORS=: -v d="$dir" '$0!=d{print}')
@@ -18,8 +20,10 @@ set -e
log debug "migrator error code: $migrator_error_code" log debug "migrator error code: $migrator_error_code"
if [ "$migrator_error_code" -eq 127 ]; then if [ "$migrator_error_code" -eq 0 ]; then
log notice "test passed" log error "test failed: ${WHITE}no error handled"
else elif [ "$migrator_error_code" -ne 127 ]; then
log error "test failed" log error "test failed: ${WHITE}unexpected error code"
fi fi
log notice "test passed"