#!/bin/sh # # run_tests.sh — meow_ntpsync 宿主沙箱单测(M22) # # 不碰真机、不联网:用假的 ntpd / hwclock / 网络探测注入, # 验证「成功 / 超时 / 失败 / 网络未就绪 / 短路 / 返回码」这些分支。 # # 用法: sh patch_v2/ntpsync/tests/run_tests.sh [meow_ntpsync 路径] # set -u HERE=$(cd "$(dirname "$0")" && pwd) SUT=${1:-"$HERE/../meow_ntpsync"} W=$(mktemp -d) trap 'rm -rf "$W"' EXIT PASS=0 FAIL=0 ok() { PASS=$((PASS + 1)); printf ' ok %s\n' "$1"; } bad() { FAIL=$((FAIL + 1)); printf ' FAIL %s\n' "$1"; } check(){ if [ "$2" = "$3" ]; then ok "$1"; else bad "$1 (want=$3 got=$2)"; fi; } # ---- 假 ntpd:行为由 MODE 决定 ---- cat >"$W/ntpd" <<'EOF' #!/bin/sh echo "invoked $(date +%s)" >> "$FAKE_NTPD_CALLS" # 断言调用方必须给 -c <临时配置> case " $* " in *" -c "*) : ;; *) echo "no -c" >&2; exit 9 ;; esac case "$FAKE_NTPD_MODE" in ok) echo "ntpd: time set +1.000000 s"; exit 0 ;; fail) echo "ntpd: no server suitable" >&2; exit 3 ;; hang) sleep 30; exit 0 ;; slew) echo "ntpd: time slew +0.000042 s"; exit 0 ;; esac exit 1 EOF chmod +x "$W/ntpd" # ---- 假 hwclock ---- cat >"$W/hwclock" <<'EOF' #!/bin/sh echo "$*" >> "$FAKE_HWCLOCK_CALLS" [ "$FAKE_HWCLOCK_MODE" = fail ] && exit 1 exit 0 EOF chmod +x "$W/hwclock" # 每种模式都跑在一个干净的沙箱里 run_case() { # $1=名字 其余=meow_ntpsync 参数;通过环境变量控制 name=$1 shift CALLS="$W/calls.$name" HW="$W/hw.$name" : >"$CALLS" : >"$HW" export FAKE_NTPD_CALLS="$CALLS" FAKE_HWCLOCK_CALLS="$HW" export MEOW_NTPD="$W/ntpd" MEOW_HWCLOCK="$W/hwclock" export MEOW_NTPSYNC_STATE="$W/state.$name" MEOW_NTPSYNC_LOCK="$W/lock.$name" export MEOW_NTPSYNC_LOG="$W/log.$name" export MEOW_NTPSYNC_ATTEMPT_TIMEOUT="${CASE_TIMEOUT:-2}" } echo "== meow_ntpsync 沙箱单测 ($SUT)" # 1) 正常同步 rm -f "$W/state.1" run_case 1 FAKE_NTPD_MODE=ok MEOW_NETCHECK=true sh "$SUT"; rc=$? check "同步成功返回 0" "$rc" 0 check "hwclock 被调用一次" "$(wc -l <"$W/hw.1" | tr -d ' ')" 1 check "hwclock 参数为 -w -u" "$(cat "$W/hw.1")" "-w -u" check "写了 state(epoch)" "$(grep -c '^epoch=' "$W/state.1" 2>/dev/null || echo 0)" 1 # 1b) 单独验证 gen_conf 的内容(截获 -c 指向的文件) cat >"$W/ntpd2" <<'EOF' #!/bin/sh while [ $# -gt 0 ]; do [ "$1" = "-c" ] && cp "$2" "$FAKE_CONF_DUMP"; shift; done exit 0 EOF chmod +x "$W/ntpd2" rm -f "$W/state.1b" run_case 1b FAKE_CONF_DUMP="$W/conf.1b" MEOW_NTPD="$W/ntpd2" FAKE_NTPD_MODE=ok MEOW_NETCHECK=true sh "$SUT" check "配置每个 server 都带 iburst" \ "$(grep -c '^server .* iburst$' "$W/conf.1b" 2>/dev/null)" \ "$(grep -c '^server ' "$W/conf.1b" 2>/dev/null)" # 2) ntpd 挂死 → 看门狗必须杀掉并返回 1 run_case 2 t0=$(date +%s) FAKE_NTPD_MODE=hang MEOW_NETCHECK=true sh "$SUT"; rc=$? t1=$(date +%s); el=$((t1 - t0)) check "挂死返回 1" "$rc" 1 if [ "$el" -ge 2 ] && [ "$el" -le 6 ]; then ok "看门狗在 2~6s 内掐断 (实测 ${el}s)" else bad "看门狗时长异常 (实测 ${el}s, 期望 2~6s)"; fi check "挂死不写 RTC" "$(wc -l <"$W/hw.2" | tr -d ' ')" 0 # 3) ntpd 明确失败 → 返回 1,不写 RTC run_case 3 FAKE_NTPD_MODE=fail MEOW_NETCHECK=true sh "$SUT"; rc=$? check "失败返回 1" "$rc" 1 check "失败不写 RTC" "$(wc -l <"$W/hw.3" | tr -d ' ')" 0 # 4) 单次模式网络未就绪 → 立刻返回 1,且不去打 ntpd run_case 4 t0=$(date +%s) FAKE_NTPD_MODE=ok MEOW_NETCHECK=false sh "$SUT"; rc=$? t1=$(date +%s); el=$((t1 - t0)) check "网络未就绪返回 1" "$rc" 1 check "网络未就绪不调 ntpd" "$(wc -l <"$W/calls.4" | tr -d ' ')" 0 if [ "$el" -le 2 ]; then ok "单次模式不做无谓等待 (${el}s)"; else bad "单次模式等了 ${el}s"; fi # 5) 开机模式:网络一直不来,-t 3 → 按时退出 run_case 5 t0=$(date +%s) FAKE_NTPD_MODE=ok MEOW_NETCHECK=false sh "$SUT" -b -t 3; rc=$? t1=$(date +%s); el=$((t1 - t0)) check "开机模式超时返回 1" "$rc" 1 if [ "$el" -ge 3 ] && [ "$el" -le 8 ]; then ok "开机模式在 -t 内退出 (${el}s)" else bad "开机模式退出时长异常 (${el}s)"; fi # 6) 开机模式:网络晚到 → 仍能同步成功 cat >"$W/latecheck" <<'EOF' #!/bin/sh n=$(cat "$LATE_FILE" 2>/dev/null || echo 0) n=$((n + 1)); echo "$n" >"$LATE_FILE" [ "$n" -gt 2 ] EOF chmod +x "$W/latecheck" rm -f "$W/late.n" "$W/state.6" run_case 6 LATE_FILE="$W/late.n" FAKE_NTPD_MODE=ok MEOW_NETCHECK="$W/latecheck" sh "$SUT" -b -t 20; rc=$? check "网络晚到仍返回 0" "$rc" 0 # 7) 非法参数 sh "$SUT" --bogus >/dev/null 2>&1; check "未知参数返回 2" "$?" 2 sh "$SUT" -t abc >/dev/null 2>&1; check "非数字 -t 返回 2" "$?" 2 # 8) 1h 内已同步 → 短路,不调 ntpd run_case 8 echo "epoch=$(date +%s)" >"$W/state.8" FAKE_NTPD_MODE=ok MEOW_NETCHECK=true sh "$SUT"; rc=$? check "已同步短路返回 0" "$rc" 0 check "短路不调 ntpd" "$(wc -l <"$W/calls.8" | tr -d ' ')" 0 # 9) RTC 写失败:时间已对,返回 0,但日志要留痕 rm -f "$W/state.9" run_case 9 FAKE_NTPD_MODE=slew FAKE_HWCLOCK_MODE=fail MEOW_NETCHECK=true sh "$SUT"; rc=$? check "RTC 写失败仍返回 0" "$rc" 0 check "日志记录 RTC 写失败" "$(grep -c 'rtc write FAILED' "$W/log.9" 2>/dev/null)" 1 # 10) -S 打印状态 run_case 10 echo "epoch=12345" >"$W/state.10" out=$(sh "$SUT" -S) check "-S 打印上次记录" "$(echo "$out" | grep -c '^epoch=12345$')" 1 echo echo "== 结果: PASS=$PASS FAIL=$FAIL" [ "$FAIL" -eq 0 ] || exit 1