#!/bin/bash # ═══════════════════════════════════════════════════════════════════════════ # WalkGuide — k6 Test Runner # Jalankan semua k6 scenarios secara berurutan atau individual. # # Usage: # chmod +x run-all-tests.sh # ./run-all-tests.sh [mode] [BASE_URL] # # Modes: # smoke — 10 VUs, 1 menit (quick sanity check) # load — 50 VUs, 5 menit (normal production load, WAJIB untuk exam) # stress — 100 VUs, 10 menit (breaking point) # spike — 0→200 VUs sudden spike # all — jalankan smoke → load → stress → spike berurutan # auth — hanya auth-flow.js # pairing — hanya pairing-flow.js # location — hanya location-update.js # obstacle — hanya obstacle-logging.js # sos — hanya sos-flow.js # notif — hanya notification-send.js # timeline — hanya timeline-query.js # # Contoh: # ./run-all-tests.sh load http://202.46.28.160:8080 # ./run-all-tests.sh smoke # ./run-all-tests.sh all http://202.46.28.160:8080 # ═══════════════════════════════════════════════════════════════════════════ set -e # ── Config ──────────────────────────────────────────────────────────────────── MODE="${1:-load}" BASE_URL="${2:-http://202.46.28.160:8080}" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" RESULTS_DIR="${SCRIPT_DIR}/k6-results" TIMESTAMP=$(date +"%Y%m%d_%H%M%S") # ── Colors ──────────────────────────────────────────────────────────────────── RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # No Color # ── Helpers ─────────────────────────────────────────────────────────────────── log() { echo -e "${CYAN}[$(date +%H:%M:%S)]${NC} $1"; } ok() { echo -e "${GREEN}[✅ OK]${NC} $1"; } warn() { echo -e "${YELLOW}[⚠️ WARN]${NC} $1"; } err() { echo -e "${RED}[❌ ERR]${NC} $1"; } hr() { echo -e "${BLUE}═══════════════════════════════════════════════════════${NC}"; } # ── Pre-flight checks ───────────────────────────────────────────────────────── hr echo -e "${BOLD} 🦺 WalkGuide — k6 Load Test Runner${NC}" echo -e " Mode: ${YELLOW}${MODE}${NC} | Backend: ${YELLOW}${BASE_URL}${NC}" hr # Check k6 installed if ! command -v k6 &> /dev/null; then err "k6 not installed!" echo "Install: https://k6.io/docs/getting-started/installation/" echo "Ubuntu: sudo apt-get install k6" echo "Mac: brew install k6" echo "Docker: docker run grafana/k6 run ..." exit 1 fi K6_VERSION=$(k6 version 2>&1 | head -1) ok "k6 found: $K6_VERSION" # Check Node.js (for result parsing) if command -v node &> /dev/null; then ok "Node.js: $(node --version)" else warn "Node.js not found — skipping HTML report generation" fi # Create results dir mkdir -p "$RESULTS_DIR" ok "Results dir: $RESULTS_DIR" # ── Backend reachability check ──────────────────────────────────────────────── log "Checking backend reachability..." HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${BASE_URL}/api/v1/auth/ping" --max-time 10 2>/dev/null || echo "000") if [ "$HTTP_STATUS" = "200" ]; then ok "Backend reachable (HTTP $HTTP_STATUS)" elif [ "$HTTP_STATUS" = "000" ]; then warn "Backend not reachable or timeout. Continuing anyway (tests will fail gracefully)." else warn "Backend returned HTTP $HTTP_STATUS. Continuing..." fi # ── k6 run helper ───────────────────────────────────────────────────────────── run_k6() { local scenario_file="$1" local scenario_name="$2" local extra_args="${3:-}" local output_json="${RESULTS_DIR}/${scenario_name}_${TIMESTAMP}.ndjson" local summary_json="${RESULTS_DIR}/${scenario_name}_summary_${TIMESTAMP}.json" log "Running scenario: ${BOLD}${scenario_name}${NC}" log "Script: ${scenario_file}" local k6_cmd="k6 run \ --out json=${output_json} \ -e BASE_URL=${BASE_URL} \ --summary-export=${summary_json} \ --no-color \ ${extra_args} \ ${SCRIPT_DIR}/scenarios/${scenario_file}" echo "Command: $k6_cmd" hr if eval "$k6_cmd"; then ok "Scenario ${scenario_name} completed successfully" else warn "Scenario ${scenario_name} completed with threshold violations (check results)" fi # Parse results if Node.js available if command -v node &> /dev/null && [ -f "$output_json" ]; then log "Parsing results..." local parsed_json="${RESULTS_DIR}/${scenario_name}_parsed_${TIMESTAMP}.json" local html_report="${RESULTS_DIR}/${scenario_name}_report_${TIMESTAMP}.html" node "${SCRIPT_DIR}/utils/result-parser.js" "$output_json" "$parsed_json" 2>/dev/null || true node "${SCRIPT_DIR}/utils/html-reporter.js" "$parsed_json" "$html_report" 2>/dev/null || true if [ -f "$html_report" ]; then ok "HTML report: $html_report" fi fi echo "" } # ── Stage-specific k6 args ──────────────────────────────────────────────────── SMOKE_ARGS="--stage 30s:3 --stage 60s:10 --stage 30s:0" # Note: --stage shorthand diganti inline di script JSON # ── Test execution ───────────────────────────────────────────────────────────── case "$MODE" in smoke) log "=== SMOKE TEST (10 VUs, 1 min) ===" run_k6 "auth-flow.js" "smoke_auth" "--vus 3 --duration 60s" run_k6 "location-update.js" "smoke_location" "--vus 3 --duration 60s" run_k6 "sos-flow.js" "smoke_sos" "--vus 2 --duration 60s" ;; load) log "=== LOAD TEST (50+ VUs, 5 min) — EXAM REQUIRED ===" run_k6 "auth-flow.js" "load_auth" run_k6 "pairing-flow.js" "load_pairing" run_k6 "location-update.js" "load_location" run_k6 "obstacle-logging.js" "load_obstacle" run_k6 "sos-flow.js" "load_sos" run_k6 "notification-send.js" "load_notif" run_k6 "timeline-query.js" "load_timeline" ;; stress) log "=== STRESS TEST (100 VUs, 10 min) ===" run_k6 "location-update.js" "stress_location" run_k6 "obstacle-logging.js" "stress_obstacle" run_k6 "notification-send.js" "stress_notif" run_k6 "timeline-query.js" "stress_timeline" ;; spike) log "=== SPIKE TEST (0→200 VUs sudden) ===" run_k6 "location-update.js" "spike_location" run_k6 "obstacle-logging.js" "spike_obstacle" ;; all) log "=== FULL TEST SUITE (smoke → load → stress → spike) ===" warn "Estimated total time: 30-45 minutes" read -p "Continue? [y/N] " confirm if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then echo "Aborted."; exit 0 fi # Smoke log "--- Phase 1: Smoke Test ---" run_k6 "auth-flow.js" "fullsuite_smoke_auth" "--vus 3 --duration 60s" run_k6 "location-update.js" "fullsuite_smoke_location" "--vus 3 --duration 60s" # Load log "--- Phase 2: Load Test ---" run_k6 "auth-flow.js" "fullsuite_load_auth" run_k6 "location-update.js" "fullsuite_load_location" run_k6 "obstacle-logging.js" "fullsuite_load_obstacle" run_k6 "sos-flow.js" "fullsuite_load_sos" run_k6 "notification-send.js" "fullsuite_load_notif" run_k6 "timeline-query.js" "fullsuite_load_timeline" # Stress log "--- Phase 3: Stress Test ---" run_k6 "location-update.js" "fullsuite_stress_location" # Spike log "--- Phase 4: Spike Test ---" run_k6 "location-update.js" "fullsuite_spike_location" ;; # Individual scenarios auth) run_k6 "auth-flow.js" "individual_auth" ;; pairing) run_k6 "pairing-flow.js" "individual_pairing" ;; location) run_k6 "location-update.js" "individual_location" ;; obstacle) run_k6 "obstacle-logging.js" "individual_obstacle" ;; sos) run_k6 "sos-flow.js" "individual_sos" ;; notif) run_k6 "notification-send.js" "individual_notif" ;; timeline) run_k6 "timeline-query.js" "individual_timeline" ;; *) err "Unknown mode: $MODE" echo "Valid modes: smoke | load | stress | spike | all | auth | pairing | location | obstacle | sos | notif | timeline" exit 1 ;; esac # ── Final summary ───────────────────────────────────────────────────────────── hr ok "All k6 tests finished!" log "Results saved to: $RESULTS_DIR" echo "" echo "Files generated:" ls -lh "$RESULTS_DIR"/*.{json,html} 2>/dev/null || echo " (no files found)" hr