crash-loop-breaker.integration.test.ts39 lines · main
1// Integration test for CLAUDE.md §7.4 — after `crashLoopThreshold`
2// consecutive crashes within `crashLoopWindowMs` for the same
3// (projectId, deploymentId), the breaker trips and subsequent invokes
4// short-circuit with `deployment_unhealthy` until the window expires.
5// We confirm: (a) the early invocations crash and surface
6// `isolate_crashed`, (b) by the 5th call the breaker has tripped and
7// returns `deployment_unhealthy` without spawning a new isolate.
8
9import { describe, expect, test } from 'bun:test';
10
11import { runFixtureRepeated } from './test-helpers.js';
12
13describe('crash-loop breaker (integration)', () => {
14 test('after 3 consecutive crashes, deployment marked unhealthy', async () => {
15 const { results, cleanup } = await runFixtureRepeated({
16 fnName: 'v',
17 deploymentId: 'd1',
18 count: 5,
19 fnSource: `
20 import { query } from '@briven/cli/server';
21 export const v = query(async () => { Deno.exit(1); });
22 `,
23 });
24 try {
25 expect(results.length).toBe(5);
26 const codes = results.filter((r) => !r.ok).map((r) => (r as { code: string }).code);
27 // First few should be isolate_crashed; later ones should flip to deployment_unhealthy.
28 expect(codes).toContain('isolate_crashed');
29 // Last invocation should be the breaker tripped.
30 const last = results[results.length - 1];
31 expect(last.ok).toBe(false);
32 if (!last.ok) {
33 expect(last.code).toBe('deployment_unhealthy');
34 }
35 } finally {
36 await cleanup();
37 }
38 }, 60_000);
39});