#!/usr/bin/env bash # run_kotlin_app_tests — Pipeline e2e completo de testing app Kotlin: # unit JVM + screenshot Roborazzi + build APK + instrumented Compose en emulador. # # USO: # bash run_kotlin_app_tests.sh [avd_name] [--skip-emulator] [--no-stop] # # ARGUMENTOS: # project_dir Raiz del proyecto Android (debe contener gradlew). Obligatorio. # avd_name Nombre del AVD para instrumented tests. Default: Medium_Phone_API_35. # --skip-emulator Saltar instrumented tests (solo unit + screenshot + build). # --no-stop No parar el emulador al finalizar (util en desarrollo iterativo). # # EXIT CODES: # 0 Todos los tests pasan. # 1 Unit tests fallaron. # 2 Screenshot tests fallaron. # 3 Build APK fallado. # 4 AVD no encontrado. # 5 Instrumented tests fallaron. # # EJEMPLO: # bash bash/functions/pipelines/run_kotlin_app_tests.sh apps/my_app # bash bash/functions/pipelines/run_kotlin_app_tests.sh apps/my_app Pixel_7_API_34 # bash bash/functions/pipelines/run_kotlin_app_tests.sh apps/my_app --skip-emulator # bash bash/functions/pipelines/run_kotlin_app_tests.sh apps/my_app Medium_Phone_API_35 --no-stop set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REGISTRY_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" # --------------------------------------------------------------------------- # Parseo de argumentos # --------------------------------------------------------------------------- PROJECT_DIR="${1:-}" AVD_NAME="Medium_Phone_API_35" SKIP_EMULATOR=false NO_STOP=false # Primer argumento posicional es project_dir; el resto puede ser flags o avd_name. shift || true for arg in "$@"; do case "$arg" in --skip-emulator) SKIP_EMULATOR=true ;; --no-stop) NO_STOP=true ;; --*) echo "[run_kotlin_app_tests] ERROR: flag desconocido: $arg" >&2 echo "USO: $0 [avd_name] [--skip-emulator] [--no-stop]" >&2 exit 1 ;; *) AVD_NAME="$arg" ;; esac done if [[ -z "$PROJECT_DIR" ]]; then echo "[run_kotlin_app_tests] ERROR: project_dir es obligatorio." >&2 echo "USO: $0 [avd_name] [--skip-emulator] [--no-stop]" >&2 exit 1 fi # Resolver path absoluto if [[ "$PROJECT_DIR" != /* ]]; then PROJECT_DIR="$(pwd)/$PROJECT_DIR" fi # --------------------------------------------------------------------------- # Validacion inicial # --------------------------------------------------------------------------- if [[ ! -f "$PROJECT_DIR/gradlew" ]]; then echo "[run_kotlin_app_tests] ERROR: no se encontro gradlew en $PROJECT_DIR" >&2 exit 1 fi echo "" echo "======================================================================" echo " run_kotlin_app_tests" echo "======================================================================" echo " project_dir : $PROJECT_DIR" echo " avd_name : $AVD_NAME" echo " skip_emulator : $SKIP_EMULATOR" echo " no_stop : $NO_STOP" echo "======================================================================" echo "" # --------------------------------------------------------------------------- # Tabla de resultados acumulada # --------------------------------------------------------------------------- # Arrays paralelos: nombre, status, tiempo STEP_NAMES=() STEP_STATUS=() STEP_TIMES=() record_step() { local name="$1" status="$2" elapsed="$3" STEP_NAMES+=("$name") STEP_STATUS+=("$status") STEP_TIMES+=("${elapsed}s") } print_summary() { echo "" echo "======================================================================" echo " RESUMEN" printf " %-30s %-6s %s\n" "STEP" "STATUS" "TIEMPO" echo " ------------------------------ ------ ------" for i in "${!STEP_NAMES[@]}"; do printf " %-30s %-6s %s\n" "${STEP_NAMES[$i]}" "${STEP_STATUS[$i]}" "${STEP_TIMES[$i]}" done echo "======================================================================" echo "" } # --------------------------------------------------------------------------- # Paso 1: Unit tests (JVM) # --------------------------------------------------------------------------- echo "[run_kotlin_app_tests] [1/4] Unit tests (JVM)..." T_START=$SECONDS if bash "$REGISTRY_ROOT/bash/functions/infra/gradle_unit_test.sh" "$PROJECT_DIR"; then record_step "unit_tests" "OK" $((SECONDS - T_START)) echo "[run_kotlin_app_tests] Unit tests: OK" else record_step "unit_tests" "FAIL" $((SECONDS - T_START)) print_summary echo "[run_kotlin_app_tests] ERROR: unit tests fallaron." >&2 exit 1 fi # --------------------------------------------------------------------------- # Paso 2: Screenshot tests (Roborazzi, JVM) # --------------------------------------------------------------------------- echo "" echo "[run_kotlin_app_tests] [2/4] Screenshot tests (Roborazzi, JVM)..." T_START=$SECONDS if bash "$REGISTRY_ROOT/bash/functions/infra/gradle_screenshot_test.sh" "$PROJECT_DIR"; then record_step "screenshot_tests" "OK" $((SECONDS - T_START)) echo "[run_kotlin_app_tests] Screenshot tests: OK" else record_step "screenshot_tests" "FAIL" $((SECONDS - T_START)) print_summary echo "[run_kotlin_app_tests] ERROR: screenshot tests fallaron." >&2 exit 2 fi # --------------------------------------------------------------------------- # Paso 3: Build APK debug # --------------------------------------------------------------------------- echo "" echo "[run_kotlin_app_tests] [3/4] Build APK debug..." T_START=$SECONDS if bash "$REGISTRY_ROOT/bash/functions/infra/gradle_assemble_debug.sh" "$PROJECT_DIR"; then record_step "assemble_debug" "OK" $((SECONDS - T_START)) echo "[run_kotlin_app_tests] Build APK: OK" else record_step "assemble_debug" "FAIL" $((SECONDS - T_START)) print_summary echo "[run_kotlin_app_tests] ERROR: build APK fallado." >&2 exit 3 fi # --------------------------------------------------------------------------- # Paso 4: Instrumented tests (emulador) # --------------------------------------------------------------------------- if [[ "$SKIP_EMULATOR" == "true" ]]; then record_step "instrumented_tests" "SKIP" 0 print_summary echo "[run_kotlin_app_tests] --skip-emulator activo. Pipeline completo (sin instrumented)." exit 0 fi echo "" echo "[run_kotlin_app_tests] [4/4] Instrumented tests en emulador '$AVD_NAME'..." # Source adb_wsl para resolver $ADB y helpers de dispositivo # shellcheck source=../infra/adb_wsl.sh source "$REGISTRY_ROOT/bash/functions/infra/adb_wsl.sh" # Verificar que el AVD existe echo "[run_kotlin_app_tests] Verificando AVD '$AVD_NAME'..." if ! bash "$REGISTRY_ROOT/bash/functions/infra/android_emulator_list.sh" | grep -qx "$AVD_NAME"; then record_step "emulator_check" "FAIL" 0 record_step "instrumented_tests" "SKIP" 0 print_summary echo "[run_kotlin_app_tests] ERROR: AVD '$AVD_NAME' no encontrado." >&2 echo " AVDs disponibles:" >&2 bash "$REGISTRY_ROOT/bash/functions/infra/android_emulator_list.sh" | sed 's/^/ /' >&2 exit 4 fi record_step "emulator_check" "OK" 0 # Arrancar emulador (idempotente) echo "[run_kotlin_app_tests] Arrancando emulador '$AVD_NAME' (idempotente)..." T_START=$SECONDS if ! bash "$REGISTRY_ROOT/bash/functions/infra/android_emulator_start.sh" "$AVD_NAME"; then record_step "emulator_start" "FAIL" $((SECONDS - T_START)) print_summary echo "[run_kotlin_app_tests] ERROR: no se pudo arrancar el emulador." >&2 exit 4 fi record_step "emulator_start" "OK" $((SECONDS - T_START)) # Correr instrumented tests echo "[run_kotlin_app_tests] Corriendo instrumented tests..." T_START=$SECONDS INSTRUMENTED_EXIT=0 bash "$REGISTRY_ROOT/bash/functions/infra/gradle_instrumented_test.sh" "$PROJECT_DIR" || INSTRUMENTED_EXIT=$? if [[ $INSTRUMENTED_EXIT -eq 0 ]]; then record_step "instrumented_tests" "OK" $((SECONDS - T_START)) echo "[run_kotlin_app_tests] Instrumented tests: OK" else record_step "instrumented_tests" "FAIL" $((SECONDS - T_START)) fi # Parar emulador (salvo --no-stop) if [[ "$NO_STOP" == "false" ]]; then echo "[run_kotlin_app_tests] Parando emulador..." T_START=$SECONDS bash "$REGISTRY_ROOT/bash/functions/infra/android_emulator_stop.sh" || true record_step "emulator_stop" "OK" $((SECONDS - T_START)) else record_step "emulator_stop" "SKIP" 0 echo "[run_kotlin_app_tests] --no-stop activo: emulador sigue corriendo." fi print_summary if [[ $INSTRUMENTED_EXIT -ne 0 ]]; then echo "[run_kotlin_app_tests] ERROR: instrumented tests fallaron." >&2 exit 5 fi echo "[run_kotlin_app_tests] Pipeline e2e completado con exito." exit 0