diff --git a/docs/tests/report-test823.txt b/docs/tests/report-test823.txt new file mode 100644 index 00000000..2ec740b5 --- /dev/null +++ b/docs/tests/report-test823.txt @@ -0,0 +1,36 @@ +# report-test823 — L1 concurrency cap gate + +Date: 2026-08-13 (Asia/Shanghai) +Base: 034f00647d42d38d5086d7fc057eb7824a441791 +Source: 76c12e98379b67eb074a2a42e2a170e6aa94db1f +run.sh blob: 7c4e3ebb4ecf13710d166d9a0d3f26eb43d8d9d1 (容器内就地重算并比对,不只验 SHA 格式) +Run: docker build --build-arg SOURCE_COMMIT=$SRC --build-arg RUNSH_BLOB=$BLOB … && docker run --rm --network none … +Exit: 0 + +## 本次运行 +``` +- cap=2 峰值=2 生效值=2 告警=0 + ok cap2: 生效上限 (= 2) + ok cap2: 峰值 2 ≤ 2 +- 非法值 two 峰值=8 生效值=8 告警=1 + ok bad_warn: 必须告警 (= 1) + ok bad_eff: 退回默认(不是静默不限) (= 8) +- 前导零 08 峰值=8 生效值=8 告警=0 + ok octal_eff: 按十进制解释,不是八进制报错/不限 (= 8) +- 0(不限) 峰值=13 生效值=0 告警=0 + ok zero_eff: 0 保留为「不限」的逃生口 (= 0) + ok zero_conc: 不限时峰值 13 > cap2 的 2,确实放开了并发 +failures=0 +RESULT: PASS +- cap=2 峰值=2 生效值=2 告警=0 +``` + +## 见证红(三种) +``` +1. 去掉 qa.sh 的取值校验段: + FAIL bad_warn: 必须告警 —— 期望 1,实测 0 + FAIL bad_eff: 退回默认(不是静默不限) —— 期望 8,实测 ? + FAIL octal_eff: 按十进制解释,不是八进制报错/不限 —— 期望 8,实测 08 +2. 传错的 run.sh blob 哈希 → FAIL: 镜像里的 run.sh 与 SOURCE_COMMIT 声称的不是同一份 (exit 1) +3. blob 参数对但文件被篡改 → 同上 (exit 1) +``` diff --git a/scripts/qa.sh b/scripts/qa.sh index e7135473..fbc53232 100755 --- a/scripts/qa.sh +++ b/scripts/qa.sh @@ -57,6 +57,9 @@ L0_TESTS=( # 它的 CI 归属是会安装依赖的层级;本地跑法见该文件头注释的门禁命令。 ) L1_TESTS=( + # 这道闸门自己的回归。放在最前:它跑的是本脚本,若闸门坏了应当最先暴露。 + # (注册这一步不是可选的 —— 一个没被任何东西调用的套件等于不存在。) + "test823-l1-concurrency-cap" "qa-cli-01-hub-start" "qa-cli-02-network-create" "qa-dash-07-auth-boundary" @@ -159,15 +162,35 @@ if [[ $RUN_L1 -eq 1 ]]; then for t in "${L1_TESTS[@]}"; do # Build (cached if recent) note "build $t" + # 🔴 原来这里是一串逐套件的 elif。那正是本 PR 撞红的成因: + # test823 被加进 L1_TESTS,却没人记得在这里也加一条,于是 + # TEST823_SOURCE_COMMIT 是空串,门 fail-closed: + # FAIL: TEST823_SOURCE_COMMIT 必须是一个完整的小写 SHA(收到 '') + # 「注册了套件但忘了在供给侧登记」会一直复发,所以改成按套件名推导: + # testNNN-... → --build-arg TESTNNN_SOURCE_COMMIT=
+ # qa-*-... 形态不匹配,和以前一样不传(它们的门不要这个变量)。 build_args="" - if [[ "$t" == "test686-rest-shape-golden" ]]; then - build_args="--build-arg TEST686_SOURCE_COMMIT=$(git rev-parse HEAD)" - elif [[ "$t" == "test765-batch-runtime-gate" ]]; then - build_args="--build-arg TEST765_SOURCE_COMMIT=$(git rev-parse HEAD)" - elif [[ "$t" == "test766-bunx-preflight" ]]; then - build_args="--build-arg TEST766_SOURCE_COMMIT=$(git rev-parse HEAD)" - elif [[ "$t" == "test746-setup-bun-pin" ]]; then - build_args="--build-arg TEST746_SOURCE_COMMIT=$(git rev-parse HEAD)" + if [[ "$t" =~ ^test([0-9]+)- ]]; then + # 🔴 仓里并存两套 build-arg 命名,必须都供给,否则名字对不上就是空串: + # 旧:test686/765/766/746 的 Dockerfile 收 TESTNNN_SOURCE_COMMIT + # 新:test823(以及 test798/test831)的 Dockerfile 收 SOURCE_COMMIT + RUNSH_BLOB + # 我上一版只按套件名推导出 TESTNNN_SOURCE_COMMIT,test823 收的是 SOURCE_COMMIT, + # 于是照旧红在 "TEST823_SOURCE_COMMIT 收到 ''"。 + # 未被 Dockerfile 声明的 build-arg 只会产生一条警告,不影响构建,所以两套都传。 + # 🔴 git 调用必须是非致命的。qa.sh 头部是 `set -euo pipefail`,而 test823 + # 会在一个**只装了 bash/coreutils/procps、没有 git** 的容器里重放这个脚本 + # (它桩了 docker 和 npm,但没桩 git)。上一版我直接写 $(git rev-parse HEAD), + # 容器里 git 不存在 → 127 → set -e 当场中断 → docker 桩一次都没被调用 → + # 峰值恒为 0 → 闸门自己的回归失败。这是我改出来的回归,不是被测代码的问题。 + _qa_sha="$(git rev-parse HEAD 2>/dev/null || true)" + if [ -n "$_qa_sha" ]; then + build_args="--build-arg TEST${BASH_REMATCH[1]}_SOURCE_COMMIT=$_qa_sha --build-arg SOURCE_COMMIT=$_qa_sha" + # blob 绑定:把 SOURCE_COMMIT 钉到被测的那份 run.sh 字节上(git blob object id) + if [ -f "tests/$t/run.sh" ]; then + _qa_blob="$(git rev-parse "HEAD:tests/$t/run.sh" 2>/dev/null || true)" + [ -n "$_qa_blob" ] && build_args="$build_args --build-arg RUNSH_BLOB=$_qa_blob" + fi + fi fi if ! dockerrun "docker build -q $build_args -t anet-$t -f tests/$t/Dockerfile ." >/tmp/qa-l1-$t-build.log 2>&1; then fail "L1 $t — build failed, see /tmp/qa-l1-$t-build.log" diff --git a/tests/test823-l1-concurrency-cap/Dockerfile b/tests/test823-l1-concurrency-cap/Dockerfile new file mode 100644 index 00000000..5de27696 --- /dev/null +++ b/tests/test823-l1-concurrency-cap/Dockerfile @@ -0,0 +1,23 @@ +ARG SOURCE_COMMIT +FROM node:22-bookworm-slim + +RUN apt-get update \ + && apt-get install -y --no-install-recommends bash ca-certificates coreutils procps \ + && rm -rf /var/lib/apt/lists/* + +ARG SOURCE_COMMIT +ARG RUNSH_BLOB +ENV TEST823_SOURCE_COMMIT=${SOURCE_COMMIT} +# 把 run.sh 在 SOURCE_COMMIT 下的 git blob 哈希带进来,让容器内能验证 +# "报告里的 SHA 确实对应镜像里被测的字节",而不是只验 SHA 的格式。 +ENV TEST823_RUNSH_BLOB=${RUNSH_BLOB} + +WORKDIR /workspace +COPY scripts/qa.sh /workspace/scripts/qa.sh +COPY tests/test823-l1-concurrency-cap/run.sh /workspace/run.sh + +# 非 root:与本仓其它套件一致 +RUN chown -R node:node /workspace +USER node + +ENTRYPOINT ["bash", "/workspace/run.sh"] diff --git a/tests/test823-l1-concurrency-cap/run.sh b/tests/test823-l1-concurrency-cap/run.sh new file mode 100755 index 00000000..7c4e3ebb --- /dev/null +++ b/tests/test823-l1-concurrency-cap/run.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash +# test823 — scripts/qa.sh 的 L1 并发上限闸门 +# +# 这道闸门的失效方向是 fail-open:QA_L1_MAX_PAR 拿到非数字时,bash 在算术 +# 上下文里把它当 0,而 0 的语义恰好是「不限」—— 于是一个笔误会静默恢复 +# 无上限运行。无上限时实测宿主 load1 顶到 58(8 核,同时跑着生产 hub、 +# dashboard 与约 200 个 session),所以这条不是形式主义。 +# +# 🔴 本套件跑的是**真的 scripts/qa.sh**,不是逻辑副本。 +# 做法:把 `docker` 换成 PATH 上的桩。qa.sh 的 dockerrun() 是 +# `bash -c "$*"`,所以它会解析到桩;真实的闸门代码原样执行。 +# 在副本上测只能证明副本自洽 —— 那正是本仓反复栽过的坑。 +# +# 峰值用**事件流**算,不用采样:每次桩调用写下精确的 START / END 纳秒 +# 时间戳,事后排序求最大重叠。采样会漏掉峰值,事件流不会。 +set -uo pipefail + +ROOT=/workspace +SRC=${TEST823_SOURCE_COMMIT:-} +[[ "$SRC" =~ ^[0-9a-f]{40}$ ]] || { echo "FAIL: TEST823_SOURCE_COMMIT 必须是一个完整的小写 SHA(收到 '${SRC}')" >&2; exit 1; } + +# 🔴 光验格式不够 —— 任何 40 位十六进制都能通过,而报告里那个 SHA 可能 +# 根本不含镜像里被测的文件。这正是 #801 上那条 P1 说的病,我建这个 +# 套件时原样犯了一遍。 +# 做法:构建时把 run.sh 在该 commit 下的 git blob 哈希作为 build-arg +# 传进来,这里就地重算镜像内文件的 blob 哈希并比对。git blob 哈希 = +# sha1("blob