test.ts
Raw
1import { readdirSync } from 'fs';
2import { spawn } from 'child_process';
3import path from 'path';
4
5const testsDir = path.resolve('tests');
6const files = readdirSync(testsDir)
7 .filter(f => f.endsWith('.test.ts'))
8 .sort();
9
10const STALL_TIMEOUT = 20_000; // kill if no output for 20s
11const MAX_RETRIES = 3;
12// retry logic needed because tests get randomly get stuck on startup with bun
13// strace shows bun completely spinning in futex and not doing anything else.
14// Only a stall-kill is retried — a genuine assertion failure returns
15// {ok: false, stalled: false} and must NOT be retried, or a real product bug
16// that fails intermittently would be laundered into a pass.
17function runTest(filePath: string): Promise<{ ok: boolean; stalled: boolean }> {
18 return new Promise((resolve) => {
19 const child = spawn('bun', ['test', '--bail=1', '--timeout', '30000', filePath], {
20 stdio: ['ignore', 'pipe', 'pipe'],
21 });
22
23 let stalled = false;
24 let timer = setTimeout(onStall, STALL_TIMEOUT);
25
26 function onStall() {
27 stalled = true;
28 console.error(`\n[test-runner] stall detected, killing ${path.basename(filePath)} (no output for ${STALL_TIMEOUT / 1000}s)`);
29 child.kill('SIGKILL');
30 }
31
32 function resetTimer() {
33 clearTimeout(timer);
34 timer = setTimeout(onStall, STALL_TIMEOUT);
35 }
36
37 child.stdout!.on('data', (chunk: Buffer) => {
38 process.stdout.write(chunk);
39 resetTimer();
40 });
41 child.stderr!.on('data', (chunk: Buffer) => {
42 process.stderr.write(chunk);
43 resetTimer();
44 });
45
46 child.on('close', (code) => {
47 clearTimeout(timer);
48 resolve({ ok: code === 0, stalled });
49 });
50 });
51}
52
53let passed = 0;
54let failed = 0;
55
56for (const file of files) {
57 const filePath = path.join(testsDir, file);
58 let ok = false;
59
60 for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
61 if (attempt > 1) {
62 console.log(`[test-runner] retrying ${file} (attempt ${attempt}/${MAX_RETRIES})`);
63 }
64 const result = await runTest(filePath);
65 ok = result.ok;
66 // Retry only the futex stall — a genuine failure is final.
67 if (ok || !result.stalled) break;
68 }
69
70 if (ok) passed++;
71 else failed++;
72}
73
74console.log(`\n${passed + failed} test files: ${passed} passed${failed ? `, ${failed} failed` : ''}`);
75if (failed > 0) process.exit(1);
76