Files
LMS/scripts/ldd-browser.sh
Vladislav Kopnin f3d614bb33 ci: изолировать пайплайны на отдельной VM
- Woodpecker workflows требуют агент с меткой isolation=dedicated-vm
- шаги выполняются в lms-ci:1 с nested dockerd, без хост-Docker сокета
- ci/Dockerfile: прогретый immutable-образ (Java, Python, Node, Gradle-кэш)
- ci-dind.sh поднимает dockerd внутри privileged-шага; ci-build-image.sh собирает образ
- deploy/WOODPECKER.md: отдельная VM, firewall, отсутствие production-секретов,
  trusted repo, чек-лист безопасности
2026-10-29 12:01:44 +03:00

174 lines
6.4 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# LDD browser E2E: полный стек + Playwright (Chromium/Firefox/WebKit) на одноразовой БД.
set -euo pipefail
cd "$(dirname "$0")/.."
DB="lms_e2e_$(date -u +%H%M%S)_$$"
POSTGRES_WAS_RUNNING=0
STACK_STARTED=0
E2E_STATUS=1
log() { echo ">> $*"; }
playwright_version() {
(cd e2e && node -p "require('@playwright/test/package.json').version" 2>/dev/null || true)
}
host_playwright_usable() {
# WebKit на Fedora часто не запускается из-за Ubuntu-специфичных libicu/libjpeg;
# проверяем все три браузера, чтобы fallback сработал и при нехватке lib для Firefox.
(cd e2e && node -e '
const { chromium, firefox, webkit } = require("playwright");
(async () => {
for (const type of [chromium, firefox, webkit]) {
const browser = await type.launch();
await browser.close();
}
})().catch(() => process.exit(1));
') >/dev/null 2>&1
}
ensure_playwright_browsers() {
local browser detected missing=()
# Проверяем точные пути браузеров текущей версии Playwright, а не кэш целиком.
if ! detected=$(cd e2e && node -e '
const fs = require("fs");
const { chromium, firefox, webkit } = require("playwright");
for (const [name, type] of [["chromium", chromium], ["firefox", firefox], ["webkit", webkit]]) {
if (!fs.existsSync(type.executablePath())) console.log(name);
}
' 2>/dev/null); then
detected=$'chromium\nfirefox\nwebkit'
fi
while IFS= read -r browser; do
[[ -n "$browser" ]] && missing+=("$browser")
done <<<"$detected"
if ((${#missing[@]} == 0)); then
log "Браузеры Playwright уже установлены (Chromium/Firefox/WebKit)."
return
fi
log "Устанавливаю браузеры Playwright: ${missing[*]}; системные зависимости ставит CI."
(cd e2e && npx playwright install --no-progress "${missing[@]}")
}
cleanup() {
local code=$?
if ((STACK_STARTED)); then
log "Останавливаю тестовый стек..."
./run.sh stop >/dev/null 2>&1 || true
fi
docker exec -i lms-postgres psql -U lms -d postgres -v ON_ERROR_STOP=1 \
-c "DROP DATABASE IF EXISTS $DB;" >/dev/null 2>&1 || true
if ((POSTGRES_WAS_RUNNING == 0)); then
docker compose stop postgres >/dev/null 2>&1 || true
fi
exit $code
}
trap cleanup EXIT INT TERM
for port in 8080 8081 8082 8083 8090; do
if ss -ltn 2>/dev/null | grep -q ":$port "; then
echo "Порт $port занят. Остановите текущий стек (./run.sh stop) и повторите." >&2
exit 1
fi
done
command -v docker >/dev/null 2>&1 || { echo "Нужен docker" >&2; exit 1; }
command -v npx >/dev/null 2>&1 || { echo "Нужен Node.js/npx" >&2; exit 1; }
JAVA_BIN="${JAVA_BIN:-$(command -v java || true)}"
[[ -x "$JAVA_BIN" ]] || { echo "Не найден Java 21: $JAVA_BIN" >&2; exit 1; }
[[ -d e2e/node_modules ]] || { echo "Выполните: cd e2e && npm install" >&2; exit 1; }
if docker compose ps --status running --services 2>/dev/null | grep -qx postgres; then
POSTGRES_WAS_RUNNING=1
fi
log "Запускаю PostgreSQL..."
docker compose up -d postgres >/dev/null
for _ in $(seq 1 40); do
docker exec lms-postgres pg_isready -U lms -d postgres >/dev/null 2>&1 && break
sleep 1
done
docker exec lms-postgres pg_isready -U lms -d postgres >/dev/null
docker exec -i lms-postgres psql -U lms -d postgres -v ON_ERROR_STOP=1 \
-c "CREATE DATABASE $DB;" >/dev/null
log "Собираю bootJar..."
./gradlew bootJar --console=plain >/tmp/lms-ldd-e2e-bootjar.log
log "Запускаю стек..."
export LMS_DB_URL="jdbc:postgresql://localhost:5432/$DB"
export LMS_DB_NAME="$DB"
export LMS_DB_USER="lms"
export LMS_DB_PASSWORD="lms"
export LMS_INTERNAL_TOKEN="ldd-internal-token"
export LMS_SESSION_COOKIE_SECURE="false"
export JAVA_BIN
STACK_STARTED=1
./run.sh start
mkdir -p build/evidence
ensure_playwright_browsers
set +e
if host_playwright_usable; then
log "Запускаю Playwright в текущем окружении (Chromium/Firefox/WebKit)..."
(
cd e2e
LDD_WEB_URL="http://localhost:8090" \
LDD_API_URL="http://localhost:8080" \
npx playwright test --config=playwright.config.ts
)
E2E_STATUS=$?
else
version=$(playwright_version)
if [[ -z "$version" ]]; then
echo "WebKit не запускается в текущем окружении, а версию Playwright определить не удалось." >&2
E2E_STATUS=1
else
log "WebKit не запускается в текущем окружении; запускаю Chromium/Firefox/WebKit в Docker-образе Playwright ${version}."
docker run --rm --network host \
-v "$PWD:/work" \
-w /work/e2e \
-e LDD_WEB_URL="http://localhost:8090" \
-e LDD_API_URL="http://localhost:8080" \
"mcr.microsoft.com/playwright:v${version}-noble" \
npx playwright test --config=playwright.config.ts
E2E_STATUS=$?
fi
fi
set -e
python3 - "$E2E_STATUS" <<'PY'
import json
import os
import sys
status_code = int(sys.argv[1])
playwright_path = "build/evidence/playwright.json"
detail = "Playwright exit=" + str(status_code)
if os.path.isfile(playwright_path):
try:
root = json.load(open(playwright_path, encoding="utf-8"))
stats = root.get("stats", {})
detail += (
f"; expected={stats.get('expected', 0)}"
f", unexpected={stats.get('unexpected', 0)}"
f", flaky={stats.get('flaky', 0)}"
f", skipped={stats.get('skipped', 0)}"
)
except Exception as exc:
detail += "; не удалось разобрать playwright.json: " + str(exc)
status = "passed" if status_code == 0 else "failed"
with open("build/evidence/browser.json", "w", encoding="utf-8") as fh:
now = __import__("datetime").datetime.now(__import__("datetime").UTC).isoformat()
json.dump(
{"generatedAt": now, "checks": [{"id": "browser.e2e", "status": status, "detail": detail}]},
fh,
ensure_ascii=False,
indent=2,
)
print(("PASS " if status == "passed" else "FAIL ") + "browser.e2e: " + detail)
sys.exit(0 if status == "passed" else 1)
PY