| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- #!/usr/bin/env bash
- # S8-REGRESSION-FIXTURE-1 统一回归 driver(dev/test only, aidopdev)。
- #
- # 顺序运行子脚本,统一汇总 PASS / SKIP / FAIL:
- # 1. sched-exec-regression.sh — 调度执行 + antiflap + DetectionLog 主链
- # 2. r2-timeout-regression.sh — TIMEOUT 主链(默认复用 demo rule 10)
- # 3. r3-shortage-regression.sh — SHORTAGE 主链(当前 dev 无 demo SHORTAGE,SKIP)
- # 4. r3-out-of-range-regression.sh — OUT_OF_RANGE 主链(默认复用 demo rule 11)
- # 5. r6-detection-log-edge-regression.sh — NO_HIT/EVALUATE_FAILED edge
- # 6. recovered-edge-regression.sh — RECOVERED 主链 + recover_count_required 抗抖
- # 7. active-exception-id-trigger1-regression.sh — trigger=1 首 tick state.active_exception_id 回填
- #
- # 退出码:
- # - 仅 FAIL>0 时 exit 1;
- # - 全 PASS 或 PASS+SKIP 混合(FAIL=0)→ exit 0;
- # - 致命错误(mysql/auth)→ exit 2。
- set -uo pipefail
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
- # shellcheck source=./s8-regression-common.sh
- source "${SCRIPT_DIR}/s8-regression-common.sh"
- TOTAL_PASS=0
- TOTAL_FAIL=0
- TOTAL_SKIP=0
- declare -a CHILD_RESULTS
- # 入场前快照 demo rule 初态(disabled,CTO 决策默认值);末态比对此快照而不是硬编码 enabled=1。
- DEMO_INITIAL_SNAPSHOT=$(snapshot_demo_rule_state)
- baseline_before=$(read_baseline)
- echo "============================================================"
- echo "S8 Regression Driver"
- echo " baseline_before=${baseline_before}"
- echo " demo_initial_snapshot=${DEMO_INITIAL_SNAPSHOT}"
- echo "============================================================"
- # trap:异常退出(child fail / Ctrl+C / SIGTERM)也必须恢复 demo rule disabled 并清 ghost。
- # 正常路径会在 trap 触发前显式调用 restore,trap 二次调用是幂等的。
- RESTORED_DEMO=0
- on_exit() {
- if [[ "${RESTORED_DEMO}" == "0" ]]; then
- cleanup_temp_sched_approval_ghost_tasks 2>/dev/null || true
- restore_demo_rules_disabled_after_regression 2>/dev/null || true
- RESTORED_DEMO=1
- fi
- }
- trap on_exit EXIT INT TERM
- # 入场 arm:CTO 决策"demo rule 默认关闭",回归期间临时启用以驱动 r2/r3-oor 等子链。
- arm_demo_rules_for_regression
- # 每个 child 结束后调用:
- # 1. 关闭 TEMP_SCHED_% 残留(防跨 child 状态污染);
- # 2. 软删 TEMP_SCHED_% 的活跃异常;
- # 3. cleanup_temp_sched_approval_ghost_tasks:取消 TEMP 软删后遗留的 Pending 审批任务。
- # 不清除 demo rule 10/11/12、DEMO-S2/S3 数据、或真实业务 exception。
- # 不动 detection_state:避免与 Job scheduler 并发竞态破坏 active_exception_id 回填。
- # 各 child 自身负责 setup 阶段清自己的 detection_state。
- cleanup_between_children() {
- local label="$1"
- mysql_run "UPDATE ado_s8_watch_rule SET enabled=0, lock_token=NULL, locked_by=NULL, lock_until=NULL, updated_at=NOW() WHERE rule_code LIKE 'TEMP_SCHED_%' AND tenant_id=${TENANT_ID} AND factory_id=${FACTORY_ID} AND enabled=1;" 2>/dev/null || true
- mysql_run "UPDATE ado_s8_exception SET is_deleted=1, updated_at=NOW() WHERE source_rule_code LIKE 'TEMP_SCHED_%' AND is_deleted=0;" 2>/dev/null || true
- cleanup_temp_sched_approval_ghost_tasks 2>/dev/null || true
- echo "[teardown] after ${label}: TEMP_SCHED_% disabled + active exceptions soft-deleted + ghost approval cancelled"
- }
- run_child() {
- local label="$1"
- local script="$2"
- if [[ ! -x "${script}" ]]; then
- echo "[${label}] SKIP — script not executable: ${script}"
- TOTAL_SKIP=$((TOTAL_SKIP + 1))
- CHILD_RESULTS+=("${label}: SKIP (not executable)")
- return 0
- fi
- echo
- echo "===> [${label}] ${script}"
- local out
- local rc=0
- set +e
- out=$(bash "${script}" 2>&1)
- rc=$?
- set -e
- echo "${out}"
- local p f s
- p=$(printf '%s\n' "${out}" | grep -c '^PASS:' || true)
- f=$(printf '%s\n' "${out}" | grep -c '^FAIL:' || true)
- s=$(printf '%s\n' "${out}" | grep -c '^SKIP:' || true)
- TOTAL_PASS=$((TOTAL_PASS + p))
- TOTAL_FAIL=$((TOTAL_FAIL + f))
- TOTAL_SKIP=$((TOTAL_SKIP + s))
- local status
- if [[ "${rc}" == "0" && "${f}" == "0" ]]; then
- if [[ "${p}" == "0" && "${s}" -gt 0 ]]; then
- status="SKIP"
- else
- status="PASS"
- fi
- else
- status="FAIL"
- fi
- CHILD_RESULTS+=("${label}: ${status} (pass=${p} fail=${f} skip=${s} rc=${rc})")
- echo "[${label}] result: ${status} pass=${p} fail=${f} skip=${s} rc=${rc}"
- cleanup_between_children "${label}"
- }
- run_child "sched-exec" "${SCRIPT_DIR}/sched-exec-regression.sh"
- run_child "r2-timeout" "${SCRIPT_DIR}/r2-timeout-regression.sh"
- run_child "r3-shortage" "${SCRIPT_DIR}/r3-shortage-regression.sh"
- run_child "r3-oor" "${SCRIPT_DIR}/r3-out-of-range-regression.sh"
- run_child "r6-edge" "${SCRIPT_DIR}/r6-detection-log-edge-regression.sh"
- run_child "recovered" "${SCRIPT_DIR}/recovered-edge-regression.sh"
- run_child "trigger1-active" "${SCRIPT_DIR}/active-exception-id-trigger1-regression.sh"
- run_child "oor-shortage-edge" "${SCRIPT_DIR}/oor-shortage-edge-regression.sh"
- # 显式 restore(trap 是兜底,正常路径走这里;幂等)。
- cleanup_temp_sched_approval_ghost_tasks
- restore_demo_rules_disabled_after_regression
- RESTORED_DEMO=1
- baseline_after=$(read_baseline)
- echo
- echo "============================================================"
- echo "Driver Summary"
- echo "============================================================"
- echo "baseline_before=${baseline_before}"
- echo "baseline_after=${baseline_after}"
- if [[ "${baseline_before}" == "${baseline_after}" ]]; then
- echo "baseline: UNCHANGED"
- else
- echo "baseline: DRIFTED (${baseline_before} -> ${baseline_after})"
- TOTAL_FAIL=$((TOTAL_FAIL + 1))
- fi
- # 验证 demo rule 10/11/12 末态 = 入场前快照(业务侧 enabled=0 不漂移)。
- demo_state_after=$(snapshot_demo_rule_state)
- echo "demo_rule_state_initial=${DEMO_INITIAL_SNAPSHOT}"
- echo "demo_rule_state_final =${demo_state_after}"
- if [[ "${demo_state_after}" == "${DEMO_INITIAL_SNAPSHOT}" ]]; then
- echo "demo rule 10/11/12: RESTORED to initial state (CTO policy: default off)"
- else
- echo "demo rule 10/11/12: DRIFTED from initial (initial=${DEMO_INITIAL_SNAPSHOT} final=${demo_state_after})"
- TOTAL_FAIL=$((TOTAL_FAIL + 1))
- fi
- # 验证 TEMP_SCHED_TIMEOUT_ANTIFLAP 收尾态
- temp_state=$(mysql_run "SELECT IFNULL(GROUP_CONCAT(CONCAT(id,':',enabled)),'absent') FROM ado_s8_watch_rule WHERE rule_code='TEMP_SCHED_TIMEOUT_ANTIFLAP';")
- temp_visible=$(mysql_run "SELECT COUNT(*) FROM ado_s8_exception WHERE source_rule_code='TEMP_SCHED_TIMEOUT_ANTIFLAP' AND is_deleted=0;")
- echo "temp_rule_state=${temp_state} temp_active_in_default_list=${temp_visible}"
- echo
- echo "Per-child:"
- for r in "${CHILD_RESULTS[@]}"; do
- echo " - ${r}"
- done
- echo
- echo "Used fixtures:"
- echo " - DEMO_ORDER_DELIVERY_TIMEOUT (rule id=10)"
- echo " - DEMO_ORDER_DIMENSION_OOR (rule id=11)"
- echo " - TEMP_SCHED_TIMEOUT_ANTIFLAP (TEMP fixture, post-test enabled=0)"
- echo " - SHORTAGE / G01_TEST_* (absent → SKIP)"
- echo
- echo "Totals: passed=${TOTAL_PASS} failed=${TOTAL_FAIL} skipped=${TOTAL_SKIP}"
- if (( TOTAL_FAIL > 0 )); then
- echo "Driver result: FAIL"
- exit 1
- fi
- echo "Driver result: PASS (FAIL=0)"
- exit 0
|