#!/bin/bash # test_cache_matrix.sh — 2026-03-23 (v4) # Комплексный тест кэша registry: # Phase 1 — полный деплой всех 24 ресурсов (kaniko builds, т.к. нет образов) # Phase 2 — destroy sless_* + re-apply (все образы из кэша) # Phase 3 — одновременно: удаление 2, смена кода 2, смена параметров 2 # ВАЖНО: postgres.tf НЕ переименовывается и НЕ трогается никогда. # Destroy sless-ресурсов делается путём переименования tf-файлов в .tf.bak, # затем terraform apply (видит что ресурсов нет → удаляет их из state+кластера), # затем файлы возвращаются обратно. Никаких -target. set -euo pipefail DIR="$(cd "$(dirname "$0")" && pwd)" LOG="$DIR/test_cache_matrix_$(date +%Y%m%d_%H%M%S).log" TIMINGS="$LOG.timings" PASS=0 FAIL=0 log() { echo "[$(date +%H:%M:%S)] $*" | tee -a "$LOG"; } sep() { log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"; } timed_op() { local label="$1"; shift log "▶ START: $label" local t0; t0=$(date +%s%3N) "$@" 2>&1 | tee -a "$LOG" local rc=${PIPESTATUS[0]} local t1; t1=$(date +%s%3N) local elapsed=$(( (t1 - t0) / 1000 )) if [[ $rc -eq 0 ]]; then log "✓ DONE: $label — ${elapsed}s" PASS=$((PASS+1)) else log "✗ FAIL: $label — ${elapsed}s (exit $rc)" FAIL=$((FAIL+1)) fi echo "$label: ${elapsed}s" >> "$TIMINGS" return $rc } destroy_sless_only() { # Переименовываем tf-файлы с sless-ресурсами в .tf.bak → terraform apply их удалит. # Никаких -target — чтобы не затрагивать postgres и не получать state drift. local label="$1" local SLESS_FILES=("chaos_marathon.tf" "functions.tf" "stress.tf") local has_state has_state=$(terraform state list 2>/dev/null | grep -cE '^(sless_service|sless_job)' || true) if [[ "$has_state" -eq 0 ]]; then log " (nothing to destroy for $label — state empty)" return 0 fi log " Hiding sless tf-files → apply will destroy $has_state resources" for f in "${SLESS_FILES[@]}"; do [[ -f "$DIR/$f" ]] && mv "$DIR/$f" "$DIR/$f.bak" done timed_op "$label" terraform apply -auto-approve for f in "${SLESS_FILES[@]}"; do [[ -f "$DIR/$f.bak" ]] && mv "$DIR/$f.bak" "$DIR/$f" done log " sless tf-files restored" } cd "$DIR" sep log "PHASE 1: Полный начальный деплой" sep destroy_sless_only "phase1-pre-clean" timed_op "phase1-apply-all" terraform apply -auto-approve log "--- Образы в registry после Phase 1 ---" kubectl exec -n sless deployment/sless-registry -- sh -c 'find /var/lib/registry -name "*.json" -path "*/tags/*" 2>/dev/null | sed "s|.*repository/||;s|/_manifests.*||" | sort | uniq -c | sort -rn' 2>/dev/null | head -30 | tee -a "$LOG" || log "(registry inspect failed)" sep log "PHASE 2: Destroy sless_* → Re-apply (ожидаем cache hits)" sep destroy_sless_only "phase2-destroy" timed_op "phase2-apply-cached" terraform apply -auto-approve sep log "PHASE 3: Mixed ops (delete+code+params)" sep log "--- 3a: destroy stress_divzero, chaos_echo (comment out → apply → restore) ---" python3 - <<'PYEOF' import re, pathlib def comment_out_resource(path, resource_type, resource_name): text = pathlib.Path(path).read_text() # Находим блок resource "type" "name" { ... } и оборачиваем в /* */ pattern = rf'(resource\s+"{re.escape(resource_type)}"\s+"{re.escape(resource_name)}"\s*\{{)' match = re.search(pattern, text) if not match: print(f" WARNING: {resource_type}.{resource_name} not found in {path}") return # Найти закрывающую скобку блока start = match.start() depth = 0 i = match.start() while i < len(text): if text[i] == '{': depth += 1 elif text[i] == '}': depth -= 1 if depth == 0: end = i + 1 break i += 1 block = text[start:end] commented = "/* COMMENTED_OUT_FOR_TEST\n" + block + "\nCOMMENTED_OUT_FOR_TEST */" pathlib.Path(path).write_text(text[:start] + commented + text[end:]) print(f" commented out: {resource_type}.{resource_name} in {path}") comment_out_resource("stress.tf", "sless_service", "stress_divzero") comment_out_resource("chaos_marathon.tf", "sless_service", "chaos_echo") PYEOF timed_op "phase3a-destroy-2" terraform apply -auto-approve # Восстанавливаем закомментированные блоки python3 - <<'PYEOF' import pathlib, re for fname in ("stress.tf", "chaos_marathon.tf"): p = pathlib.Path(fname) text = p.read_text() text = re.sub(r'/\* COMMENTED_OUT_FOR_TEST\n', '', text) text = re.sub(r'\nCOMMENTED_OUT_FOR_TEST \*/', '', text) p.write_text(text) print(f" restored: {fname}") PYEOF log " stress_divzero, chaos_echo removed from state and k8s" log "--- 3b: code changes (new sha256 → kaniko) ---" echo "" >> "$DIR/code/pg-counter/pg_counter.py" echo "# cache-test-$(date +%s)" >> "$DIR/code/pg-counter/pg_counter.py" echo "" >> "$DIR/code/stress-js-async/stress_js_async.js" echo "// cache-test-$(date +%s)" >> "$DIR/code/stress-js-async/stress_js_async.js" log " changed: pg_counter.py, stress_js_async.js" log "--- 3c: param changes (same sha256 → no kaniko) ---" python3 - <<'PYEOF' import re, sys with open("stress.tf") as f: content = f.read() orig = content content = re.sub( r'(resource "sless_service" "stress_slow" \{[^}]*?)memory_mb\s*=\s*\d+', lambda m: m.group(1) + 'memory_mb = 192', content, flags=re.DOTALL ) content = re.sub( r'(resource "sless_service" "pg_stats" \{[^}]*?)timeout_sec\s*=\s*\d+', lambda m: m.group(1) + 'timeout_sec = 20', content, flags=re.DOTALL ) if content == orig: print(" stress.tf: no changes (already patched?)", file=sys.stderr) else: with open("stress.tf", "w") as f: f.write(content) print(" stress.tf: stress_slow→memory_mb=192, pg_stats→timeout_sec=20") PYEOF log "--- 3d: apply всех mixed изменений ---" log " Expected: stress_divzero+chaos_echo=cache_hit, pg_counter+stress_js_async=kaniko, stress_slow+pg_stats=k8s_only" timed_op "phase3d-mixed-apply" terraform apply -auto-approve sep log "ИТОГ" sep log "Timings:" cat "$TIMINGS" 2>/dev/null | tee -a "$LOG" log "Pass: $PASS | Fail: $FAIL" log "Лог: $LOG"