learning_ai_common_plat/services/cowork-service/src/server.test.ts
saravanakumardb1 53c3565874 fix(cowork-service): audit flush field name mismatch + server test mock gap
BUG: flush-scheduler.ts flushAudit() read 'events' from IPC response but
Rust handle_flush_audit() returns { count, entries }. Audit events were
silently lost (always empty array). Fixed to read 'entries'.

Also fixed:
- server.test.ts: added missing flush-scheduler.js mock (new import in server.ts)
- feature-flags.ts: doc comment '12 flags' → '13 flags'
- flush-scheduler.test.ts: mock data aligned to Rust response shape

49 tests passing, 8 test files, typecheck clean.
2026-04-02 23:02:38 -07:00

90 lines
2.8 KiB
TypeScript

import { describe, expect, it, vi, beforeEach } from 'vitest';
const createServiceAppMock = vi.fn();
const registerOptionalJwtContextMock = vi.fn(async () => undefined);
const startServiceMock = vi.fn(async () => undefined);
const appMock = {
register: vi.fn(async () => undefined),
inject: vi.fn(),
get: vi.fn(),
log: { info: vi.fn(), warn: vi.fn() },
addHook: vi.fn(),
};
vi.mock('@bytelyst/fastify-core', () => ({
createServiceApp: createServiceAppMock,
registerOptionalJwtContext: registerOptionalJwtContextMock,
startService: startServiceMock,
}));
vi.mock('jose', () => ({ jwtVerify: vi.fn() }));
vi.mock('./modules/health/routes.js', () => ({ healthRoutes: vi.fn() }));
vi.mock('./modules/tasks/routes.js', () => ({ taskRoutes: vi.fn() }));
vi.mock('./lib/config.js', () => ({
config: {
PORT: 4009,
HOST: '0.0.0.0',
CORS_ORIGIN: undefined,
SERVICE_NAME: 'cowork-service',
PLATFORM_SERVICE_URL: 'http://localhost:4003',
RUST_RUNTIME_BIN: 'cowork-orchestrator',
RUST_RUNTIME_TIMEOUT_MS: 300_000,
JWT_SECRET: 'test-secret',
ANTHROPIC_API_KEY: undefined,
},
}));
vi.mock('./lib/product-config.js', () => ({
PRODUCT_ID: 'clawcowork',
productConfig: {
productId: 'clawcowork',
displayName: 'Claw Cowork',
platforms: ['macos', 'linux', 'windows'],
backendPort: 4009,
},
}));
vi.mock('./lib/request-context.js', () => ({
getUserId: vi.fn(() => 'demo-user'),
getRequestProductId: vi.fn(() => 'clawcowork'),
}));
vi.mock('./lib/ipc-bridge.js', () => ({
getIpcBridge: vi.fn(() => ({
isRunning: false,
start: vi.fn(async () => { throw new Error('no binary in test'); }),
shutdown: vi.fn(async () => undefined),
})),
}));
vi.mock('./lib/flush-scheduler.js', () => ({
getFlushScheduler: vi.fn(() => ({
isRunning: false,
start: vi.fn(),
stop: vi.fn(),
finalFlush: vi.fn(async () => undefined),
})),
}));
describe('cowork-service bootstrap', () => {
beforeEach(() => {
vi.resetModules();
vi.clearAllMocks();
createServiceAppMock.mockResolvedValue(appMock);
appMock.register.mockReset();
appMock.register.mockResolvedValue(undefined);
});
it('creates app, registers JWT + routes, and starts on port 4009', async () => {
await import('./server.js');
expect(createServiceAppMock).toHaveBeenCalledOnce();
const opts = createServiceAppMock.mock.calls[0][0];
expect(opts.name).toBe('cowork-service');
expect(opts.version).toBe('0.1.0');
expect(opts.readiness).toBe(true);
// JWT context + health + task routes = 2 register calls + 1 JWT
expect(registerOptionalJwtContextMock).toHaveBeenCalledOnce();
expect(appMock.register).toHaveBeenCalledTimes(2);
expect(startServiceMock).toHaveBeenCalledWith(appMock, { port: 4009, host: '0.0.0.0' });
});
});