348 lines
14 KiB
Bash
348 lines
14 KiB
Bash
|
|
#!/bin/bash
|
|||
|
|
|
|||
|
|
# Скрипт для тестирования baseline миграции на чистой БД
|
|||
|
|
# Создает тестовую БД, применяет baseline, и сравнивает схему с production
|
|||
|
|
|
|||
|
|
set -e
|
|||
|
|
|
|||
|
|
# Цвета для вывода
|
|||
|
|
RED='\033[0;31m'
|
|||
|
|
GREEN='\033[0;32m'
|
|||
|
|
YELLOW='\033[1;33m'
|
|||
|
|
BLUE='\033[0;34m'
|
|||
|
|
NC='\033[0m' # No Color
|
|||
|
|
|
|||
|
|
# Получаем переменные окружения
|
|||
|
|
DB_HOST=${DB_HOST:-localhost}
|
|||
|
|
DB_PORT=${DB_PORT:-5432}
|
|||
|
|
DB_USER=${DB_USER:-playeng}
|
|||
|
|
DB_PASSWORD=${DB_PASSWORD:-playeng}
|
|||
|
|
DB_NAME=${DB_NAME:-playeng}
|
|||
|
|
|
|||
|
|
TEST_DB_NAME="playeng_baseline_test_$$"
|
|||
|
|
MIGRATIONS_PATH="migrations"
|
|||
|
|
TMP_DIR=$(mktemp -d)
|
|||
|
|
|
|||
|
|
echo "=== Тестирование baseline миграции на чистой БД ==="
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Добавляем ~/go/bin в PATH если migrate не найден
|
|||
|
|
if ! command -v migrate &> /dev/null; then
|
|||
|
|
export PATH="$HOME/go/bin:$PATH"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Проверяем наличие необходимых инструментов
|
|||
|
|
if ! command -v migrate &> /dev/null; then
|
|||
|
|
echo -e "${RED}Ошибка: migrate не найден. Установите golang-migrate:${NC}"
|
|||
|
|
echo " brew install golang-migrate"
|
|||
|
|
echo " или"
|
|||
|
|
echo " go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Определяем способ выполнения PostgreSQL команд
|
|||
|
|
PG_DUMP_CMD=""
|
|||
|
|
PG_PSQL_CMD=""
|
|||
|
|
POSTGRES_CONTAINER=""
|
|||
|
|
if command -v pg_dump &> /dev/null; then
|
|||
|
|
PG_DUMP_CMD="pg_dump"
|
|||
|
|
PG_PSQL_CMD="psql"
|
|||
|
|
else
|
|||
|
|
# Пытаемся найти PostgreSQL контейнер
|
|||
|
|
if command -v docker &> /dev/null; then
|
|||
|
|
POSTGRES_CONTAINER=$(docker ps --format "{{.Names}}" 2>/dev/null | grep -iE "(postgres|db)" | head -1)
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
PG_DUMP_CMD="docker exec $POSTGRES_CONTAINER pg_dump"
|
|||
|
|
PG_PSQL_CMD="docker exec -i $POSTGRES_CONTAINER psql"
|
|||
|
|
echo -e "${BLUE}Используется PostgreSQL из Docker контейнера: $POSTGRES_CONTAINER${NC}"
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
HAS_PG_DUMP=false
|
|||
|
|
if [ -n "$PG_DUMP_CMD" ]; then
|
|||
|
|
HAS_PG_DUMP=true
|
|||
|
|
else
|
|||
|
|
echo -e "${YELLOW}Предупреждение: pg_dump не найден. Сравнение схем будет пропущено.${NC}"
|
|||
|
|
echo " Для полного тестирования установите PostgreSQL client tools"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Проверяем наличие директории миграций
|
|||
|
|
if [ ! -d "$MIGRATIONS_PATH" ]; then
|
|||
|
|
echo -e "${RED}Ошибка: Директория миграций не найдена: $MIGRATIONS_PATH${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
# Проверяем наличие baseline миграции
|
|||
|
|
if [ ! -f "$MIGRATIONS_PATH/000001_baseline.up.sql" ]; then
|
|||
|
|
echo -e "${RED}Ошибка: Baseline миграция не найдена: $MIGRATIONS_PATH/000001_baseline.up.sql${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo "Параметры подключения:"
|
|||
|
|
echo " Host: $DB_HOST"
|
|||
|
|
echo " Port: $DB_PORT"
|
|||
|
|
echo " User: $DB_USER"
|
|||
|
|
echo " Test DB: $TEST_DB_NAME"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Проверяем подключение к БД
|
|||
|
|
echo "1. Проверка подключения к БД..."
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
# Используем Docker
|
|||
|
|
echo "SELECT 1;" | $PG_PSQL_CMD -U $DB_USER -d postgres > /dev/null 2>&1
|
|||
|
|
elif [ -n "$PG_PSQL_CMD" ]; then
|
|||
|
|
# Используем локальный psql
|
|||
|
|
PGPASSWORD=$DB_PASSWORD $PG_PSQL_CMD \
|
|||
|
|
-h $DB_HOST \
|
|||
|
|
-p $DB_PORT \
|
|||
|
|
-U $DB_USER \
|
|||
|
|
-d postgres \
|
|||
|
|
-c "SELECT 1;" > /dev/null 2>&1
|
|||
|
|
else
|
|||
|
|
# Пытаемся через стандартный psql
|
|||
|
|
PGPASSWORD=$DB_PASSWORD psql \
|
|||
|
|
-h $DB_HOST \
|
|||
|
|
-p $DB_PORT \
|
|||
|
|
-U $DB_USER \
|
|||
|
|
-d postgres \
|
|||
|
|
-c "SELECT 1;" > /dev/null 2>&1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if [ $? -ne 0 ]; then
|
|||
|
|
echo -e "${RED}Ошибка: Не удалось подключиться к БД${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo -e "${GREEN}✓ Подключение успешно${NC}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Создаем тестовую БД
|
|||
|
|
echo "2. Создание тестовой БД..."
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
echo "CREATE DATABASE $TEST_DB_NAME;" | $PG_PSQL_CMD -U $DB_USER -d postgres > /dev/null 2>&1
|
|||
|
|
elif [ -n "$PG_PSQL_CMD" ]; then
|
|||
|
|
PGPASSWORD=$DB_PASSWORD $PG_PSQL_CMD \
|
|||
|
|
-h $DB_HOST \
|
|||
|
|
-p $DB_PORT \
|
|||
|
|
-U $DB_USER \
|
|||
|
|
-d postgres \
|
|||
|
|
-c "CREATE DATABASE $TEST_DB_NAME;" > /dev/null 2>&1
|
|||
|
|
else
|
|||
|
|
PGPASSWORD=$DB_PASSWORD psql \
|
|||
|
|
-h $DB_HOST \
|
|||
|
|
-p $DB_PORT \
|
|||
|
|
-U $DB_USER \
|
|||
|
|
-d postgres \
|
|||
|
|
-c "CREATE DATABASE $TEST_DB_NAME;" > /dev/null 2>&1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if [ $? -ne 0 ]; then
|
|||
|
|
echo -e "${RED}Ошибка: Не удалось создать тестовую БД${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo -e "${GREEN}✓ Тестовая БД создана: $TEST_DB_NAME${NC}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Ждем немного, чтобы БД точно создалась
|
|||
|
|
sleep 1
|
|||
|
|
|
|||
|
|
# Проверяем, что БД создана
|
|||
|
|
echo "3. Проверка существования тестовой БД..."
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
if echo "SELECT 1 FROM pg_database WHERE datname='$TEST_DB_NAME';" | $PG_PSQL_CMD -U $DB_USER -d postgres -t | grep -q 1; then
|
|||
|
|
echo -e "${GREEN}✓ БД подтверждена${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e "${RED}Ошибка: БД не найдена после создания${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Применяем baseline миграцию
|
|||
|
|
echo "4. Применение baseline миграции..."
|
|||
|
|
cd "$(dirname "$0")" || exit 1
|
|||
|
|
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
# Для Docker контейнеров используем psql напрямую, так как migrate может иметь проблемы с подключением
|
|||
|
|
echo -e "${BLUE}Применение миграции через psql (Docker)...${NC}"
|
|||
|
|
if [ -f "$MIGRATIONS_PATH/000001_baseline.up.sql" ]; then
|
|||
|
|
if cat "$MIGRATIONS_PATH/000001_baseline.up.sql" | $PG_PSQL_CMD -U $DB_USER -d $TEST_DB_NAME > /dev/null 2>&1; then
|
|||
|
|
echo -e "${GREEN}✓ Миграция применена через psql${NC}"
|
|||
|
|
# Создаем таблицу schema_migrations вручную для migrate
|
|||
|
|
echo "CREATE TABLE IF NOT EXISTS schema_migrations (version bigint NOT NULL PRIMARY KEY, dirty boolean NOT NULL);" | $PG_PSQL_CMD -U $DB_USER -d $TEST_DB_NAME > /dev/null 2>&1
|
|||
|
|
echo "INSERT INTO schema_migrations (version, dirty) VALUES (1, false) ON CONFLICT (version) DO UPDATE SET dirty = false;" | $PG_PSQL_CMD -U $DB_USER -d $TEST_DB_NAME > /dev/null 2>&1
|
|||
|
|
MIGRATE_SUCCESS=false # Устанавливаем в false, чтобы использовать psql для проверки версии
|
|||
|
|
else
|
|||
|
|
echo -e "${RED}Ошибка: Не удалось применить миграцию через psql${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
echo -e "${RED}Ошибка: Файл миграции не найден${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
DATABASE_URL="postgres://$DB_USER:$DB_PASSWORD@localhost:$DB_PORT/$TEST_DB_NAME?sslmode=disable"
|
|||
|
|
else
|
|||
|
|
DATABASE_URL="postgres://$DB_USER:$DB_PASSWORD@$DB_HOST:$DB_PORT/$TEST_DB_NAME?sslmode=disable"
|
|||
|
|
if ! migrate -path "$MIGRATIONS_PATH" -database "$DATABASE_URL" up; then
|
|||
|
|
echo -e "${RED}Ошибка: Не удалось применить baseline миграцию${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo -e "${GREEN}✓ Baseline миграция применена${NC}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Проверяем версию миграции
|
|||
|
|
echo "5. Проверка версии миграции..."
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ] && [ "${MIGRATE_SUCCESS:-false}" = "false" ]; then
|
|||
|
|
# Проверяем версию через psql
|
|||
|
|
VERSION=$(echo "SELECT version FROM schema_migrations;" | $PG_PSQL_CMD -U $DB_USER -d $TEST_DB_NAME -t 2>/dev/null | tr -d ' ' | head -1)
|
|||
|
|
if [ -n "$VERSION" ] && [ "$VERSION" != "" ]; then
|
|||
|
|
echo " Версия: $VERSION"
|
|||
|
|
if [ "$VERSION" = "1" ]; then
|
|||
|
|
echo -e "${GREEN}✓ Версия миграции корректна${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e "${YELLOW}⚠ Неожиданная версия миграции: $VERSION${NC}"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
echo -e "${YELLOW}⚠ Не удалось определить версию миграции${NC}"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
# Используем migrate для проверки версии
|
|||
|
|
VERSION=$(migrate -path "$MIGRATIONS_PATH" -database "$DATABASE_URL" version 2>&1)
|
|||
|
|
echo " Версия: $VERSION"
|
|||
|
|
|
|||
|
|
if echo "$VERSION" | grep -qE "^1"; then
|
|||
|
|
echo -e "${GREEN}✓ Версия миграции корректна${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e "${YELLOW}⚠ Неожиданная версия миграции${NC}"
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Экспортируем схему из тестовой БД (если pg_dump доступен)
|
|||
|
|
if [ "$HAS_PG_DUMP" = true ]; then
|
|||
|
|
echo "6. Экспорт схемы из тестовой БД..."
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
$PG_DUMP_CMD -U $DB_USER -d $TEST_DB_NAME --schema-only --no-owner --no-privileges > "$TMP_DIR/baseline_schema.sql"
|
|||
|
|
else
|
|||
|
|
PGPASSWORD=$DB_PASSWORD $PG_DUMP_CMD \
|
|||
|
|
-h $DB_HOST \
|
|||
|
|
-p $DB_PORT \
|
|||
|
|
-U $DB_USER \
|
|||
|
|
-d $TEST_DB_NAME \
|
|||
|
|
--schema-only \
|
|||
|
|
--no-owner \
|
|||
|
|
--no-privileges \
|
|||
|
|
-f "$TMP_DIR/baseline_schema.sql"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if [ $? -ne 0 ]; then
|
|||
|
|
echo -e "${RED}Ошибка: Не удалось экспортировать схему${NC}"
|
|||
|
|
exit 1
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo -e "${GREEN}✓ Схема экспортирована${NC}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Пытаемся экспортировать схему из production БД для сравнения
|
|||
|
|
echo "7. Экспорт схемы из production БД для сравнения..."
|
|||
|
|
if [ -n "$POSTGRES_CONTAINER" ]; then
|
|||
|
|
if $PG_DUMP_CMD -U $DB_USER -d $DB_NAME --schema-only --no-owner --no-privileges > "$TMP_DIR/production_schema.sql" 2>/dev/null; then
|
|||
|
|
PROD_EXPORT_SUCCESS=true
|
|||
|
|
else
|
|||
|
|
PROD_EXPORT_SUCCESS=false
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
if PGPASSWORD=$DB_PASSWORD $PG_DUMP_CMD \
|
|||
|
|
-h $DB_HOST \
|
|||
|
|
-p $DB_PORT \
|
|||
|
|
-U $DB_USER \
|
|||
|
|
-d $DB_NAME \
|
|||
|
|
--schema-only \
|
|||
|
|
--no-owner \
|
|||
|
|
--no-privileges \
|
|||
|
|
-f "$TMP_DIR/production_schema.sql" 2>/dev/null; then
|
|||
|
|
PROD_EXPORT_SUCCESS=true
|
|||
|
|
else
|
|||
|
|
PROD_EXPORT_SUCCESS=false
|
|||
|
|
fi
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
if [ "$PROD_EXPORT_SUCCESS" = true ]; then
|
|||
|
|
|
|||
|
|
echo -e "${GREEN}✓ Схема production экспортирована${NC}"
|
|||
|
|
echo ""
|
|||
|
|
|
|||
|
|
# Сравниваем схемы
|
|||
|
|
echo "8. Сравнение схем..."
|
|||
|
|
|
|||
|
|
# Подсчитываем объекты
|
|||
|
|
echo -e "${BLUE}Таблицы:${NC}"
|
|||
|
|
BASELINE_TABLES=$(grep -c "CREATE TABLE" "$TMP_DIR/baseline_schema.sql" || echo "0")
|
|||
|
|
PROD_TABLES=$(grep -c "CREATE TABLE" "$TMP_DIR/production_schema.sql" || echo "0")
|
|||
|
|
echo " Baseline: $BASELINE_TABLES"
|
|||
|
|
echo " Production: $PROD_TABLES"
|
|||
|
|
|
|||
|
|
if [ "$BASELINE_TABLES" -eq "$PROD_TABLES" ]; then
|
|||
|
|
echo -e " ${GREEN}✓ Количество таблиц совпадает${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e " ${YELLOW}⚠ Количество таблиц не совпадает${NC}"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo -e "${BLUE}Индексы:${NC}"
|
|||
|
|
BASELINE_INDEXES=$(grep -c "CREATE.*INDEX" "$TMP_DIR/baseline_schema.sql" || echo "0")
|
|||
|
|
PROD_INDEXES=$(grep -c "CREATE.*INDEX" "$TMP_DIR/production_schema.sql" || echo "0")
|
|||
|
|
echo " Baseline: $BASELINE_INDEXES"
|
|||
|
|
echo " Production: $PROD_INDEXES"
|
|||
|
|
|
|||
|
|
if [ "$BASELINE_INDEXES" -eq "$PROD_INDEXES" ]; then
|
|||
|
|
echo -e " ${GREEN}✓ Количество индексов совпадает${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e " ${YELLOW}⚠ Количество индексов не совпадает${NC}"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo -e "${BLUE}Materialized Views:${NC}"
|
|||
|
|
BASELINE_MV=$(grep -c "CREATE MATERIALIZED VIEW" "$TMP_DIR/baseline_schema.sql" || echo "0")
|
|||
|
|
PROD_MV=$(grep -c "CREATE MATERIALIZED VIEW" "$TMP_DIR/production_schema.sql" || echo "0")
|
|||
|
|
echo " Baseline: $BASELINE_MV"
|
|||
|
|
echo " Production: $PROD_MV"
|
|||
|
|
|
|||
|
|
if [ "$BASELINE_MV" -eq "$PROD_MV" ]; then
|
|||
|
|
echo -e " ${GREEN}✓ Количество materialized views совпадает${NC}"
|
|||
|
|
else
|
|||
|
|
echo -e " ${YELLOW}⚠ Количество materialized views не совпадает${NC}"
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo "Для детального сравнения выполните:"
|
|||
|
|
echo " diff $TMP_DIR/baseline_schema.sql $TMP_DIR/production_schema.sql"
|
|||
|
|
echo ""
|
|||
|
|
echo "Или используйте:"
|
|||
|
|
echo " diff -u $TMP_DIR/baseline_schema.sql $TMP_DIR/production_schema.sql | less"
|
|||
|
|
|
|||
|
|
else
|
|||
|
|
echo -e "${YELLOW}⚠ Не удалось экспортировать схему production БД${NC}"
|
|||
|
|
echo " Продолжаем без сравнения"
|
|||
|
|
echo ""
|
|||
|
|
echo "Схема baseline сохранена в: $TMP_DIR/baseline_schema.sql"
|
|||
|
|
fi
|
|||
|
|
else
|
|||
|
|
echo "6. Пропуск экспорта схемы (pg_dump недоступен)"
|
|||
|
|
echo ""
|
|||
|
|
echo -e "${YELLOW}Для полного тестирования установите PostgreSQL client tools:${NC}"
|
|||
|
|
echo " macOS: brew install postgresql"
|
|||
|
|
echo " или используйте Docker контейнер с PostgreSQL"
|
|||
|
|
echo ""
|
|||
|
|
fi
|
|||
|
|
|
|||
|
|
echo ""
|
|||
|
|
echo "=== Тестирование завершено ==="
|
|||
|
|
echo ""
|
|||
|
|
echo -e "${GREEN}✓ Baseline миграция успешно применена к чистой БД${NC}"
|
|||
|
|
echo ""
|