a1a17e81a1
Includes updated JS challenge scripts with Claude-User whitelist, same-site referer bypass, Blackbox-Exporter allowed bot, and all new exporters, cheat sheets, and automation scripts.
560 lines
23 KiB
Bash
560 lines
23 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
#########################################################################################
|
|
#### k6-test-runner.sh — Run k6 load tests with Prometheus push and formatted ####
|
|
#### reports. Execute test scripts, push metrics, compare runs, threshold checks ####
|
|
#### Requires: bash 4+, k6 ####
|
|
#### ####
|
|
#### Author: Phil Connor ####
|
|
#### Contact: contact@mylinux.work ####
|
|
#### License: MIT ####
|
|
#### Version 1.01 ####
|
|
#### ####
|
|
#### Usage: ####
|
|
#### ./k6-test-runner.sh --run ./tests/load.js ####
|
|
#### ####
|
|
#### See --help for all options. ####
|
|
#########################################################################################
|
|
|
|
set -euo pipefail
|
|
|
|
# ── Colors (pre-initialized) ─────────────────────────────────────────
|
|
RED="" GREEN="" YELLOW="" BLUE="" CYAN="" BOLD="" DIM="" RESET=""
|
|
|
|
setup_colors() {
|
|
if [[ "${COLOR:-auto}" == "never" ]]; then
|
|
return
|
|
fi
|
|
if [[ "${COLOR:-auto}" == "always" ]] || [[ -t 1 ]]; then
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[0;33m'
|
|
BLUE='\033[0;34m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
DIM='\033[2m'
|
|
RESET='\033[0m'
|
|
fi
|
|
}
|
|
|
|
# ── Logging ───────────────────────────────────────────────────────────
|
|
log() { echo -e "${BLUE}[INFO]${RESET} $*"; }
|
|
warn() { echo -e "${YELLOW}[WARN]${RESET} $*" >&2; }
|
|
err() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
|
|
verbose() { if [[ "$VERBOSE" == "true" ]]; then echo -e "${DIM}[DEBUG]${RESET} $*"; fi; }
|
|
die() { err "$*"; exit 1; }
|
|
|
|
section_header() {
|
|
echo ""
|
|
echo -e " ${BOLD}${CYAN}── $1 ──${RESET}"
|
|
echo ""
|
|
}
|
|
|
|
field() {
|
|
printf " ${BOLD}%-22s${RESET} %s\n" "$1" "$2"
|
|
}
|
|
|
|
field_color() {
|
|
printf " ${BOLD}%-22s${RESET} %b\n" "$1" "$2"
|
|
}
|
|
|
|
elapsed() {
|
|
local end_time
|
|
end_time=$(date +%s)
|
|
echo "$(( end_time - START_TIME ))s"
|
|
}
|
|
|
|
# ── Defaults ──────────────────────────────────────────────────────────
|
|
RUN_MODE=""
|
|
TEST_SCRIPT=""
|
|
K6_PATH="${K6_PATH:-k6}"
|
|
VUS="${K6_VUS:-10}"
|
|
DURATION="${K6_DURATION:-30s}"
|
|
PUSH_GW="${K6_PUSH_GATEWAY:-}"
|
|
RESULTS_DIR="${K6_RESULTS_DIR:-./k6-results}"
|
|
OUTPUT_FORMAT="${K6_FORMAT:-text}"
|
|
THRESHOLDS_FILE=""
|
|
COMPARE_RUN=""
|
|
LIST_DIR=""
|
|
INSPECT_SCRIPT=""
|
|
VERBOSE="${VERBOSE:-false}"
|
|
COLOR="${COLOR:-auto}"
|
|
declare -a ENV_VARS=()
|
|
TAGS="${K6_TAGS:-}"
|
|
|
|
# ── State ─────────────────────────────────────────────────────────────
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
readonly SCRIPT_NAME
|
|
START_TIME=""
|
|
RUN_ID=""
|
|
|
|
# ── Dependency checks ────────────────────────────────────────────────
|
|
require_k6() {
|
|
if ! command -v "$K6_PATH" &>/dev/null; then
|
|
die "k6 not found: ${K6_PATH}. Install from https://k6.io/docs/get-started/installation/"
|
|
fi
|
|
verbose "k6 found: $(command -v "$K6_PATH") ($("$K6_PATH" version 2>/dev/null | head -1))"
|
|
}
|
|
|
|
require_jq() {
|
|
if ! command -v jq &>/dev/null; then
|
|
die "jq is required for result parsing"
|
|
fi
|
|
}
|
|
|
|
# ── Format helpers ───────────────────────────────────────────────────
|
|
format_duration_ms() {
|
|
local ms="$1"
|
|
if command -v awk &>/dev/null; then
|
|
if awk "BEGIN{exit ($ms >= 1000) ? 0 : 1}" 2>/dev/null; then
|
|
awk "BEGIN{printf \"%.2fs\", $ms / 1000}"
|
|
else
|
|
awk "BEGIN{printf \"%.1fms\", $ms}"
|
|
fi
|
|
else
|
|
echo "${ms}ms"
|
|
fi
|
|
}
|
|
|
|
format_rate() {
|
|
local rate="$1"
|
|
if command -v awk &>/dev/null; then
|
|
awk "BEGIN{printf \"%.1f/s\", $rate}"
|
|
else
|
|
echo "${rate}/s"
|
|
fi
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# RUN MODE
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
do_run() {
|
|
[[ -z "$TEST_SCRIPT" ]] && die "No test script specified"
|
|
[[ ! -f "$TEST_SCRIPT" ]] && die "Test script not found: ${TEST_SCRIPT}"
|
|
require_k6
|
|
|
|
RUN_ID="$(date +%Y%m%d-%H%M%S)"
|
|
local run_dir="${RESULTS_DIR}/${RUN_ID}"
|
|
mkdir -p "$run_dir"
|
|
|
|
section_header "k6 Load Test"
|
|
field "Test script:" "$TEST_SCRIPT"
|
|
field "Virtual users:" "$VUS"
|
|
field "Duration:" "$DURATION"
|
|
field "Run ID:" "$RUN_ID"
|
|
[[ -n "$PUSH_GW" ]] && field "Push gateway:" "$PUSH_GW"
|
|
echo ""
|
|
|
|
# Build k6 command
|
|
local -a k6_args=("run")
|
|
k6_args+=("--vus" "$VUS")
|
|
k6_args+=("--duration" "$DURATION")
|
|
k6_args+=("--summary-export" "${run_dir}/summary.json")
|
|
k6_args+=("--out" "json=${run_dir}/results.json")
|
|
|
|
if [[ -n "$PUSH_GW" ]]; then
|
|
k6_args+=("--out" "experimental-prometheus-rw=${PUSH_GW}")
|
|
fi
|
|
|
|
if [[ -n "$THRESHOLDS_FILE" && -f "$THRESHOLDS_FILE" ]]; then
|
|
k6_args+=("--config" "$THRESHOLDS_FILE")
|
|
fi
|
|
|
|
for ev in "${ENV_VARS[@]+"${ENV_VARS[@]}"}"; do
|
|
k6_args+=("-e" "$ev")
|
|
done
|
|
|
|
if [[ -n "$TAGS" ]]; then
|
|
k6_args+=("--tag" "$TAGS")
|
|
fi
|
|
|
|
k6_args+=("$TEST_SCRIPT")
|
|
|
|
verbose "Command: ${K6_PATH} ${k6_args[*]}"
|
|
|
|
# Save run metadata
|
|
cat > "${run_dir}/metadata.json" <<EOF
|
|
{"run_id":"${RUN_ID}","script":"${TEST_SCRIPT}","vus":${VUS},"duration":"${DURATION}","timestamp":"$(date -u '+%Y-%m-%dT%H:%M:%SZ')"}
|
|
EOF
|
|
|
|
log "Starting k6 test..."
|
|
echo ""
|
|
|
|
local exit_code=0
|
|
"$K6_PATH" "${k6_args[@]}" 2>&1 | tee "${run_dir}/output.log" || exit_code=$?
|
|
|
|
echo ""
|
|
|
|
# Parse and display results
|
|
if [[ -f "${run_dir}/summary.json" ]]; then
|
|
display_results "${run_dir}/summary.json"
|
|
else
|
|
warn "No summary file generated"
|
|
fi
|
|
|
|
section_header "Run Summary"
|
|
field "Run ID:" "$RUN_ID"
|
|
field "Results:" "$run_dir"
|
|
field "Duration:" "$(elapsed)"
|
|
|
|
if [[ $exit_code -ne 0 ]]; then
|
|
field_color "Status:" "${RED}FAILED (exit ${exit_code})${RESET}"
|
|
else
|
|
field_color "Status:" "${GREEN}PASSED${RESET}"
|
|
fi
|
|
|
|
return "$exit_code"
|
|
}
|
|
|
|
display_results() {
|
|
local summary_file="$1"
|
|
|
|
if ! command -v jq &>/dev/null; then
|
|
warn "jq not available — skipping detailed results"
|
|
return
|
|
fi
|
|
|
|
section_header "Test Results"
|
|
|
|
local http_reqs http_req_dur_avg http_req_dur_p95 http_req_dur_p99
|
|
local http_req_failed iterations data_received data_sent
|
|
|
|
http_reqs=$(jq -r '.metrics.http_reqs.values.count // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
http_req_dur_avg=$(jq -r '.metrics.http_req_duration.values.avg // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
http_req_dur_p95=$(jq -r '.metrics.http_req_duration.values["p(95)"] // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
http_req_dur_p99=$(jq -r '.metrics.http_req_duration.values["p(99)"] // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
http_req_failed=$(jq -r '.metrics.http_req_failed.values.rate // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
iterations=$(jq -r '.metrics.iterations.values.count // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
data_received=$(jq -r '.metrics.data_received.values.count // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
data_sent=$(jq -r '.metrics.data_sent.values.count // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
|
|
local iter_rate
|
|
iter_rate=$(jq -r '.metrics.iterations.values.rate // 0' "$summary_file" 2>/dev/null || echo 0)
|
|
|
|
printf " ${BOLD}%-28s %s${RESET}\n" "METRIC" "VALUE"
|
|
printf " %s\n" "$(printf '%.0s─' {1..50})"
|
|
printf " %-28s %s\n" "HTTP Requests" "$http_reqs"
|
|
printf " %-28s %s\n" "Request Duration (avg)" "$(format_duration_ms "$http_req_dur_avg")"
|
|
printf " %-28s %s\n" "Request Duration (p95)" "$(format_duration_ms "$http_req_dur_p95")"
|
|
printf " %-28s %s\n" "Request Duration (p99)" "$(format_duration_ms "$http_req_dur_p99")"
|
|
|
|
local fail_pct
|
|
fail_pct=$(awk "BEGIN{printf \"%.2f\", $http_req_failed * 100}" 2>/dev/null || echo "0")
|
|
if awk "BEGIN{exit ($http_req_failed > 0) ? 0 : 1}" 2>/dev/null; then
|
|
printf " %-28s ${RED}%s%%${RESET}\n" "Failed Requests" "$fail_pct"
|
|
else
|
|
printf " %-28s ${GREEN}%s%%${RESET}\n" "Failed Requests" "$fail_pct"
|
|
fi
|
|
|
|
printf " %-28s %s\n" "Iterations" "$iterations"
|
|
printf " %-28s %s\n" "Iteration Rate" "$(format_rate "$iter_rate")"
|
|
printf " %-28s %s\n" "Data Received" "$(numfmt --to=iec "$data_received" 2>/dev/null || echo "${data_received} B")"
|
|
printf " %-28s %s\n" "Data Sent" "$(numfmt --to=iec "$data_sent" 2>/dev/null || echo "${data_sent} B")"
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# LIST MODE
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
do_list() {
|
|
local dir="${LIST_DIR:-.}"
|
|
[[ ! -d "$dir" ]] && die "Directory not found: ${dir}"
|
|
|
|
section_header "Available Test Scripts"
|
|
|
|
local count=0
|
|
printf " ${BOLD}%-40s %10s %s${RESET}\n" "SCRIPT" "SIZE" "MODIFIED"
|
|
printf " %s\n" "$(printf '%.0s─' {1..65})"
|
|
|
|
while IFS= read -r -d '' f; do
|
|
local name size modified
|
|
name=$(basename "$f")
|
|
size=$(stat --printf="%s" "$f" 2>/dev/null || stat -f%z "$f" 2>/dev/null || echo 0)
|
|
modified=$(stat --printf="%y" "$f" 2>/dev/null | cut -d' ' -f1 || stat -f"%Sm" -t "%Y-%m-%d" "$f" 2>/dev/null || echo "unknown")
|
|
local human_size
|
|
human_size=$(numfmt --to=iec "$size" 2>/dev/null || echo "${size}B")
|
|
printf " %-40s %10s %s\n" "${name:0:38}" "$human_size" "$modified"
|
|
((count++)) || true
|
|
done < <(find "$dir" -maxdepth 2 -name '*.js' -type f -print0 2>/dev/null | sort -z)
|
|
|
|
echo ""
|
|
field "Total scripts:" "$count"
|
|
|
|
if [[ "$count" -eq 0 ]]; then
|
|
warn "No .js test scripts found in ${dir}"
|
|
fi
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# COMPARE MODE
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
do_compare() {
|
|
[[ -z "$COMPARE_RUN" ]] && die "No run ID specified for comparison"
|
|
require_jq
|
|
|
|
local prev_summary="${RESULTS_DIR}/${COMPARE_RUN}/summary.json"
|
|
[[ ! -f "$prev_summary" ]] && die "Previous run not found: ${prev_summary}"
|
|
|
|
# Find most recent run (excluding the comparison target)
|
|
local latest_dir=""
|
|
while IFS= read -r d; do
|
|
local base
|
|
base=$(basename "$d")
|
|
if [[ "$base" != "$COMPARE_RUN" && -f "${d}/summary.json" ]]; then
|
|
latest_dir="$d"
|
|
break
|
|
fi
|
|
done < <(find "$RESULTS_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort -r)
|
|
|
|
if [[ -z "$latest_dir" ]]; then
|
|
die "No other runs found to compare against"
|
|
fi
|
|
|
|
local curr_summary="${latest_dir}/summary.json"
|
|
local curr_id
|
|
curr_id=$(basename "$latest_dir")
|
|
|
|
section_header "Run Comparison"
|
|
field "Current run:" "$curr_id"
|
|
field "Previous run:" "$COMPARE_RUN"
|
|
echo ""
|
|
|
|
printf " ${BOLD}%-24s %14s %14s %10s${RESET}\n" "METRIC" "CURRENT" "PREVIOUS" "DELTA"
|
|
printf " %s\n" "$(printf '%.0s─' {1..66})"
|
|
|
|
local metrics=("http_reqs.values.count" "http_req_duration.values.avg" "http_req_duration.values[\"p(95)\"]" "iterations.values.count")
|
|
local labels=("HTTP Requests" "Duration (avg ms)" "Duration (p95 ms)" "Iterations")
|
|
|
|
for i in "${!metrics[@]}"; do
|
|
local metric="${metrics[$i]}"
|
|
local label="${labels[$i]}"
|
|
local curr_val prev_val
|
|
curr_val=$(jq -r ".metrics.${metric} // 0" "$curr_summary" 2>/dev/null || echo 0)
|
|
prev_val=$(jq -r ".metrics.${metric} // 0" "$prev_summary" 2>/dev/null || echo 0)
|
|
|
|
local delta delta_pct color
|
|
delta=$(awk "BEGIN{printf \"%.1f\", $curr_val - $prev_val}" 2>/dev/null || echo "0")
|
|
if awk "BEGIN{exit ($prev_val > 0) ? 0 : 1}" 2>/dev/null; then
|
|
delta_pct=$(awk "BEGIN{printf \"%.1f%%\", (($curr_val - $prev_val) / $prev_val) * 100}" 2>/dev/null || echo "0%")
|
|
else
|
|
delta_pct="N/A"
|
|
fi
|
|
|
|
color="$RESET"
|
|
if awk "BEGIN{exit ($delta > 0) ? 0 : 1}" 2>/dev/null; then
|
|
color="$RED"
|
|
elif awk "BEGIN{exit ($delta < 0) ? 0 : 1}" 2>/dev/null; then
|
|
color="$GREEN"
|
|
fi
|
|
|
|
printf " %-24s %14s %14s ${color}%10s${RESET}\n" "$label" \
|
|
"$(awk "BEGIN{printf \"%.1f\", $curr_val}")" \
|
|
"$(awk "BEGIN{printf \"%.1f\", $prev_val}")" \
|
|
"$delta_pct"
|
|
done
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# REPORT MODE
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
do_report() {
|
|
[[ ! -d "$RESULTS_DIR" ]] && die "Results directory not found: ${RESULTS_DIR}"
|
|
|
|
section_header "Test Run History"
|
|
|
|
printf " ${BOLD}%-20s %-30s %8s %12s %s${RESET}\n" "RUN ID" "SCRIPT" "VUS" "DURATION" "STATUS"
|
|
printf " %s\n" "$(printf '%.0s─' {1..80})"
|
|
|
|
local count=0
|
|
while IFS= read -r d; do
|
|
local meta="${d}/metadata.json"
|
|
[[ ! -f "$meta" ]] && continue
|
|
|
|
local run_id script vus duration
|
|
run_id=$(basename "$d")
|
|
if command -v jq &>/dev/null; then
|
|
script=$(jq -r '.script // "unknown"' "$meta" 2>/dev/null || echo "unknown")
|
|
vus=$(jq -r '.vus // "?"' "$meta" 2>/dev/null || echo "?")
|
|
duration=$(jq -r '.duration // "?"' "$meta" 2>/dev/null || echo "?")
|
|
else
|
|
script="(jq required)"
|
|
vus="?"
|
|
duration="?"
|
|
fi
|
|
|
|
local status_icon="${GREEN}✓${RESET}"
|
|
if [[ -f "${d}/summary.json" ]]; then
|
|
local fail_rate
|
|
fail_rate=$(jq -r '.metrics.http_req_failed.values.rate // 0' "${d}/summary.json" 2>/dev/null || echo 0)
|
|
if awk "BEGIN{exit ($fail_rate > 0) ? 0 : 1}" 2>/dev/null; then
|
|
status_icon="${RED}✗${RESET}"
|
|
fi
|
|
else
|
|
status_icon="${YELLOW}?${RESET}"
|
|
fi
|
|
|
|
printf " %-20s %-30s %8s %12s %b\n" "$run_id" "${script:0:28}" "$vus" "$duration" "$status_icon"
|
|
((count++)) || true
|
|
done < <(find "$RESULTS_DIR" -mindepth 1 -maxdepth 1 -type d 2>/dev/null | sort -r)
|
|
|
|
echo ""
|
|
field "Total runs:" "$count"
|
|
|
|
if [[ "$count" -eq 0 ]]; then
|
|
warn "No test runs found in ${RESULTS_DIR}"
|
|
fi
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# INSPECT MODE
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
do_inspect() {
|
|
[[ -z "$INSPECT_SCRIPT" ]] && die "No test script specified"
|
|
[[ ! -f "$INSPECT_SCRIPT" ]] && die "Test script not found: ${INSPECT_SCRIPT}"
|
|
|
|
section_header "Test Inspection"
|
|
field "Script:" "$INSPECT_SCRIPT"
|
|
field "Size:" "$(stat --printf="%s" "$INSPECT_SCRIPT" 2>/dev/null || stat -f%z "$INSPECT_SCRIPT" 2>/dev/null || echo unknown) bytes"
|
|
echo ""
|
|
|
|
log "k6 command that would execute:"
|
|
echo ""
|
|
echo -e " ${DIM}${K6_PATH} run \\"
|
|
echo -e " --vus ${VUS} \\"
|
|
echo -e " --duration ${DURATION} \\"
|
|
[[ -n "$PUSH_GW" ]] && echo -e " --out experimental-prometheus-rw=${PUSH_GW} \\"
|
|
[[ -n "$THRESHOLDS_FILE" ]] && echo -e " --config ${THRESHOLDS_FILE} \\"
|
|
for ev in "${ENV_VARS[@]+"${ENV_VARS[@]}"}"; do
|
|
echo -e " -e ${ev} \\"
|
|
done
|
|
echo -e " ${INSPECT_SCRIPT}${RESET}"
|
|
|
|
echo ""
|
|
if command -v "$K6_PATH" &>/dev/null; then
|
|
field_color "k6 version:" "${GREEN}$("$K6_PATH" version 2>/dev/null | head -1)${RESET}"
|
|
else
|
|
field_color "k6 status:" "${RED}not installed${RESET}"
|
|
fi
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# HELP
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
show_help() {
|
|
cat <<EOF
|
|
${BOLD}${SCRIPT_NAME}${RESET} — k6 Load Test Runner
|
|
|
|
Run k6 load tests with Prometheus metrics push, result comparison,
|
|
and formatted reporting.
|
|
|
|
${BOLD}MODES${RESET}
|
|
--run SCRIPT Execute a k6 test script
|
|
--list [DIR] List available test scripts (default: current dir)
|
|
--compare RUN_ID Compare latest run against a previous run
|
|
--report Show test run history
|
|
--inspect SCRIPT Show what would execute without running
|
|
|
|
${BOLD}OPTIONS${RESET}
|
|
--vus N Number of virtual users (default: 10)
|
|
--duration TIME Test duration (default: 30s)
|
|
--push-gw URL Prometheus push gateway URL
|
|
--results-dir DIR Results directory (default: ./k6-results)
|
|
--thresholds FILE k6 config file with threshold definitions
|
|
--env KEY=VALUE Pass environment variable to k6 (repeatable)
|
|
--tag KEY=VALUE Add tag to k6 metrics
|
|
--format FORMAT Output format: text, json, csv (default: text)
|
|
--verbose Debug output
|
|
--no-color Disable colored output
|
|
--help Show this help message
|
|
|
|
${BOLD}ENVIRONMENT VARIABLES${RESET}
|
|
K6_PATH Path to k6 binary (default: k6)
|
|
K6_VUS Default virtual users (default: 10)
|
|
K6_DURATION Default test duration (default: 30s)
|
|
K6_PUSH_GATEWAY Prometheus push gateway URL
|
|
K6_RESULTS_DIR Results directory (default: ./k6-results)
|
|
K6_FORMAT Output format (default: text)
|
|
K6_TAGS Default tags for k6 metrics
|
|
VERBOSE Enable verbose output (true/false)
|
|
COLOR Color mode: auto, always, never
|
|
|
|
${BOLD}EXAMPLES${RESET}
|
|
# Run a load test
|
|
${SCRIPT_NAME} --run ./tests/load.js
|
|
|
|
# Run with custom VUs and duration
|
|
${SCRIPT_NAME} --run ./tests/api.js --vus 50 --duration 2m
|
|
|
|
# Run with Prometheus push
|
|
${SCRIPT_NAME} --run ./tests/load.js --push-gw http://pushgw:9091
|
|
|
|
# Compare runs
|
|
${SCRIPT_NAME} --compare 20260410-143000
|
|
|
|
# List available tests
|
|
${SCRIPT_NAME} --list ./tests/
|
|
|
|
# Inspect without running
|
|
${SCRIPT_NAME} --inspect ./tests/load.js --vus 100 --duration 5m
|
|
|
|
${BOLD}EXIT CODES${RESET}
|
|
0 Test passed
|
|
1 Runtime error
|
|
2 Test thresholds exceeded
|
|
EOF
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# PARSE ARGS
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--run) RUN_MODE="run"; TEST_SCRIPT="${2:?--run requires a script path}"; shift 2 ;;
|
|
--list) RUN_MODE="list"; LIST_DIR="${2:-.}"; shift; if [[ "${1:-}" != -* ]]; then shift; fi ;;
|
|
--compare) RUN_MODE="compare"; COMPARE_RUN="${2:?--compare requires a run ID}"; shift 2 ;;
|
|
--report) RUN_MODE="report"; shift ;;
|
|
--inspect) RUN_MODE="inspect"; INSPECT_SCRIPT="${2:?--inspect requires a script path}"; shift 2 ;;
|
|
--vus) VUS="${2:?--vus requires a number}"; shift 2 ;;
|
|
--duration) DURATION="${2:?--duration requires a value}"; shift 2 ;;
|
|
--push-gw) PUSH_GW="${2:?--push-gw requires a URL}"; shift 2 ;;
|
|
--results-dir) RESULTS_DIR="${2:?--results-dir requires a path}"; shift 2 ;;
|
|
--thresholds) THRESHOLDS_FILE="${2:?--thresholds requires a file}"; shift 2 ;;
|
|
--env) ENV_VARS+=("${2:?--env requires KEY=VALUE}"); shift 2 ;;
|
|
--tag) TAGS="${2:?--tag requires KEY=VALUE}"; shift 2 ;;
|
|
--format) OUTPUT_FORMAT="${2:?--format requires a value}"; export OUTPUT_FORMAT; shift 2 ;;
|
|
--verbose) VERBOSE="true"; shift ;;
|
|
--no-color) COLOR="never"; shift ;;
|
|
--help|-h) setup_colors; show_help; exit 0 ;;
|
|
*) die "Unknown option: $1 (see --help)" ;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# MAIN
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
main() {
|
|
parse_args "$@"
|
|
setup_colors
|
|
|
|
if [[ -z "$RUN_MODE" ]]; then
|
|
err "No mode specified"
|
|
echo ""
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
START_TIME=$(date +%s)
|
|
|
|
case "$RUN_MODE" in
|
|
run) do_run ;;
|
|
list) do_list ;;
|
|
compare) do_compare ;;
|
|
report) do_report ;;
|
|
inspect) do_inspect ;;
|
|
*) die "Unknown mode: ${RUN_MODE}" ;;
|
|
esac
|
|
}
|
|
|
|
main "$@"
|