freellmapi / server /src /__tests__ /lib /process-safety-net.test.ts
Nryn215's picture
Deploy: Enable and enforce pure ELO-based Intelligence routing strategy
ed57015
Raw
History Blame Contribute Delete
2.81 kB
import { describe, it, expect, vi } from 'vitest';
import {
isTransportError,
classifyProcessError,
handleProcessError,
} from '../../lib/process-safety-net.js';
describe('isTransportError', () => {
it('matches Node socket error codes', () => {
expect(isTransportError(Object.assign(new Error('read ECONNRESET'), { code: 'ECONNRESET' }))).toBe(true);
expect(isTransportError(Object.assign(new Error('x'), { code: 'ETIMEDOUT' }))).toBe(true);
expect(isTransportError(Object.assign(new Error('x'), { code: 'EPIPE' }))).toBe(true);
});
it('matches undici codes nested under err.cause (the late-error shape)', () => {
const err = Object.assign(new TypeError('fetch failed'), {
cause: Object.assign(new Error('other side closed'), { code: 'UND_ERR_SOCKET' }),
});
expect(isTransportError(err)).toBe(true);
});
it('matches by message hint when no code is present', () => {
expect(isTransportError(new Error('terminated'))).toBe(true);
expect(isTransportError(new TypeError('fetch failed'))).toBe(true);
expect(isTransportError(new Error('socket hang up'))).toBe(true);
});
it('does NOT match genuine programming bugs', () => {
expect(isTransportError(new TypeError("Cannot read properties of undefined (reading 'x')"))).toBe(false);
expect(isTransportError(Object.assign(new Error('assert'), { code: 'ERR_ASSERTION' }))).toBe(false);
expect(isTransportError(new RangeError('Maximum call stack size exceeded'))).toBe(false);
});
it('handles null / undefined / cyclic causes safely', () => {
expect(isTransportError(null)).toBe(false);
expect(isTransportError(undefined)).toBe(false);
const a: any = new Error('loop');
a.cause = a; // cycle
expect(isTransportError(a)).toBe(false);
});
});
describe('classifyProcessError', () => {
it('swallows transport errors and is fatal for everything else', () => {
expect(classifyProcessError(Object.assign(new Error('x'), { code: 'ECONNRESET' }))).toBe('swallow');
expect(classifyProcessError(new Error('real bug'))).toBe('fatal');
});
});
describe('handleProcessError', () => {
it('swallows a transport error without exiting', () => {
const exit = vi.fn();
const log = vi.fn();
const decision = handleProcessError('uncaughtException', Object.assign(new Error('x'), { code: 'ECONNRESET' }), { exit, log });
expect(decision).toBe('swallow');
expect(exit).not.toHaveBeenCalled();
expect(log).toHaveBeenCalledOnce();
});
it('exits(1) on a genuine bug, preserving fail-fast', () => {
const exit = vi.fn();
const log = vi.fn();
const decision = handleProcessError('unhandledRejection', new TypeError('boom'), { exit, log });
expect(decision).toBe('fatal');
expect(exit).toHaveBeenCalledExactlyOnceWith(1);
});
});