#!/bin/bash
# backup-mysql.sh 参数解析与校验的 dry-run 测试
# 不实际执行 mysqldump，仅验证参数解析、必填校验、默认值、帮助信息等。
#
# 运行方式（需要 bash 环境，如 Git Bash / WSL）：
#   bash infra/backup/test-backup-mysql.sh
#
# 退出码：0 表示全部通过，非 0 表示有失败用例。
set -uo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT="${SCRIPT_DIR}/backup-mysql.sh"

PASS=0
FAIL=0

# assertExit <expected_code> <description> <actual_code> <stderr>
assertExit() {
  local expected="$1" desc="$2" actual="$3" stderr="${4:-}"
  if [[ "$actual" == "$expected" ]]; then
    echo "[PASS] $desc (exit=$actual)"
    PASS=$((PASS + 1))
  else
    echo "[FAIL] $desc: 期望 exit=$expected, 实际 exit=$actual"
    [[ -n "$stderr" ]] && echo "       stderr: $stderr"
    FAIL=$((FAIL + 1))
  fi
}

# assertContains <needle> <description> <haystack>
assertContains() {
  local needle="$1" desc="$2" haystack="${3:-}"
  if [[ "$haystack" == *"$needle"* ]]; then
    echo "[PASS] $desc"
    PASS=$((PASS + 1))
  else
    echo "[FAIL] $desc: 输出应包含 '$needle'"
    echo "       实际输出: $haystack"
    FAIL=$((FAIL + 1))
  fi
}

echo "=== backup-mysql.sh dry-run 测试 ==="

# ---------- 用例 1: 无参数应失败并提示 --service 必填 ----------
output="$("$SCRIPT" 2>&1)"
code=$?
assertExit 1 "无参数应退出 1" "$code" "$output"
assertContains "--service 参数必填" "无参数应提示 --service 必填" "$output"

# ---------- 用例 2: --help 应退出 0 并输出 Usage ----------
output="$("$SCRIPT" --help 2>&1)"
code=$?
assertExit 0 "--help 应退出 0" "$code" "$output"
assertContains "Usage:" "--help 应输出 Usage" "$output"
assertContains "--service" "--help 应说明 --service 参数" "$output"
assertContains "--keep" "--help 应说明 --keep 参数" "$output"

# ---------- 用例 3: --keep 默认值（未提供时）应在日志中体现 7 天 ----------
# 设置 MYSQL_PASSWORD 让脚本通过环境变量校验，进入主流程打印日志；
# 随后会在 mysqldump 阶段失败（CI 环境无 mysqldump）。
output="$(MYSQL_PASSWORD=fake-pass "$SCRIPT" --service iam 2>&1)"
code=$?
assertExit 1 "无 mysqldump 时应最终退出 1" "$code" "$output"
assertContains "保留 7 天" "未提供 --keep 时应使用默认值 7 天" "$output"

# ---------- 用例 4: --keep 非数字应失败 ----------
output="$("$SCRIPT" --service iam --keep abc 2>&1)"
code=$?
assertExit 1 "--keep 非数字应退出 1" "$code" "$output"
assertContains "--keep 必须为正整数" "非数字 --keep 应报错" "$output"

# ---------- 用例 5: --keep 小于 1 应失败 ----------
output="$("$SCRIPT" --service iam --keep 0 2>&1)"
code=$?
assertExit 1 "--keep=0 应退出 1" "$code" "$output"
assertContains "--keep 必须为正整数" "--keep=0 应报错" "$output"

# ---------- 用例 6: 未知参数应失败 ----------
output="$("$SCRIPT" --service iam --unknown-flag 2>&1)"
code=$?
assertExit 1 "未知参数应退出 1" "$code" "$output"
assertContains "未知参数" "未知参数应报错" "$output"

# ---------- 用例 7: --keep 自定义值应在日志中体现 ----------
output="$(MYSQL_PASSWORD=fake-pass "$SCRIPT" --service iam --keep 30 2>&1)"
code=$?
assertExit 1 "无 mysqldump 时应最终退出 1（用例 7 预置）" "$code" "$output"
assertContains "保留 30 天" "--keep=30 应在日志中体现" "$output"

# ---------- 用例 8: MYSQL_PASSWORD 已设置但 mysqldump 不可用时应优雅失败 ----------
# 此用例验证：参数校验通过后，脚本会尝试调用 mysqldump；若 mysqldump 不存在则失败。
# 在无 MySQL 容器的 CI 环境中，这是最接近真实 dry-run 的验证。
output="$(MYSQL_PASSWORD=fake-pass "$SCRIPT" --service iam 2>&1)"
code=$?
# mysqldump 不存在时，pipefail + gzip 写入空文件 → 脚本检测到空文件后 exit 1
# 或 mysqldump 命令未找到 → set -e 触发 exit 1
# 任一路径都应是非 0 退出
if [[ "$code" -ne 0 ]]; then
  echo "[PASS] mysqldump 不可用时应非 0 退出 (exit=$code)"
  PASS=$((PASS + 1))
else
  echo "[FAIL] mysqldump 不可用时不应返回 0"
  FAIL=$((FAIL + 1))
fi

echo "=== 测试结果 ==="
echo "通过: $PASS  失败: $FAIL"
if [[ "$FAIL" -gt 0 ]]; then
  exit 1
fi
exit 0
