104 lines
3.4 KiB
TypeScript
104 lines
3.4 KiB
TypeScript
import { describe, expect, it, vi } from 'vitest';
|
|
import {
|
|
warmupOpencodeRuntime,
|
|
type OpencodeStartupWarmupDependencies,
|
|
} from '@electron/opencode/startup-warmup';
|
|
|
|
function createDependencies(
|
|
overrides: Partial<OpencodeStartupWarmupDependencies> = {},
|
|
): OpencodeStartupWarmupDependencies {
|
|
return {
|
|
hasAuthenticatedSession: () => true,
|
|
getStatus: () => ({ state: 'stopped', port: 4096 }),
|
|
getActiveProject: vi.fn(async () => ({ path: '/projects/demo' })),
|
|
readProjectConfig: vi.fn(async () => ({
|
|
status: 'valid' as const,
|
|
config: { initialized: true },
|
|
})),
|
|
getConfiguredProviderCount: vi.fn(async () => 1),
|
|
start: vi.fn(async () => ({ state: 'running' as const, port: 4096 })),
|
|
...overrides,
|
|
};
|
|
}
|
|
|
|
describe('warmupOpencodeRuntime', () => {
|
|
it('starts a ready runtime in the background', async () => {
|
|
const dependencies = createDependencies();
|
|
|
|
const result = await warmupOpencodeRuntime(dependencies);
|
|
|
|
expect(result).toEqual({
|
|
started: true,
|
|
status: { state: 'running', port: 4096 },
|
|
});
|
|
expect(dependencies.readProjectConfig).toHaveBeenCalledWith('/projects/demo');
|
|
expect(dependencies.getConfiguredProviderCount).toHaveBeenCalledOnce();
|
|
expect(dependencies.start).toHaveBeenCalledOnce();
|
|
});
|
|
|
|
it('does not start without an authenticated session', async () => {
|
|
const dependencies = createDependencies({
|
|
hasAuthenticatedSession: () => false,
|
|
});
|
|
|
|
await expect(warmupOpencodeRuntime(dependencies)).resolves.toEqual({
|
|
started: false,
|
|
reason: 'no-session',
|
|
});
|
|
expect(dependencies.getActiveProject).not.toHaveBeenCalled();
|
|
expect(dependencies.start).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it.each([
|
|
['no active project', { getActiveProject: vi.fn(async () => null) }, 'no-active-project'],
|
|
[
|
|
'uninitialized project',
|
|
{
|
|
readProjectConfig: vi.fn(async () => ({
|
|
status: 'valid' as const,
|
|
config: { initialized: false },
|
|
})),
|
|
},
|
|
'project-not-ready',
|
|
],
|
|
['no configured provider', { getConfiguredProviderCount: vi.fn(async () => 0) }, 'no-provider'],
|
|
] as const)('skips when there is %s', async (_label, overrides, reason) => {
|
|
const dependencies = createDependencies(overrides);
|
|
|
|
await expect(warmupOpencodeRuntime(dependencies)).resolves.toMatchObject({
|
|
started: false,
|
|
reason,
|
|
});
|
|
expect(dependencies.start).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('does not compete with an already active runtime', async () => {
|
|
const dependencies = createDependencies({
|
|
getStatus: () => ({ state: 'starting', port: 4096 }),
|
|
});
|
|
|
|
await expect(warmupOpencodeRuntime(dependencies)).resolves.toEqual({
|
|
started: false,
|
|
reason: 'runtime-active',
|
|
});
|
|
expect(dependencies.getActiveProject).not.toHaveBeenCalled();
|
|
expect(dependencies.start).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('swallows startup errors and leaves lazy Chat startup available', async () => {
|
|
const error = new Error('runtime failed');
|
|
const onError = vi.fn();
|
|
const dependencies = createDependencies({
|
|
start: vi.fn(async () => { throw error; }),
|
|
onError,
|
|
});
|
|
|
|
await expect(warmupOpencodeRuntime(dependencies)).resolves.toMatchObject({
|
|
started: false,
|
|
reason: 'start-failed',
|
|
error,
|
|
});
|
|
expect(onError).toHaveBeenCalledWith(error, 'start');
|
|
});
|
|
});
|