#!/usr/bin/env node /** * 测试前置自检:**临时目录还有空间吗**。 * * 名字**不带 `.test.`** —— 所以它不会被 `node --test 'test/*.test.mjs'` 收进去 * 当用例跑;它由 `package.json` 的 `test` 脚本**先**跑一次。 * * # 它在挡什么 * * 2026-09-14 实测:`/tmp` 是 tmpfs,被别的项目/别的 agent 的东西占满, * `bavail` 只剩 0.70 MiB。此时 `npm test` 会红一条 * `★巨大的 message 行不进内存也不影响解析`(`ENOSPC`)—— 那条红**长得像内存缺陷**, * 而真相是环境不足。这个脚本把"环境不足"在**跑测试之前**就大声说出来。 * * # 退出码约定(与 `deploy/redeploy-plugin.sh` 同一套) * * 0 = 环境够用,继续跑测试 * 2 = **环境问题**(不是断言失败) * * 写清 `2` 的意义很关键:CI 或人看到 `1` 会去查代码,看到 `2` 才知道去查机器。 */ import { tmpdir } from 'node:os'; import { judgeSpace, measureAvailBytes, MIN_FREE_BYTES } from './tmp-space.mjs'; /* * 两个**只为测试存在**的开关(`src/pool.mjs` 的 `workerPath` 是同一手法)。 * * 为什么需要:端到端那条判据要验"不足 ⇒ exit 2",而本机 `/tmp` 现在恰好是满的。 * 靠"机器恰好是满的"来验,等于把判据绑在一个**会变**的环境上 —— `/tmp` 一被清空, * 那条判据就自动跳过、无声失效。开关让同一个行为在任何机器上都验得了。 * * --measure= 只量并打印 JSON(`{"dir":…,"availBytes":…}`),总是 exit 0 * --inject-avail= 绕过测量,直接按 `n` 字节判定(`null` 表示"没测到") */ const argOf = (name) => { const hit = process.argv.find((a) => a.startsWith(`--${name}=`)); return hit ? hit.slice(name.length + 3) : undefined; }; /** 未知参数一律拒绝(exit 2,与"环境/参数问题"同义)。 * 静默忽略未知参数会让 `--inject-avail=abc` 这类笔误退化成"没测到 ⇒ 放行" —— * 在这条链上就等于**悄悄跳过守卫**。拼错参数必须炸,不能忍。 */ const KNOWN = ['--measure', '--inject-avail']; for (const a of process.argv.slice(2)) { if (!KNOWN.some((k) => a.startsWith(`${k}=`))) { console.error(`[env-preflight] 不认识这个参数:${a}\n用法:--measure= | --inject-avail=<字节数|null>`); process.exit(2); } } const measureDir = argOf('measure'); if (measureDir !== undefined) { console.log(JSON.stringify({ dir: measureDir, availBytes: measureAvailBytes(measureDir) })); process.exit(0); } const injected = argOf('inject-avail'); const dir = tmpdir(); let availBytes; if (injected === undefined) { availBytes = measureAvailBytes(dir); } else if (injected === 'null') { availBytes = null; } else { availBytes = Number(injected); // `Number('abc')` = NaN ⇒ 判据会当成"没测到"而**放行**。笔误在这条链上等于跳过守卫, // 所以非法值按参数错误处理(exit 2),不给它静默放行的机会。 if (!Number.isFinite(availBytes) || availBytes < 0) { console.error(`[env-preflight] --inject-avail 的值不合法:${injected}(要字节数或 null)`); process.exit(2); } } const verdict = judgeSpace({ availBytes }); if (verdict.ok) { console.log(`[env-preflight] 临时目录 ${dir}:${verdict.note}`); process.exit(0); } console.error(` [env-preflight] 环境不足:临时目录写不下,**这是环境不足,不是断言失败**。 目录 ${dir} 可用 ${(availBytes / 1048576).toFixed(1)} MiB 需要 ${(MIN_FREE_BYTES / 1048576).toFixed(1)} MiB 判定 ${verdict.note} 测试用例会往临时目录写十几 MiB 的文件。空间不够时它报的是 ENOSPC, 而那看起来像代码缺陷 —— 曾经就是这么误导过一次。 药方(任选其一): TMPDIR=<有空间的目录> npm test # 换临时目录,最省事 清理 ${dir} 下不属于你的东西之前先问主人 # 别误删别人的缓存 退出码 2 = 环境问题(与 deploy/redeploy-plugin.sh 的 2 同义),不是代码问题。 `); process.exit(2);