#!/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) إبطال كاش التعرفة ───────────────────────────────────────────── # `getActive` تكاشي في Redis 900 ثانية، و**Redis حاوية منفصلة لا تتأثر # بإعادة تشغيل الـapi**. تطبيق `tariffs.sql` مباشرةً على القاعدة يتجاوز # التطبيق فلا يُبطل شيئاً — فبقي النظام يخدم أسعاراً قديمة عبر دورتَي نشر # كاملتين وهو يعلن النجاح. المسح هنا يجعل الطزاجة مضمونة بالبناء لا # بالتذكّر. hr; echo "4) إبطال كاش التعرفة" KEYS=$(docker compose exec -T redis redis-cli -n "${REDIS_DB:-3}" --scan --pattern 'tripz:tariff:*' 2>/dev/null | tr -d '\r') if [[ -n "$KEYS" ]]; then COUNT=$(printf '%s\n' "$KEYS" | grep -c . || true) printf '%s\n' "$KEYS" | xargs -r docker compose exec -T redis redis-cli -n "${REDIS_DB:-3}" DEL >/dev/null echo " ✅ مُسح $COUNT مفتاح تعرفة" else echo " ℹ️ لا مفاتيح تعرفة مكاشية" fi # ── 5) اختبار التسعير ──────────────────────────────────────────────── hr; echo "5) اختبار التسعير" 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