From ff433e172d2b58b5e1a3bdd8daa9b8f7a6161a2d Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Thu, 2 Apr 2026 22:22:59 -0700 Subject: [PATCH] test(cowork-service): add product-config, feature-flags, health routes tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New test files (3): - lib/product-config.test.ts — 3 tests: PRODUCT_ID, productConfig fields, consistency - lib/feature-flags.test.ts — 3 tests: 13 flag names match seed.ts, defaults correct, setFlag override - modules/health/routes.test.ts — 2 tests: degraded when IPC disconnected, connected status reporting 32 tests passing (was 24), 6 test files, typecheck clean. --- .../src/lib/feature-flags.test.ts | 53 ++++++++++++++ .../src/lib/product-config.test.ts | 21 ++++++ .../src/modules/health/routes.test.ts | 70 +++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 services/cowork-service/src/lib/feature-flags.test.ts create mode 100644 services/cowork-service/src/lib/product-config.test.ts create mode 100644 services/cowork-service/src/modules/health/routes.test.ts diff --git a/services/cowork-service/src/lib/feature-flags.test.ts b/services/cowork-service/src/lib/feature-flags.test.ts new file mode 100644 index 00000000..d62e3303 --- /dev/null +++ b/services/cowork-service/src/lib/feature-flags.test.ts @@ -0,0 +1,53 @@ +import { describe, expect, it, vi } from 'vitest'; + +vi.mock('./config.js', () => ({ + config: { FEATURE_FLAGS_ENABLED: false }, +})); + +import { isFeatureEnabled, getAllFlags, setFlag } from './feature-flags.js'; + +describe('feature-flags', () => { + it('has all 13 expected flag names', () => { + const flags = getAllFlags(); + const expected = [ + 'sandbox_enabled', + 'plugins_enabled', + 'mcp_connectors_enabled', + 'scheduling_enabled', + 'computer_use_enabled', + 'parallel_agents_enabled', + 'marketplace_enabled', + 'wasm_plugins_enabled', + 'llm_multi_model_enabled', + 'audit_logging_enabled', + 'platform_auth_required', + 'dispatch_api_enabled', + 'telemetry_enabled', + ]; + for (const name of expected) { + expect(flags).toHaveProperty(name); + } + expect(Object.keys(flags)).toHaveLength(expected.length); + }); + + it('defaults match seed.ts', () => { + expect(isFeatureEnabled('sandbox_enabled')).toBe(true); + expect(isFeatureEnabled('plugins_enabled')).toBe(true); + expect(isFeatureEnabled('mcp_connectors_enabled')).toBe(true); + expect(isFeatureEnabled('computer_use_enabled')).toBe(false); + expect(isFeatureEnabled('wasm_plugins_enabled')).toBe(false); + expect(isFeatureEnabled('llm_multi_model_enabled')).toBe(false); + expect(isFeatureEnabled('platform_auth_required')).toBe(false); + expect(isFeatureEnabled('marketplace_enabled')).toBe(true); + expect(isFeatureEnabled('dispatch_api_enabled')).toBe(true); + expect(isFeatureEnabled('audit_logging_enabled')).toBe(true); + expect(isFeatureEnabled('telemetry_enabled')).toBe(false); + }); + + it('setFlag overrides a default', () => { + setFlag('computer_use_enabled', true); + expect(isFeatureEnabled('computer_use_enabled')).toBe(true); + // Reset + setFlag('computer_use_enabled', false); + }); +}); diff --git a/services/cowork-service/src/lib/product-config.test.ts b/services/cowork-service/src/lib/product-config.test.ts new file mode 100644 index 00000000..398965b1 --- /dev/null +++ b/services/cowork-service/src/lib/product-config.test.ts @@ -0,0 +1,21 @@ +import { describe, expect, it } from 'vitest'; +import { PRODUCT_ID, productConfig } from './product-config.js'; + +describe('product-config', () => { + it('exports PRODUCT_ID as clawcowork', () => { + expect(PRODUCT_ID).toBe('clawcowork'); + }); + + it('exports productConfig with correct fields', () => { + expect(productConfig.productId).toBe('clawcowork'); + expect(productConfig.displayName).toBe('Claw Cowork'); + expect(productConfig.backendPort).toBe(4009); + expect(productConfig.platforms).toContain('macos'); + expect(productConfig.platforms).toContain('linux'); + expect(productConfig.platforms).toContain('windows'); + }); + + it('productConfig.productId matches PRODUCT_ID', () => { + expect(productConfig.productId).toBe(PRODUCT_ID); + }); +}); diff --git a/services/cowork-service/src/modules/health/routes.test.ts b/services/cowork-service/src/modules/health/routes.test.ts new file mode 100644 index 00000000..c53d71a7 --- /dev/null +++ b/services/cowork-service/src/modules/health/routes.test.ts @@ -0,0 +1,70 @@ +import { describe, expect, it, vi, beforeAll, afterAll } from 'vitest'; +import { createServiceApp, type FastifyApp } from '@bytelyst/fastify-core'; + +vi.mock('../../lib/config.js', () => ({ + config: { + SERVICE_NAME: 'cowork-service', + PLATFORM_SERVICE_URL: 'http://localhost:4003', + }, +})); +vi.mock('../../lib/product-config.js', () => ({ + PRODUCT_ID: 'clawcowork', +})); +vi.mock('../../lib/ipc-bridge.js', () => ({ + getIpcBridge: vi.fn(() => ({ isRunning: false })), +})); + +import { healthRoutes } from './routes.js'; +import { getIpcBridge } from '../../lib/ipc-bridge.js'; + +let app: FastifyApp; + +beforeAll(async () => { + app = await createServiceApp({ + name: 'cowork-health-test', + version: '0.0.1', + logger: false, + }); + await app.register(healthRoutes); +}); + +afterAll(async () => { + await app.close(); +}); + +describe('health routes', () => { + it('GET /api/health/dependencies — returns degraded when IPC bridge is disconnected', async () => { + const res = await app.inject({ + method: 'GET', + url: '/api/health/dependencies', + }); + + // Platform-service unreachable + IPC disconnected → 503 + expect(res.statusCode).toBe(503); + const body = JSON.parse(res.payload); + expect(body.status).toBe('degraded'); + expect(body.service).toBe('cowork-service'); + expect(body.productId).toBe('clawcowork'); + expect(body.ipcBridge).toBe('disconnected'); + expect(body.checks).toHaveProperty('platform-service'); + expect(body.timestamp).toBeDefined(); + }); + + it('GET /api/health/dependencies — reports ipcBridge connected when bridge is running', async () => { + vi.mocked(getIpcBridge).mockReturnValue({ isRunning: true } as ReturnType); + + const res = await app.inject({ + method: 'GET', + url: '/api/health/dependencies', + }); + + const body = JSON.parse(res.payload); + expect(body.ipcBridge).toBe('connected'); + expect(body.productId).toBe('clawcowork'); + // Overall status depends on platform-service reachability — just verify field exists + expect(['ok', 'degraded']).toContain(body.status); + + // Reset + vi.mocked(getIpcBridge).mockReturnValue({ isRunning: false } as ReturnType); + }); +});