From 9d67bbd8ae6156206977295f51e9a3e2f025c7ab Mon Sep 17 00:00:00 2001 From: alexm Date: Thu, 20 Feb 2025 09:17:54 +0100 Subject: [PATCH] feat: refs #6695 run parallel e2e in local --- test/cypress/docker/run/cleanup.sh | 17 ++- test/cypress/docker/run/main.sh | 45 ++++-- test/cypress/docker/run/run_group.sh | 129 +++++------------- test/cypress/docker/run/setup.sh | 7 +- test/cypress/docker/run/wait_for_api_ready.sh | 29 ++++ 5 files changed, 114 insertions(+), 113 deletions(-) create mode 100644 test/cypress/docker/run/wait_for_api_ready.sh diff --git a/test/cypress/docker/run/cleanup.sh b/test/cypress/docker/run/cleanup.sh index db0c897f1..09ff19c58 100644 --- a/test/cypress/docker/run/cleanup.sh +++ b/test/cypress/docker/run/cleanup.sh @@ -5,20 +5,19 @@ cleanup() { # Detener todos los procesos en paralelo kill "${pids[@]}" 2>/dev/null + for pid in "${pids[@]}"; do + if kill -0 "$pid" 2>/dev/null; then + echo "→ ⏹️ Matando proceso $pid" + kill "$pid" + fi + done # Buscar y eliminar contenedores que comiencen con NETWORK containers=$(docker ps -aq --filter "name=^${NETWORK}") if [[ -n "$containers" ]]; then # echo "🧹 Eliminando contenedores: $containers" docker rm -fv $containers >/dev/null 2>&1 || true - echo "✅ → ⏹🧹 Detenido y eliminado contenedores correctamente" - fi - - # Buscar y eliminar redes que comiencen con NETWORK - networks=$(docker network ls --format '{{.Name}}' | grep "^${NETWORK}" || true) - if [[ -n "$networks" ]]; then - # echo "🧹 Eliminando redes: $networks" - docker network rm $networks >/dev/null 2>&1 || true - echo "✅ → 🧹 Redes eliminadas correctamente" + echo "⏹ Detenido y eliminado contenedores correctamente" fi + exit 0 } diff --git a/test/cypress/docker/run/main.sh b/test/cypress/docker/run/main.sh index 4fdb06a4c..6cbd3c5a9 100644 --- a/test/cypress/docker/run/main.sh +++ b/test/cypress/docker/run/main.sh @@ -5,28 +5,53 @@ source "$(dirname "$0")/cleanup.sh" source "$(dirname "$0")/setup.sh" source "$(dirname "$0")/run_group.sh" source "$(dirname "$0")/summary.sh" +source "$(dirname "$0")/wait_for_api_ready.sh" # Manejo de señales para limpiar si se interrumpe el script trap cleanup SIGINT -# docker-compose -p lilium-e2e -f docker-compose.e2e.local.yml build cypress-setup >/dev/null 2>&1 + +# Docker setup echo "💿 Construyendo CypressSetup" docker build -t cypress-setup:latest -f ./test/cypress/Dockerfile . >/dev/null 2>&1 -echo "💿 Descargando imagenes actualizadas" +echo "💿 Descargando imágenes actualizadas" docker-compose -f docker-compose.e2e.yml pull back front vn-database -echo "📀 Actualizadas" +echo "💿 Levantando los contenedores" +docker-compose -p lilium-e2e -f docker-compose.e2e.yml up -d >/dev/null 2>&1 -# Ejecutar grupos en paralelo y almacenar PIDs -for i in "${!groups[@]}"; do - run_group "${groups[$i]}" "$((i+1))" & # Ejecutar en segundo plano - pids+=($!) # Guardar el PID del proceso +wait_for_api_ready "Aplicación" "front" 9000 "/api/Applications/status" "lilium-e2e_default" +echo "📀 Lanzando E2E" + +# Lista global de PIDs +declare -A running + +# Índice de ejecución de carpetas +INDEX_FILE="/tmp/index_file" +index=$((numParallelGroups - 1)) +echo $index > "$INDEX_FILE" + +# 🔹 Lanzar los primeros `numParallelGroups` procesos +for ((i = 0; i < numParallelGroups && i < ${#folders[@]}; i++)); do + run_group "${folders[$i]}" $i & done -# Esperar a que terminen todos los procesos en segundo plano -wait "${pids[@]}" +# 🔹 Esperar a que todos los procesos terminen +while [[ $((index + 2)) -lt ${#folders[@]} ]] || [[ $(docker ps --filter "ancestor=cypress-setup" --format "{{.ID}}" | wc -l) -gt 0 ]]; do + # Actualizar index desde el archivo compartido + next_index=$(cat "$INDEX_FILE") + index=$next_index + + # Mostrar los contenedores en ejecución si hay alguno con imagen "cypress-setup" + if [[ $(docker ps --filter "ancestor=cypress-setup" --format "{{.ID}}" | wc -l) -gt 0 ]]; then + docker ps --filter "ancestor=cypress-setup" --format " 🔹 ID: {{.ID}} | Nombre: {{.Names}}" + fi + + sleep 1 # Pausa antes de volver a comprobar +done + +docker-compose -p lilium-e2e -f docker-compose.e2e.yml down # Generar el resumen final generate_summary # Limpiar contenedores al finalizar cleanup -exit 0 diff --git a/test/cypress/docker/run/run_group.sh b/test/cypress/docker/run/run_group.sh index e3a202987..9afc74ef1 100644 --- a/test/cypress/docker/run/run_group.sh +++ b/test/cypress/docker/run/run_group.sh @@ -1,103 +1,48 @@ #!/bin/bash # Función para esperar a que un servicio devuelva un JSON con `{ "status": true }` en la red de Docker -wait_for_api_ready() { - local service_name="$1" - local container_name="$2" - local port="$3" - local path="$4" - local network="${5,,}" - local max_retries=30 # Máximo de intentos (30 segundos) - local retries=0 - local url="http://$container_name:$port$path" - - # echo "⏳ Esperando a que $service_name devuelva exactamente 'true' en $url..." - - while [[ $retries -lt $max_retries ]]; do - response=$(docker run --rm --network="$network" curlimages/curl -s "$url" || echo "error") - - # echo "🔍 Respuesta recibida de $service_name: '$response'" - - if [[ "$response" == "true" ]]; then - # echo "✅ Conectado al servicio $service_name → $url!" - return 0 - fi - - sleep 1 - ((retries++)) - done - - echo "❌ ERROR: $service_name no respondió con 'true' en $url después de $max_retries intentos." - exit 1 -} run_group() { - local group="$1" - local parallelIndex="$2" - local groupIndex=1 + local testFolder=$1 + local parallelIndex=$2 + local folderName=$(basename "$testFolder" | tr -cd 'a-zA-Z0-9_-') + local uniqueName=lilium-e2e + echo "🔹 Lanzado - $folderName (Grupo: $parallelIndex)" - echo "=== Ejecutando grupo paralelo ${parallelIndex} ===" + # 🚀 Ejecutar Cypress en modo detach y capturar el container ID + containerId=$(docker run -d --name ${uniqueName}_${folderName}_cypress \ + --network ${uniqueName}_default \ + -e TZ=Europe/Madrid \ + -e DOCKER=true \ + -v "$(pwd)":/app \ + -w /app \ + cypress-setup \ + pnpm exec cypress run --browser chromium --spec test/cypress/integration/${folderName}/**/*.spec.js) - for testFolder in $group; do - folderName=$(basename "$testFolder" | tr -cd 'a-zA-Z0-9_-') - uniqueName="${NETWORK}_${folderName}_${parallelIndex}_${groupIndex}" - - echo "🔹 $folderName (Grupo: $parallelIndex, Índice: $groupIndex) - Levantado" - - export CYPRESS_SPEC="test/cypress/integration/${folderName}/**/*.spec.js" - - # Iniciar servicios del backend y frontend - docker-compose -p "$uniqueName" -f docker-compose.e2e.local.yml up -d back >/dev/null 2>&1 - docker-compose -p "$uniqueName" -f docker-compose.e2e.local.yml up -d front >/dev/null 2>&1 - - # 🔹 Esperar a que la API en /api/Applications/status devuelva { "status": true } - wait_for_api_ready "Aplicación" "front" 9000 "/api/Applications/status" "${uniqueName}_default" - echo "🌐 $folderName (Grupo: $parallelIndex, Índice: $groupIndex) - Conectado" - - # 🚀 Ejecutar pruebas en modo detach - docker-compose -p "$uniqueName" -f docker-compose.e2e.local.yml up -d e2e >/dev/null 2>&1 - - # 🔹 Esperar hasta que el contenedor de Cypress finalice - container_id="" - max_retries=10 - retries=0 - while [[ -z "$container_id" && $retries -lt $max_retries ]]; do - sleep 2 - container_id=$(docker-compose -p "$uniqueName" -f docker-compose.e2e.local.yml ps -q e2e) - ((retries++)) - done - - if [[ -z "$container_id" ]]; then - echo "⚠️ No se pudo obtener el contenedor para ${folderName} después de $max_retries intentos" - failedTests+=("$folderName") - continue + # 🔹 Esperar activamente a que el contenedor finalice + while true; do + container_status=$(docker inspect -f '{{.State.Running}}' "$containerId" 2>/dev/null || echo "false") + if [[ "$container_status" == "false" ]]; then + break fi - - # echo "📦 Contenedor $container_id encontrado. Esperando a que finalice..." - - # 🔹 Esperar activamente a que el contenedor finalice - while true; do - container_status=$(docker inspect -f '{{.State.Running}}' "$container_id" 2>/dev/null || echo "false") - if [[ "$container_status" == "false" ]]; then - break - fi - sleep 2 - done - - # Verificar el código de salida - exit_code=$(docker inspect -f '{{.State.ExitCode}}' "$container_id" 2>/dev/null || echo "1") - - if [[ "$exit_code" -ne 0 ]]; then - echo "❌ Error en la ejecución de ${folderName} (Exit Code: $exit_code)" - buildResult="UNSTABLE" - docker logs "$container_id" > "test/cypress/docker/logs/${uniqueName}.log" 2>/dev/null || true - failedTests+=("$folderName") - fi - - # Limpiar contenedores - docker-compose -p "$uniqueName" -f docker-compose.e2e.local.yml down >/dev/null 2>&1 || true - - ((groupIndex++)) + sleep 1 done + + # Verificar el código de salida + exit_code=$(docker inspect -f '{{.State.ExitCode}}' "$containerId" 2>/dev/null || echo "1") + + if [[ "$exit_code" -ne 0 ]]; then + # echo "❌ Error en la ejecución de ${folderName} (Exit Code: $exit_code)" + docker logs "$containerId" > "test/cypress/docker/logs/${uniqueName}_${folderName}_log" 2>/dev/null || true + fi + docker rm -f ${uniqueName}_${folderName}_cypress >/dev/null 2>&1 || true + + next_index=$(cat "$INDEX_FILE") + next_index=$((next_index + 1)) + echo "$next_index" > "$INDEX_FILE" + + if [[ $next_index -lt ${#folders[@]} ]]; then + run_group "${folders[$next_index]}" $parallelIndex & + fi } diff --git a/test/cypress/docker/run/setup.sh b/test/cypress/docker/run/setup.sh index 4841e0b67..0135c3f84 100644 --- a/test/cypress/docker/run/setup.sh +++ b/test/cypress/docker/run/setup.sh @@ -4,15 +4,18 @@ numParallelGroups=${1:-4} NETWORK="lilium-e2e" pids=() # Para almacenar los procesos en paralelo -failedTests=() # Para almacenar las carpetas que fallaron # Limpiar la carpeta de logs antes de cada ejecución LOG_DIR="test/cypress/docker/logs" +SCREEN_SHOTS_DIR="test/cypress/screenshots" if [[ -d "$LOG_DIR" ]]; then echo "🧹 Borrando logs anteriores en $LOG_DIR..." - rm -rf "$LOG_DIR" + echo "🧹 Borrando screenshots anteriores en $SCREEN_SHOTS_DIR..." + sudo rm -rf "$LOG_DIR" + sudo rm -rf "$SCREEN_SHOTS_DIR" fi mkdir -p "$LOG_DIR" +mkdir -p "$SCREEN_SHOTS_DIR" # Verificar si se pasó una carpeta específica como segundo parámetro if [[ -n "$2" ]]; then diff --git a/test/cypress/docker/run/wait_for_api_ready.sh b/test/cypress/docker/run/wait_for_api_ready.sh new file mode 100644 index 000000000..3d8dab48a --- /dev/null +++ b/test/cypress/docker/run/wait_for_api_ready.sh @@ -0,0 +1,29 @@ +wait_for_api_ready() { + local service_name="$1" + local container_name="$2" + local port="$3" + local path="$4" + local network="${5,,}" + local max_retries=30 # Máximo de intentos (30 segundos) + local retries=0 + local url="http://$container_name:$port$path" + + # echo "⏳ Esperando a que $service_name devuelva exactamente 'true' en $url..." + + while [[ $retries -lt $max_retries ]]; do + response=$(docker run --rm --network="$network" curlimages/curl -s "$url" || echo "error") + + # echo "🔍 Respuesta recibida de $service_name: '$response'" + + if [[ "$response" == "true" ]]; then + # echo "✅ Conectado al servicio $service_name → $url!" + return 0 + fi + + sleep 1 + ((retries++)) + done + + echo "❌ ERROR: $service_name no respondió con 'true' en $url después de $max_retries intentos." + exit 1 +}