Files
tripz-llc/backend/scripts/verify-and-test.sh
T
Hamza-AyedandClaude Opus 4.8 f58f2e2e2c chore: gate the test loop behind a real health check
ضاعت دورتان كاملتان على السبب نفسه: تسلسل `up -d && restart && <اختبار>`
كان يشغّل الاختبار بينما الـapi ساقطة، فيظهر خطأ الإقلاع كـ`EAI_AGAIN` داخل
الاختبار — أي في المكان الخطأ تماماً، فيُشخَّص كعطل شبكة أو عطل سكربت.

`verify-and-test.sh` يجعل الدورة واحدة ومحروسة:
- يفحص `.env` قبل الإقلاع ويصلّح التعارض القاتل (OTP_DEV_MODE=true مع
  NODE_ENV=production — حارس `main.ts` ينهي العملية لا يحذّر، فتدخل الحاوية
  حلقة إعادة تشغيل).
- يميّز «حلقة إعادة تشغيل» عن «بطء إقلاع»: الأولى خطأ إقلاع يُطبع سببه من
  اللوغ فوراً بدل انتظار عقيم.
- **لا اختبار قبل ردّ /health فعلياً** — هذه هي البوابة التي كانت غائبة.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 01:11:43 +03:00

113 lines
5.2 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# دورة تحقّق واحدة: افحص البيئة → أقلِع → **انتظر الصحة فعلاً** → اختبر.
#
# سبب وجوده: تسلسل `up -d --build && restart && <اختبار>` كان يشغّل الاختبار
# بينما الـapi ساقطة، فيظهر الفشل كـ`EAI_AGAIN` في الاختبار — أي في المكان
# الخطأ تماماً. ضاعت دورتان كاملتان على تشخيص خاطئ لهذا السبب وحده.
# البوابة هنا تمنع تكراره: لا اختبار قبل ردّ /health الفعلي.
#
# التشغيل من backend/: bash scripts/verify-and-test.sh
# بلا اختبار (نشر فقط): bash scripts/verify-and-test.sh --deploy-only
# مع إعادة بناء: bash scripts/verify-and-test.sh --build
set -uo pipefail
BUILD=0
DEPLOY_ONLY=0
for arg in "$@"; do
case "$arg" in
--build) BUILD=1 ;;
--deploy-only) DEPLOY_ONLY=1 ;;
*) echo "خيار غير معروف: $arg"; exit 2 ;;
esac
done
cd "$(dirname "$0")/.." || exit 1
ENV_FILE=".env"
FAILED=0
hr() { printf '%s\n' "────────────────────────────────────────────────"; }
# ── 1) فحص البيئة قبل أي إقلاع ───────────────────────────────────────
hr; echo "1) فحص البيئة"
if [[ ! -f "$ENV_FILE" ]]; then
echo "❌ لا يوجد $ENV_FILE"; exit 1
fi
NODE_ENV_VAL=$(grep -E '^NODE_ENV=' "$ENV_FILE" | cut -d= -f2- | tr -d '"'"'"'\r ' || true)
OTP_DEV_VAL=$(grep -E '^OTP_DEV_MODE=' "$ENV_FILE" | cut -d= -f2- | tr -d '"'"'"'\r ' || true)
echo " NODE_ENV=${NODE_ENV_VAL:-<غير مضبوط>} OTP_DEV_MODE=${OTP_DEV_VAL:-<غير مضبوط>}"
# التعارض القاتل: الحارس في main.ts ينهي العملية (exit 1) لا يحذّر فقط،
# فالحاوية تدخل حلقة إعادة تشغيل ويظهر العطل لاحقاً كفشل شبكة مضلِّل.
if [[ "$NODE_ENV_VAL" == "production" && "$OTP_DEV_VAL" == "true" ]]; then
echo " ⚠️ تعارض قاتل: OTP_DEV_MODE=true مع NODE_ENV=production → الـapi لن تقلع."
echo " ↪︎ أطفئ OTP_DEV_MODE تلقائياً (الاختبار لا يحتاجه — يقرأ الرمز من Redis)."
sed -i.bak 's/^OTP_DEV_MODE=.*/OTP_DEV_MODE=false/' "$ENV_FILE"
echo " ✅ OTP_DEV_MODE=false (نسخة احتياطية: ${ENV_FILE}.bak)"
fi
if ! grep -qE '^PLATFORM_SECRET=.+' "$ENV_FILE"; then
echo " ❌ PLATFORM_SECRET غير مضبوط — نقاط السوبر-أدمن مغلقة والاختبار يحتاجها."
exit 1
fi
# ── 2) الإقلاع ───────────────────────────────────────────────────────
hr; echo "2) الإقلاع"
if [[ "$BUILD" == "1" ]]; then
echo " بناء (الاختبارات تعمل داخل مرحلة البناء وتحجب النشر عند الفشل)…"
docker compose up -d --build || { echo "❌ فشل البناء"; exit 1; }
else
docker compose up -d || { echo "❌ فشل الإقلاع"; exit 1; }
fi
# ── 3) بوابة الصحة — لا اختبار قبلها ─────────────────────────────────
hr; echo "3) انتظار /health"
HEALTH_OK=0
for i in $(seq 1 30); do
STATUS=$(docker compose ps --format '{{.Name}} {{.Status}}' | grep '^tripz-api' || true)
# الحاوية في حلقة إعادة تشغيل = خطأ إقلاع، والانتظار لن يصلحه.
if [[ "$STATUS" == *Restarting* ]]; then
echo " ❌ tripz-api في حلقة إعادة تشغيل — خطأ إقلاع، لا مشكلة شبكة."
hr; echo "سبب السقوط (آخر أخطاء):"
docker compose logs api --tail=200 2>/dev/null | grep -E 'ERROR|⛔|Error:' | tail -15
exit 1
fi
if docker run --rm --network tripz-net curlimages/curl:latest \
-fsS --max-time 3 http://tripz-api:4010/api/health >/dev/null 2>&1; then
HEALTH_OK=1
echo " ✅ الـapi تستجيب (بعد ${i} محاولة)"
break
fi
sleep 2
done
if [[ "$HEALTH_OK" != "1" ]]; then
echo " ❌ لم تستجب /health خلال 60 ثانية."
hr; docker compose ps
hr; docker compose logs api --tail=40
exit 1
fi
docker compose ps --format 'table {{.Name}}\t{{.Status}}'
if [[ "$DEPLOY_ONLY" == "1" ]]; then
hr; echo "✅ النشر سليم (بلا اختبار)."; exit 0
fi
# ── 4) اختبار التسعير ────────────────────────────────────────────────
hr; echo "4) اختبار التسعير"
SECRET=$(grep -E '^PLATFORM_SECRET=' "$ENV_FILE" | cut -d= -f2- | tr -d '"'"'"'\r ')
docker run --rm --network tripz-net \
-e BASE=http://tripz-api:4010/api \
-e PLATFORM_SECRET="$SECRET" \
-v "$(pwd)/scripts:/s" \
node:22-alpine node /s/pricing-test.mjs
FAILED=$?
hr
if [[ "$FAILED" == "0" ]]; then echo "✅ تمّت الدورة بنجاح."; else echo "❌ فشل الاختبار (رمز $FAILED)."; fi
exit $FAILED