fix: harden managed OpenCode startup
This commit is contained in:
@@ -90,6 +90,11 @@ const createRuntime = (overrides = {}) => {
|
||||
clearResolvedOpenCodeBinary: vi.fn(),
|
||||
buildAugmentedPath: vi.fn(() => '/home/user/.bun/bin:/usr/local/bin:/usr/bin'),
|
||||
buildManagedOpenCodePath: vi.fn(() => '/home/user/.bun/bin:/usr/local/bin:/usr/bin'),
|
||||
getManagedOpenCodeShellEnvSnapshot: vi.fn(() => ({
|
||||
PATH: '/home/user/.bun/bin:/usr/local/bin:/usr/bin',
|
||||
SHELL_ONLY: 'yes',
|
||||
OPENCODE_SERVER_PASSWORD: 'shell-password',
|
||||
})),
|
||||
...overrides,
|
||||
});
|
||||
};
|
||||
@@ -112,6 +117,7 @@ describe('OpenCode lifecycle', () => {
|
||||
expect(binary).toBe('opencode');
|
||||
expect(args).toEqual(['serve', '--hostname', '127.0.0.1', '--port', '45678']);
|
||||
expect(options.env.PATH).toBe('/home/user/.bun/bin:/usr/local/bin:/usr/bin');
|
||||
expect(options.env.SHELL_ONLY).toBe('yes');
|
||||
expect(options.env.OPENCODE_SERVER_PASSWORD).toBe('password');
|
||||
|
||||
await server.close();
|
||||
@@ -163,4 +169,51 @@ describe('OpenCode lifecycle', () => {
|
||||
|
||||
await server.close();
|
||||
});
|
||||
|
||||
it('reports the exit signal when managed OpenCode exits before becoming ready', async () => {
|
||||
delete process.env.OPENCODE_BINARY;
|
||||
const firstChild = createMockChild();
|
||||
const secondChild = createMockChild();
|
||||
spawnMock.mockImplementationOnce(() => {
|
||||
queueMicrotask(() => {
|
||||
firstChild.emit('exit', null, 'SIGTERM');
|
||||
});
|
||||
return firstChild;
|
||||
});
|
||||
spawnMock.mockImplementationOnce(() => {
|
||||
queueMicrotask(() => {
|
||||
secondChild.emit('exit', null, 'SIGTERM');
|
||||
});
|
||||
return secondChild;
|
||||
});
|
||||
|
||||
const runtime = createRuntime();
|
||||
|
||||
await expect(runtime.startOpenCode()).rejects.toThrow('OpenCode exited with signal SIGTERM. No stdout/stderr captured');
|
||||
expect(spawnMock).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('retries managed OpenCode startup once after a pre-ready exit', async () => {
|
||||
delete process.env.OPENCODE_BINARY;
|
||||
const firstChild = createMockChild();
|
||||
const secondChild = createMockChild();
|
||||
spawnMock.mockImplementationOnce(() => {
|
||||
queueMicrotask(() => {
|
||||
firstChild.emit('exit', null, 'SIGTERM');
|
||||
});
|
||||
return firstChild;
|
||||
});
|
||||
spawnMock.mockImplementationOnce(() => {
|
||||
queueMicrotask(() => {
|
||||
secondChild.stdout.emit('data', 'opencode server listening on http://127.0.0.1:45678\n');
|
||||
});
|
||||
return secondChild;
|
||||
});
|
||||
|
||||
const runtime = createRuntime();
|
||||
const server = await runtime.startOpenCode();
|
||||
|
||||
expect(spawnMock).toHaveBeenCalledTimes(2);
|
||||
await server.close();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user