#!/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 ""