Files
maestro/scripts/server-startup-failure-output.test.ts
oss-sync 57702b4f34
CI / build-and-test (push) Canceled after 0s
sync: update from private repo (2336949a)
2026-09-17 11:29:31 +00:00

42 lines
2.4 KiB
TypeScript

// 起動に失敗したとき、その理由が画面に出ることを守るテスト (#1235)。
//
// 起動を断る判定は 3 行以上の本文で「なぜ止めたか」と「どう直すか」を書く。
// ところが致命的な例外は `src/main.ts` の最上位ハンドラが `err.stack` ごと
// 1 レコードで書き出すので、記録の並びは【本文】→【呼び出し位置の羅列】になる。
// `scripts/server.sh` が末尾 5 行しか出さないと、出るのは呼び出し位置だけで、
// 肝心の本文は画面から溢れる。直し方が書いてあるのに管理者には見えない。
//
// だからここで守るのは「行数の数字」ではなく、**本文が収まる幅が残っていること**。
// 末尾の行数を減らす変更は、ここで落ちる。
import { describe, it, expect } from 'vitest';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
/** 起動失敗の案内は最長で 4 行。加えてスタックの見出しと呼び出し位置が続く。 */
const MIN_TAIL_LINES = 20;
describe('起動失敗時の出力 (#1235)', () => {
it('server.sh の起動失敗は、案内の本文が収まる行数を出す', () => {
const sh = readFileSync(join(repoRoot, 'scripts', 'server.sh'), 'utf8');
const failureBlock = sh.slice(sh.indexOf('Server failed to start'));
const tail = /tail\s+(?:-n\s*)?-?(\d+)\s+"\$LOG_FILE"/.exec(failureBlock);
expect(tail).not.toBeNull();
expect(Number(tail![1])).toBeGreaterThanOrEqual(MIN_TAIL_LINES);
});
it('起動を断る本文とスタックの合計が、その行数に収まる', () => {
// 本文の行数は実物から数える。文面を伸ばしたときに、この歯止めが
// 一緒に見直されるようにするため。
const src = readFileSync(join(repoRoot, 'src', 'worker-bootstrap.ts'), 'utf8');
// throw new Error(`...`) のテンプレートリテラルに含まれる改行の数。
const refusals = src.match(/throw new Error\(\s*`[\s\S]*?\)\s*;/g) ?? [];
expect(refusals.length).toBeGreaterThan(0);
const longest = Math.max(...refusals.map((r) => (r.match(/\\n/g) ?? []).length + 1));
// スタックの見出し 1 行 + 呼び出し位置の余裕。
expect(longest + 10).toBeLessThanOrEqual(MIN_TAIL_LINES);
});
});