feat(gateway): enhance gateway readiness handling and batch sync configuration (#851)
Co-authored-by: paisley <8197966+su8su@users.noreply.github.com>
This commit is contained in:
127
tests/unit/gateway-ready-fallback.test.ts
Normal file
127
tests/unit/gateway-ready-fallback.test.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user