#!/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);