diff --git a/scripts/live_migration_smoke.sh b/scripts/live_migration_smoke.sh index db0235f4..36f8f188 100644 --- a/scripts/live_migration_smoke.sh +++ b/scripts/live_migration_smoke.sh @@ -3,6 +3,87 @@ set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" PYTHON_BIN="${PYTHON_BIN:-}" +LIVE_SMOKE_USE_DOCKER="${LIVE_SMOKE_USE_DOCKER:-auto}" + +run_docker_smoke() { + cd "$ROOT" + + echo "== GeoIntel live migration smoke ==" + echo "Using Docker Compose backend service." + + docker compose exec -T backend sh <<'CONTAINER_SCRIPT' +set -eu +cd /app + +echo "Database URL is read from backend container settings / DATABASE_URL." + +python - <<'PY' +from sqlalchemy import text + +from app.db.session import get_engine + +with get_engine().connect() as connection: + connection.execute(text("SELECT 1")) + print("Database connection: ok") +PY + +python -m alembic upgrade head + +python - <<'PY' +from sqlalchemy import text + +from app.db.session import get_engine + +required_objects = [ + "public.projects", + "public.areas", + "public.datasets", + "public.jobs", + "public.vector_features", + "public.quality_checks", + "public.metrics", + "public.analysis_runs", + "public.detections", + "public.segmentations", + "public.ix_vector_features_geometry", + "public.ix_detections_geometry", + "public.ix_segmentations_geometry", +] + +with get_engine().connect() as connection: + postgis_version = connection.execute(text("SELECT PostGIS_Version()")).scalar() + print(f"PostGIS version: {postgis_version}") + + missing = [ + object_name + for object_name in required_objects + if connection.execute(text("SELECT to_regclass(:object_name)"), {"object_name": object_name}).scalar() is None + ] + if missing: + raise SystemExit(f"Missing expected migrated schema objects: {', '.join(missing)}") + print("Required runtime schema objects: ok") +PY + +HEAD_COUNT="$(python -m alembic heads | grep -c 'head')" +if [ "$HEAD_COUNT" -ne 1 ]; then + echo "Expected exactly one Alembic head, found $HEAD_COUNT" >&2 + python -m alembic heads >&2 + exit 1 +fi + +python -m alembic heads +echo "== Live migration smoke passed ==" +CONTAINER_SCRIPT +} + +if [ "$LIVE_SMOKE_USE_DOCKER" != "0" ] && command -v docker >/dev/null 2>&1 && [ -f "$ROOT/docker-compose.yml" ]; then + if docker compose ps -q backend >/dev/null 2>&1 && [ -n "$(docker compose ps -q backend 2>/dev/null)" ]; then + if [ "$LIVE_SMOKE_USE_DOCKER" = "1" ] || docker compose ps --status running backend | grep -q backend; then + run_docker_smoke + exit 0 + fi + fi +fi if [ -z "$PYTHON_BIN" ]; then for candidate in python3 python.exe python; do