test: E2E скрипт run_e2e_tests.sh + fix provider token/version в примерах
This commit is contained in:
Executable
+256
@@ -0,0 +1,256 @@
|
||||
#!/usr/bin/env bash
|
||||
# 2026-03-11
|
||||
# run_e2e_tests.sh — E2E тест примеров: apply → modify → apply → destroy
|
||||
#
|
||||
# Запускает два примера: hello-node (nodejs20) и simple-python (python3.11)
|
||||
# Каждый проходит полный цикл: init → apply → modify → apply → destroy
|
||||
# В конце кластер должен быть полностью чистым.
|
||||
#
|
||||
# Использование:
|
||||
# ./run_e2e_tests.sh
|
||||
# ./run_e2e_tests.sh hello-node # только один пример
|
||||
#
|
||||
# Требования: terraform, curl в PATH
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
EXAMPLES_DIR="$REPO_ROOT/examples"
|
||||
LOGS_DIR="$REPO_ROOT/.e2e-logs"
|
||||
mkdir -p "$LOGS_DIR"
|
||||
|
||||
# ── Примеры для запуска ──────────────────────────────────────────────────────
|
||||
if [ $# -gt 0 ]; then
|
||||
EXAMPLES=("$@")
|
||||
else
|
||||
EXAMPLES=("hello-node" "simple-python")
|
||||
fi
|
||||
|
||||
# ── Цвета ────────────────────────────────────────────────────────────────────
|
||||
GREEN='\033[0;32m'; RED='\033[0;31m'; YELLOW='\033[1;33m'; RESET='\033[0m'
|
||||
ok() { echo -e "${GREEN} ✓ $*${RESET}"; }
|
||||
fail() { echo -e "${RED} ✗ $*${RESET}"; }
|
||||
info() { echo -e "${YELLOW} → $*${RESET}"; }
|
||||
|
||||
# ── Результаты ───────────────────────────────────────────────────────────────
|
||||
declare -A RESULTS=()
|
||||
|
||||
# ── Cleanup-trap: уничтожить всё что могло остаться ──────────────────────────
|
||||
cleanup() {
|
||||
for example in "${EXAMPLES[@]}"; do
|
||||
local dir="$EXAMPLES_DIR/$example"
|
||||
if [ -f "$dir/terraform.tfstate" ] && \
|
||||
grep -q '"resources"' "$dir/terraform.tfstate" 2>/dev/null && \
|
||||
python3 -c "import json,sys; d=json.load(open('$dir/terraform.tfstate')); sys.exit(0 if d.get('resources') else 1)" 2>/dev/null; then
|
||||
info "cleanup trap: destroying $example"
|
||||
(cd "$dir" && terraform destroy -auto-approve -input=false -no-color \
|
||||
>> "$LOGS_DIR/${example}-destroy-emergency.log" 2>&1) || true
|
||||
fi
|
||||
restore_backup "$example"
|
||||
done
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# ── Retry wrapper: 3 попытки, ретрай при TLS/EOF ошибках ─────────────────────
|
||||
# Использование: tf_retry <logfile> <terraform args...>
|
||||
tf_retry() {
|
||||
local logfile="$1"; shift
|
||||
local attempt=1
|
||||
while [ "$attempt" -le 3 ]; do
|
||||
if "$@" 2>&1 | tee "$logfile"; then
|
||||
return 0
|
||||
fi
|
||||
if grep -Eiq \
|
||||
'TLS handshake timeout|unexpected EOF|i/o timeout|context deadline' \
|
||||
"$logfile" && [ "$attempt" -lt 3 ]; then
|
||||
info "network error, retry $((attempt+1))/3..."
|
||||
attempt=$((attempt + 1))
|
||||
sleep 3
|
||||
continue
|
||||
fi
|
||||
return 1
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# ── Modify: сохранить бэкап и внести изменение ───────────────────────────────
|
||||
# Изменения минимальны и легко проверяемы в plan output
|
||||
backup_and_modify() {
|
||||
local example="$1"
|
||||
case "$example" in
|
||||
hello-node)
|
||||
cp "$EXAMPLES_DIR/$example/http.tf" \
|
||||
"$EXAMPLES_DIR/$example/http.tf.e2e.bak"
|
||||
# memory_mb 128 → 256, добавить env_vars
|
||||
perl -0pi -e \
|
||||
's/(memory_mb\s+=\s+)128/${1}256/' \
|
||||
"$EXAMPLES_DIR/$example/http.tf"
|
||||
perl -0pi -e \
|
||||
's/(source_dir\s+=.*\n)/$1\n env_vars = \{ GREETING = "e2e-test" \}\n/' \
|
||||
"$EXAMPLES_DIR/$example/http.tf"
|
||||
;;
|
||||
simple-python)
|
||||
cp "$EXAMPLES_DIR/$example/time-display.tf" \
|
||||
"$EXAMPLES_DIR/$example/time-display.tf.e2e.bak"
|
||||
# memory_mb 64 → 96
|
||||
perl -0pi -e \
|
||||
's/(memory_mb\s+=\s+)64/${1}96/' \
|
||||
"$EXAMPLES_DIR/$example/time-display.tf"
|
||||
;;
|
||||
simple-node)
|
||||
cp "$EXAMPLES_DIR/$example/time-display.tf" \
|
||||
"$EXAMPLES_DIR/$example/time-display.tf.e2e.bak"
|
||||
perl -0pi -e \
|
||||
's/(memory_mb\s+=\s+)64/${1}96/' \
|
||||
"$EXAMPLES_DIR/$example/time-display.tf"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
restore_backup() {
|
||||
local example="$1"
|
||||
for bak in "$EXAMPLES_DIR/$example"/*.e2e.bak; do
|
||||
[ -f "$bak" ] || continue
|
||||
mv "$bak" "${bak%.e2e.bak}"
|
||||
done
|
||||
}
|
||||
|
||||
# ── Шаг apply: проверяем что terraform вернул 0 и есть "Apply complete" ───────
|
||||
assert_apply_ok() {
|
||||
local logfile="$1"
|
||||
if ! grep -q 'Apply complete' "$logfile"; then
|
||||
return 1
|
||||
fi
|
||||
# Выводим краткий итог
|
||||
grep -E 'Apply complete|added|changed|destroyed|Outputs:' "$logfile" | head -5
|
||||
return 0
|
||||
}
|
||||
|
||||
assert_destroy_ok() {
|
||||
local logfile="$1"
|
||||
grep -q 'Destroy complete' "$logfile"
|
||||
}
|
||||
|
||||
# ── Запуск одного примера ─────────────────────────────────────────────────────
|
||||
run_example() {
|
||||
local example="$1"
|
||||
local dir="$EXAMPLES_DIR/$example"
|
||||
local log_base="$LOGS_DIR/$example"
|
||||
local failed=0
|
||||
|
||||
echo
|
||||
echo "════════════════════════════════════════"
|
||||
echo " EXAMPLE: $example"
|
||||
echo "════════════════════════════════════════"
|
||||
|
||||
# Чистим локальные артефакты от предыдущих запусков
|
||||
rm -rf "$dir/.terraform" "$dir/.terraform.lock.hcl" \
|
||||
"$dir/terraform.tfstate" "$dir/terraform.tfstate.backup" \
|
||||
"$dir"/terraform.tfstate.*.backup
|
||||
|
||||
# 1. init ───────────────────────────────────────────────────────────────────
|
||||
info "init"
|
||||
if tf_retry "${log_base}-init.log" \
|
||||
terraform -chdir="$dir" init -input=false -no-color; then
|
||||
ok "init"
|
||||
else
|
||||
fail "init — см. ${log_base}-init.log"
|
||||
RESULTS[$example]="FAIL (init)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 2. apply ──────────────────────────────────────────────────────────────────
|
||||
info "apply"
|
||||
if tf_retry "${log_base}-apply.log" \
|
||||
terraform -chdir="$dir" apply -auto-approve -input=false -no-color \
|
||||
&& assert_apply_ok "${log_base}-apply.log"; then
|
||||
ok "apply"
|
||||
else
|
||||
fail "apply — см. ${log_base}-apply.log"
|
||||
RESULTS[$example]="FAIL (apply)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 3. modify ─────────────────────────────────────────────────────────────────
|
||||
info "modify (backup + patch)"
|
||||
backup_and_modify "$example"
|
||||
ok "files patched"
|
||||
|
||||
# 4. apply after modify ─────────────────────────────────────────────────────
|
||||
info "apply (после modify)"
|
||||
if tf_retry "${log_base}-apply-modify.log" \
|
||||
terraform -chdir="$dir" apply -auto-approve -input=false -no-color \
|
||||
&& assert_apply_ok "${log_base}-apply-modify.log"; then
|
||||
ok "apply (modify)"
|
||||
# Показываем что изменилось
|
||||
grep -E 'changed|updated|Modifying' "${log_base}-apply-modify.log" | head -3 \
|
||||
|| true
|
||||
else
|
||||
fail "apply (modify) — см. ${log_base}-apply-modify.log"
|
||||
RESULTS[$example]="FAIL (apply-modify)"
|
||||
failed=1
|
||||
fi
|
||||
|
||||
# Восстанавливаем файлы до destroy
|
||||
restore_backup "$example"
|
||||
|
||||
# 5. destroy ────────────────────────────────────────────────────────────────
|
||||
info "destroy"
|
||||
if tf_retry "${log_base}-destroy.log" \
|
||||
terraform -chdir="$dir" destroy -auto-approve -input=false -no-color \
|
||||
&& assert_destroy_ok "${log_base}-destroy.log"; then
|
||||
ok "destroy"
|
||||
grep 'Destroy complete' "${log_base}-destroy.log" || true
|
||||
else
|
||||
fail "destroy — см. ${log_base}-destroy.log"
|
||||
RESULTS[$example]="FAIL (destroy)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Чистим после успешного прогона
|
||||
rm -rf "$dir/.terraform" "$dir/.terraform.lock.hcl" \
|
||||
"$dir/terraform.tfstate" "$dir/terraform.tfstate.backup"
|
||||
|
||||
if [ "$failed" -eq 0 ]; then
|
||||
RESULTS[$example]="PASS"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Main ──────────────────────────────────────────────────────────────────────
|
||||
main() {
|
||||
echo
|
||||
echo "╔══════════════════════════════════════╗"
|
||||
echo "║ sless E2E tests $(date '+%Y-%m-%d %H:%M') ║"
|
||||
echo "╚══════════════════════════════════════╝"
|
||||
echo "Примеры: ${EXAMPLES[*]}"
|
||||
echo "Логи: $LOGS_DIR"
|
||||
|
||||
for example in "${EXAMPLES[@]}"; do
|
||||
run_example "$example" || true
|
||||
done
|
||||
|
||||
# ── Итог ────────────────────────────────────────────────────────────────────
|
||||
echo
|
||||
echo "════════════════ ИТОГ ════════════════"
|
||||
local all_pass=1
|
||||
for example in "${EXAMPLES[@]}"; do
|
||||
local result="${RESULTS[$example]:-UNKNOWN}"
|
||||
if [ "$result" = "PASS" ]; then
|
||||
ok "$example: $result"
|
||||
else
|
||||
fail "$example: $result"
|
||||
all_pass=0
|
||||
fi
|
||||
done
|
||||
echo "══════════════════════════════════════"
|
||||
|
||||
if [ "$all_pass" -eq 1 ]; then
|
||||
echo -e "${GREEN}Все тесты прошли успешно.${RESET}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}Есть ошибки. Логи: $LOGS_DIR${RESET}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main
|
||||
Reference in New Issue
Block a user