Files
multica/scripts/worktree-db.test.sh
YYClaw e9528c722a MUL-5855: feat(dev): add worktree database cleanup (#6560)
* feat(dev): add worktree database cleanup

* fix(dev): handle database cleanup cancellation

* fix(dev): protect nested current worktree
2026-08-14 15:40:34 +08:00

199 lines
7.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
root_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' EXIT
fail() {
echo "FAIL: $*" >&2
exit 1
}
require_contains() {
local file=$1
local expected=$2
if ! grep -Fq "$expected" "$file"; then
echo "Expected output to contain: $expected" >&2
echo "Observed:" >&2
cat "$file" >&2
exit 1
fi
}
stub_dir="$tmp_dir/bin"
mkdir -p "$stub_dir"
docker_log="$tmp_dir/docker.log"
cat >"$stub_dir/docker" <<'STUB'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >>"$DOCKER_LOG"
STUB
chmod +x "$stub_dir/docker"
local_env="$tmp_dir/local.env"
cat >"$local_env" <<'EOF'
POSTGRES_DB=multica_feature_123
POSTGRES_USER=multica
DATABASE_URL=postgres://multica:multica@localhost:5432/multica_feature_123?sslmode=disable
EOF
output="$tmp_dir/output"
: >"$docker_log"
cancel_status=0
printf 'n\n' | PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/drop-database.sh" "$local_env" >"$output" 2>&1 || cancel_status=$?
if [ "$cancel_status" -ne 2 ]; then
fail "db-drop cancellation status = $cancel_status, want 2"
fi
require_contains "$output" "Drop this database permanently? [y/N] Cancelled."
if [ -s "$docker_log" ]; then
fail "db-drop invoked Docker after confirmation was declined"
fi
if ! printf 'n\n' | PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
make --no-print-directory -C "$root_dir" db-drop ENV_FILE="$local_env" >"$output" 2>&1; then
fail "make db-drop must treat an intentional cancellation as success"
fi
require_contains "$output" "Cancelled."
if grep -Fq "Error" "$output"; then
fail "make db-drop printed a Make error after cancellation"
fi
: >"$docker_log"
printf 'y\n' | PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/drop-database.sh" "$local_env" >"$output"
require_contains "$docker_log" \
"compose exec -T postgres dropdb --username multica --maintenance-db postgres --if-exists --force -- multica_feature_123"
require_contains "$output" "Dropped database 'multica_feature_123'."
remote_env="$tmp_dir/remote.env"
cat >"$remote_env" <<'EOF'
POSTGRES_DB=production
DATABASE_URL=postgres://user:password@db.example.com:5432/production
EOF
: >"$docker_log"
if printf 'y\n' | PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/drop-database.sh" "$remote_env" >"$output" 2>&1; then
fail "db-drop must refuse a remote DATABASE_URL"
fi
require_contains "$output" "DATABASE_URL points at a remote host"
if [ -s "$docker_log" ]; then
fail "db-drop invoked Docker for a remote DATABASE_URL"
fi
system_env="$tmp_dir/system.env"
cat >"$system_env" <<'EOF'
POSTGRES_DB=postgres
DATABASE_URL=postgres://multica:multica@localhost:5432/postgres
EOF
if printf 'y\n' | PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/drop-database.sh" "$system_env" >"$output" 2>&1; then
fail "db-drop must protect PostgreSQL system databases"
fi
require_contains "$output" "Refusing to drop protected PostgreSQL database"
main_env="$tmp_dir/main.env"
cat >"$main_env" <<'EOF'
POSTGRES_DB=multica
DATABASE_URL=postgres://multica:multica@localhost:5432/multica
EOF
if printf 'y\n' | PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/drop-database.sh" "$main_env" >"$output" 2>&1; then
fail "db-drop must protect the default main database"
fi
require_contains "$output" "Refusing to drop the default main database"
: >"$docker_log"
cancel_status=0
PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/drop-database.sh" "$local_env" </dev/null >"$output" 2>&1 || cancel_status=$?
if [ "$cancel_status" -ne 2 ]; then
fail "db-drop EOF cancellation status = $cancel_status, want 2"
fi
require_contains "$output" "Cancelled."
if [ -s "$docker_log" ]; then
fail "db-drop invoked Docker without affirmative confirmation"
fi
repo="$tmp_dir/repo"
worktree="$tmp_dir/worktree"
git init -q -b main "$repo"
git -C "$repo" config user.name "Worktree DB Test"
git -C "$repo" config user.email "worktree-db-test@example.com"
printf '.env.worktree\n' >"$repo/.gitignore"
printf 'base\n' >"$repo/tracked.txt"
mkdir -p "$repo/backend"
printf 'nested\n' >"$repo/backend/tracked.txt"
git -C "$repo" add .gitignore tracked.txt backend/tracked.txt
git -C "$repo" commit -qm "test: initialize fixture"
git -C "$repo" worktree add -q -b feature "$worktree"
cat >"$worktree/.env.worktree" <<'EOF'
POSTGRES_DB=multica_worktree_456
POSTGRES_USER=multica
DATABASE_URL=postgres://multica:multica@localhost:5432/multica_worktree_456?sslmode=disable
EOF
: >"$docker_log"
if printf 'y\n' | (cd "$worktree/backend" && PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/remove-worktree.sh" "$worktree") >"$output" 2>&1; then
fail "remove-worktree must refuse the current worktree from a nested directory"
fi
require_contains "$output" "Refusing to remove the current worktree from inside itself."
if [ ! -d "$worktree" ]; then
fail "remove-worktree removed the current worktree from a nested directory"
fi
if [ -s "$docker_log" ]; then
fail "remove-worktree dropped the database before rejecting the current worktree"
fi
: >"$docker_log"
if ! printf 'n\n' | (cd "$repo" && PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/remove-worktree.sh" "$worktree") >"$output" 2>&1; then
fail "remove-worktree must treat an intentional cancellation as success"
fi
if [ ! -d "$worktree" ]; then
fail "remove-worktree removed the worktree after database deletion was declined"
fi
require_contains "$output" "Worktree was not removed."
if grep -Fq "Error" "$output"; then
fail "remove-worktree printed an error after cancellation"
fi
printf 'y\n' | (cd "$repo" && PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/remove-worktree.sh" "$worktree") >"$output"
if [ -e "$worktree" ]; then
fail "remove-worktree did not remove the worktree after database deletion"
fi
require_contains "$docker_log" \
"compose exec -T postgres dropdb --username multica --maintenance-db postgres --if-exists --force -- multica_worktree_456"
dirty_worktree="$tmp_dir/dirty-worktree"
git -C "$repo" worktree add -q -b dirty-feature "$dirty_worktree"
printf 'dirty\n' >>"$dirty_worktree/tracked.txt"
: >"$docker_log"
if printf 'y\n' | (cd "$repo" && PATH="$stub_dir:$PATH" DOCKER_LOG="$docker_log" \
bash "$root_dir/scripts/remove-worktree.sh" "$dirty_worktree") >"$output" 2>&1; then
fail "remove-worktree must refuse a dirty worktree"
fi
require_contains "$output" "Refusing to remove dirty worktree"
if [ -s "$docker_log" ]; then
fail "remove-worktree dropped the database before rejecting a dirty worktree"
fi
empty_worktree="$tmp_dir/empty-worktree"
git -C "$repo" worktree add -q -b empty-feature "$empty_worktree"
(cd "$repo" && bash "$root_dir/scripts/remove-worktree.sh" "$empty_worktree") >"$output"
require_contains "$output" "No .env.worktree found; skipping database cleanup."
if [ -e "$empty_worktree" ]; then
fail "remove-worktree did not remove a worktree without an env file"
fi
if (cd "$repo" && bash "$root_dir/scripts/remove-worktree.sh" "$repo") >"$output" 2>&1; then
fail "remove-worktree must refuse the primary checkout"
fi
require_contains "$output" "Refusing to remove the primary checkout"
echo "worktree database cleanup tests passed"