128 lines
4.6 KiB
TypeScript
128 lines
4.6 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
vi.mock('electron', () => ({
|
|
app: {
|
|
getPath: () => '/tmp',
|
|
isPackaged: false,
|
|
},
|
|
utilityProcess: {},
|
|
}));
|
|
|
|
vi.mock('@electron/utils/logger', () => ({
|
|
logger: {
|
|
info: vi.fn(),
|
|
warn: vi.fn(),
|
|
error: vi.fn(),
|
|
debug: vi.fn(),
|
|
},
|
|
}));
|
|
|
|
vi.mock('@electron/utils/config', () => ({
|
|
PORTS: { OPENCLAW_GATEWAY: 18789 },
|
|
}));
|
|
|
|
describe('GatewayManager gatewayReady fallback', () => {
|
|
beforeEach(() => {
|
|
vi.useFakeTimers();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
afterEach(() => {
|
|
vi.useRealTimers();
|
|
});
|
|
|
|
it('sets gatewayReady=false when entering starting state', async () => {
|
|
vi.resetModules();
|
|
const { GatewayManager } = await import('@electron/gateway/manager');
|
|
const manager = new GatewayManager();
|
|
|
|
const statusUpdates: Array<{ gatewayReady?: boolean }> = [];
|
|
manager.on('status', (status: { gatewayReady?: boolean }) => {
|
|
statusUpdates.push({ gatewayReady: status.gatewayReady });
|
|
});
|
|
|
|
// Simulate start attempt (will fail but we can check the initial status)
|
|
try {
|
|
await manager.start();
|
|
} catch {
|
|
// expected to fail — no actual gateway process
|
|
}
|
|
|
|
const startingUpdate = statusUpdates.find((u) => u.gatewayReady === false);
|
|
expect(startingUpdate).toBeDefined();
|
|
});
|
|
|
|
it('emits gatewayReady=true when gateway:ready event is received', async () => {
|
|
vi.resetModules();
|
|
const { GatewayManager } = await import('@electron/gateway/manager');
|
|
const manager = new GatewayManager();
|
|
|
|
// Force internal state to 'running' for the test
|
|
const stateController = (manager as unknown as { stateController: { setStatus: (u: Record<string, unknown>) => void } }).stateController;
|
|
stateController.setStatus({ state: 'running', connectedAt: Date.now() });
|
|
|
|
const statusUpdates: Array<{ gatewayReady?: boolean; state: string }> = [];
|
|
manager.on('status', (status: { gatewayReady?: boolean; state: string }) => {
|
|
statusUpdates.push({ gatewayReady: status.gatewayReady, state: status.state });
|
|
});
|
|
|
|
manager.emit('gateway:ready', {});
|
|
|
|
const readyUpdate = statusUpdates.find((u) => u.gatewayReady === true);
|
|
expect(readyUpdate).toBeDefined();
|
|
});
|
|
|
|
it('auto-sets gatewayReady=true after fallback timeout if no event received', async () => {
|
|
vi.resetModules();
|
|
const { GatewayManager } = await import('@electron/gateway/manager');
|
|
const manager = new GatewayManager();
|
|
|
|
// Force internal state to 'running' without gatewayReady
|
|
const stateController = (manager as unknown as { stateController: { setStatus: (u: Record<string, unknown>) => void } }).stateController;
|
|
stateController.setStatus({ state: 'running', connectedAt: Date.now() });
|
|
|
|
const statusUpdates: Array<{ gatewayReady?: boolean }> = [];
|
|
manager.on('status', (status: { gatewayReady?: boolean }) => {
|
|
statusUpdates.push({ gatewayReady: status.gatewayReady });
|
|
});
|
|
|
|
// Call the private scheduleGatewayReadyFallback method
|
|
(manager as unknown as { scheduleGatewayReadyFallback: () => void }).scheduleGatewayReadyFallback();
|
|
|
|
// Before timeout, no gatewayReady update
|
|
vi.advanceTimersByTime(29_000);
|
|
expect(statusUpdates.find((u) => u.gatewayReady === true)).toBeUndefined();
|
|
|
|
// After 30s fallback timeout
|
|
vi.advanceTimersByTime(2_000);
|
|
const readyUpdate = statusUpdates.find((u) => u.gatewayReady === true);
|
|
expect(readyUpdate).toBeDefined();
|
|
});
|
|
|
|
it('cancels fallback timer when gateway:ready event arrives first', async () => {
|
|
vi.resetModules();
|
|
const { GatewayManager } = await import('@electron/gateway/manager');
|
|
const manager = new GatewayManager();
|
|
|
|
const stateController = (manager as unknown as { stateController: { setStatus: (u: Record<string, unknown>) => void } }).stateController;
|
|
stateController.setStatus({ state: 'running', connectedAt: Date.now() });
|
|
|
|
const statusUpdates: Array<{ gatewayReady?: boolean }> = [];
|
|
manager.on('status', (status: { gatewayReady?: boolean }) => {
|
|
statusUpdates.push({ gatewayReady: status.gatewayReady });
|
|
});
|
|
|
|
// Schedule fallback
|
|
(manager as unknown as { scheduleGatewayReadyFallback: () => void }).scheduleGatewayReadyFallback();
|
|
|
|
// gateway:ready event arrives at 5s
|
|
vi.advanceTimersByTime(5_000);
|
|
manager.emit('gateway:ready', {});
|
|
expect(statusUpdates.filter((u) => u.gatewayReady === true)).toHaveLength(1);
|
|
|
|
// After 30s, no duplicate gatewayReady=true
|
|
vi.advanceTimersByTime(30_000);
|
|
expect(statusUpdates.filter((u) => u.gatewayReady === true)).toHaveLength(1);
|
|
});
|
|
});
|