mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-07 12:18:44 +02:00
tests: some additional tests
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import { EventEmitter } from 'node:events';
|
||||
|
||||
import { describe, expect, mock, test } from 'bun:test';
|
||||
|
||||
import type { SidecarCapabilities } from '@shared/contracts/sidecar';
|
||||
|
||||
class FakeReadableStream extends EventEmitter {
|
||||
setEncoding(_encoding: BufferEncoding): void {}
|
||||
}
|
||||
|
||||
class FakeWritableStream {
|
||||
readonly writes: string[] = [];
|
||||
|
||||
write(chunk: string): boolean {
|
||||
this.writes.push(chunk);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class FakeChildProcess extends EventEmitter {
|
||||
readonly stdout = new FakeReadableStream();
|
||||
readonly stderr = new FakeReadableStream();
|
||||
readonly stdin = new FakeWritableStream();
|
||||
exitCode: number | null = null;
|
||||
killed = false;
|
||||
|
||||
kill(): boolean {
|
||||
this.killed = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
emitStdout(line: string): void {
|
||||
this.stdout.emit('data', line);
|
||||
}
|
||||
|
||||
completeExit(code = 0): void {
|
||||
this.exitCode = code;
|
||||
this.emit('exit', code, null);
|
||||
this.emit('close', code, null);
|
||||
}
|
||||
}
|
||||
|
||||
const spawnedProcesses: FakeChildProcess[] = [];
|
||||
|
||||
mock.module('electron', () => ({
|
||||
app: {
|
||||
isPackaged: false,
|
||||
getAppPath: () => 'C:\\workspace\\personal\\repositories\\eryx',
|
||||
},
|
||||
}));
|
||||
|
||||
mock.module('node:child_process', () => ({
|
||||
spawn: () => {
|
||||
const child = new FakeChildProcess();
|
||||
spawnedProcesses.push(child);
|
||||
return child;
|
||||
},
|
||||
}));
|
||||
|
||||
const { SidecarClient } = await import('@main/sidecar/sidecarProcess');
|
||||
|
||||
const CAPABILITIES_FIXTURE: SidecarCapabilities = {
|
||||
runtime: 'dotnet-maf',
|
||||
modes: {
|
||||
single: { available: true },
|
||||
sequential: { available: true },
|
||||
concurrent: { available: true },
|
||||
handoff: { available: true },
|
||||
magentic: { available: true },
|
||||
'group-chat': { available: true },
|
||||
},
|
||||
models: [],
|
||||
runtimeTools: [],
|
||||
connection: {
|
||||
status: 'ready',
|
||||
summary: 'Connected',
|
||||
checkedAt: '2026-03-25T00:00:00.000Z',
|
||||
},
|
||||
};
|
||||
|
||||
function getRequestId(process: FakeChildProcess): string {
|
||||
const rawRequest = process.stdin.writes.at(-1);
|
||||
if (!rawRequest) {
|
||||
throw new Error('Expected the fake sidecar to receive a request.');
|
||||
}
|
||||
|
||||
return (JSON.parse(rawRequest.trim()) as { requestId: string }).requestId;
|
||||
}
|
||||
|
||||
describe('SidecarClient', () => {
|
||||
test('waits for the disposed sidecar to fully close before spawning a replacement process', async () => {
|
||||
spawnedProcesses.length = 0;
|
||||
const client = new SidecarClient();
|
||||
|
||||
const firstCapabilities = client.describeCapabilities();
|
||||
await Promise.resolve();
|
||||
expect(spawnedProcesses).toHaveLength(1);
|
||||
spawnedProcesses[0]!.emitStdout(
|
||||
`${JSON.stringify({
|
||||
type: 'capabilities',
|
||||
requestId: getRequestId(spawnedProcesses[0]!),
|
||||
capabilities: CAPABILITIES_FIXTURE,
|
||||
})}\n`,
|
||||
);
|
||||
await expect(firstCapabilities).resolves.toEqual(CAPABILITIES_FIXTURE);
|
||||
|
||||
let disposeCompleted = false;
|
||||
const disposePromise = client.dispose().then(() => {
|
||||
disposeCompleted = true;
|
||||
});
|
||||
|
||||
const replacementCapabilities = client.describeCapabilities();
|
||||
|
||||
await Promise.resolve();
|
||||
|
||||
expect(disposeCompleted).toBe(false);
|
||||
expect(spawnedProcesses).toHaveLength(1);
|
||||
|
||||
spawnedProcesses[0]!.completeExit();
|
||||
await disposePromise;
|
||||
|
||||
expect(disposeCompleted).toBe(true);
|
||||
expect(spawnedProcesses).toHaveLength(2);
|
||||
|
||||
spawnedProcesses[1]!.emitStdout(
|
||||
`${JSON.stringify({
|
||||
type: 'capabilities',
|
||||
requestId: getRequestId(spawnedProcesses[1]!),
|
||||
capabilities: CAPABILITIES_FIXTURE,
|
||||
})}\n`,
|
||||
);
|
||||
await expect(replacementCapabilities).resolves.toEqual(CAPABILITIES_FIXTURE);
|
||||
|
||||
const finalDispose = client.dispose();
|
||||
spawnedProcesses[1]!.completeExit();
|
||||
await finalDispose;
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user