Files
SubMiner/src/anime-bridge/sidecar-process.test.ts
T
sudacode 301714777a fix(anime): honor the sidecar readiness deadline and confirm shutdown
The capabilities probe used a fixed 5s timeout, so a readiness budget
shorter than that could be overrun by one stalled request. Pass the
remaining deadline down instead.

stop() also resolved after the SIGKILL wait even when the child had not
exited, letting a restart race a process still holding the port. Throw
in that case, and keep a failed shutdown from masking the readiness
error at startup.
2026-08-06 21:48:00 -07:00

67 lines
2.2 KiB
TypeScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { EventEmitter } from 'node:events';
import type { spawn as spawnType, ChildProcess } from 'node:child_process';
import { allocatePort, startSidecar } from './sidecar-process';
import type { BundleBinaries } from './sidecar-bundle';
const binaries: BundleBinaries = {
javaPath: '/nonexistent/java',
jarPath: '/tmp/MExtensionServer.jar',
};
/** A ChildProcess stand-in: an EventEmitter with the bits startSidecar touches. */
function fakeChild(onKill?: (child: EventEmitter) => void): ChildProcess {
const child = new EventEmitter();
Object.assign(child, {
stdout: null,
stderr: null,
kill: () => {
onKill?.(child);
return true;
},
});
return child as unknown as ChildProcess;
}
test('a failed spawn rejects instead of throwing an unhandled error event', async () => {
const port = await allocatePort();
const child = fakeChild();
const spawnImpl = (() => {
// Node emits `error` asynchronously when the binary cannot be executed.
queueMicrotask(() => child.emit('error', new Error('spawn ENOENT')));
return child;
}) as unknown as typeof spawnType;
await assert.rejects(
() => startSidecar({ binaries, port, readyTimeoutMs: 2000, spawnImpl }),
/could not start.*ENOENT/,
);
});
test('a readiness timeout shuts the child down and reports the timeout', async () => {
const port = await allocatePort();
// Never becomes ready, but does go down on the first signal.
const child = fakeChild((emitter) => queueMicrotask(() => emitter.emit('exit', 0, 'SIGTERM')));
const spawnImpl = (() => child) as unknown as typeof spawnType;
await assert.rejects(
() => startSidecar({ binaries, port, readyTimeoutMs: 50, spawnImpl }),
/did not become ready within 50ms/,
);
});
test('an early exit is reported with its code rather than waiting out the deadline', async () => {
const port = await allocatePort();
const child = fakeChild();
const spawnImpl = (() => {
queueMicrotask(() => child.emit('exit', 1, null));
return child;
}) as unknown as typeof spawnType;
await assert.rejects(
() => startSidecar({ binaries, port, readyTimeoutMs: 2000, spawnImpl }),
/exited before becoming ready \(code 1/,
);
});