fix(tests): bump PGLite hook timeouts to 60s for parallel-load stability

Six test files spin up PGLite + 20 migrations + git repos in beforeEach/
beforeAll hooks. Under 136-way parallel test file execution, bun's default
5s hook timeout wasn't enough, producing 18 flaky failures that only
reproduced under full-suite parallel load (all 6 files passed in isolation).

Root cause: PGLite.create() + initSchema() takes ~3-5s under idle load, but
under 136 concurrent WASM instantiations the OS thrashes and hooks stall
well past 5s. The bunfig.toml `timeout = 60_000` applies to TESTS, not HOOKS
— bun requires per-hook timeouts as the third beforeEach/beforeAll argument.

Files touched (hook timeouts added, no test logic changed):
- test/dream.test.ts           — 5 describe blocks × before/afterEach
- test/orphans.test.ts         — 1 beforeEach + afterEach
- test/core/cycle.test.ts      — shared beforeAll + afterAll
- test/brain-allowlist.test.ts — beforeAll + afterAll
- test/extract-db.test.ts      — beforeAll + afterAll
- test/multi-source-integration.test.ts — beforeAll + afterAll

Results: 2317 pass / 0 fail (was 2253 pass / 18 fail).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-23 22:37:37 -07:00
co-authored by Claude Opus 4.7
parent 423eba6883
commit 626aebf405
6 changed files with 20 additions and 20 deletions
+2 -2
View File
@@ -27,11 +27,11 @@ beforeAll(async () => {
engine = new PGLiteEngine();
await engine.connect({ database_url: '' });
await engine.initSchema();
});
}, 60_000);
afterAll(async () => {
await engine.disconnect();
});
}, 60_000);
beforeEach(async () => {
await engine.executeRaw('DELETE FROM pages');
+2 -2
View File
@@ -135,11 +135,11 @@ beforeAll(async () => {
sharedEngine = new PGLiteEngine();
await sharedEngine.connect({});
await sharedEngine.initSchema();
});
}, 60_000);
afterAll(async () => {
await sharedEngine.disconnect();
});
}, 60_000);
beforeEach(() => {
lintCalls = [];
+10 -10
View File
@@ -55,12 +55,12 @@ describe('runDream — brainDir resolution', () => {
beforeEach(async () => {
repo = makeGitRepo();
engine = await makePGLite();
});
}, 60_000);
afterEach(async () => {
await engine.disconnect();
rmSync(repo, { recursive: true, force: true });
});
}, 60_000);
test('explicit --dir takes precedence over engine config', async () => {
await engine.setConfig('sync.repo_path', '/configured/dir');
@@ -112,12 +112,12 @@ describe('runDream — --phase <name> restricts the cycle', () => {
beforeEach(async () => {
repo = makeGitRepo();
engine = await makePGLite();
});
}, 60_000);
afterEach(async () => {
await engine.disconnect();
rmSync(repo, { recursive: true, force: true });
});
}, 60_000);
test('--phase lint produces a report with exactly one phase = lint', async () => {
const report = await runDream(engine, ['--dir', repo, '--phase', 'lint', '--json']);
@@ -160,12 +160,12 @@ describe('runDream — output format', () => {
beforeEach(async () => {
repo = makeGitRepo();
engine = await makePGLite();
});
}, 60_000);
afterEach(async () => {
await engine.disconnect();
rmSync(repo, { recursive: true, force: true });
});
}, 60_000);
test('--json emits parsable CycleReport JSON with schema_version', async () => {
const lines: string[] = [];
@@ -198,12 +198,12 @@ describe('runDream — dry-run propagates through to runCycle', () => {
beforeEach(async () => {
repo = makeGitRepo();
engine = await makePGLite();
});
}, 60_000);
afterEach(async () => {
await engine.disconnect();
rmSync(repo, { recursive: true, force: true });
});
}, 60_000);
test('--dry-run produces a report where no DB-mutating work happened', async () => {
// Before: empty pages table.
@@ -227,12 +227,12 @@ describe('runDream — exit-code semantics', () => {
beforeEach(async () => {
repo = makeGitRepo();
engine = await makePGLite();
});
}, 60_000);
afterEach(async () => {
await engine.disconnect();
rmSync(repo, { recursive: true, force: true });
});
}, 60_000);
test('clean/ok/partial statuses do not call process.exit', async () => {
const spy = spyOn(process, 'exit').mockImplementation(() => { throw new Error('UNEXPECTED_EXIT'); });
+2 -2
View File
@@ -19,11 +19,11 @@ beforeAll(async () => {
engine = new PGLiteEngine();
await engine.connect({});
await engine.initSchema();
});
}, 60_000);
afterAll(async () => {
await engine.disconnect();
});
}, 60_000);
async function truncateAll() {
for (const t of ['content_chunks', 'links', 'tags', 'raw_data', 'timeline_entries', 'page_versions', 'ingest_log', 'pages']) {
+2 -2
View File
@@ -27,11 +27,11 @@ beforeAll(async () => {
engine = new PGLiteEngine();
await engine.connect({ type: 'pglite' } as never);
await engine.initSchema();
});
}, 60_000);
afterAll(async () => {
await engine.disconnect();
});
}, 60_000);
describe('v0.18.0 — sources table seeded with default row on fresh PGLite', () => {
test("sources('default') exists after initSchema + migration", async () => {
+2 -2
View File
@@ -216,11 +216,11 @@ describe('findOrphans (engine-injected)', () => {
engine = new PGLiteEngine();
await engine.connect({});
await engine.initSchema();
});
}, 60_000);
afterEach(async () => {
await engine.disconnect();
});
}, 60_000);
test('returns pages with no inbound links, excluding pseudo-pages', async () => {
// Build a tiny brain: alice links to bob. alice is an orphan (nothing