import { describe, test, expect, beforeEach, mock } from 'bun:test' // Mock config before imports const mockConfig = { port: 3000, host: '0.0.0.0', apiKeys: ['test-api-key'], baseUrl: 'http://localhost:3000', pollTimeout: 1, // Short timeout for tests heartbeatInterval: 20, jwtExpiresIn: 3600, disconnectTimeout: 300, webCorsOrigins: [], wsIdleTimeout: 30, wsKeepaliveInterval: 20, } mock.module('../config', () => ({ config: mockConfig, getBaseUrl: () => 'http://localhost:3000', })) import { storeReset, storeCreateEnvironment, storeCreateSession, storeGetWorkItem, storeGetPendingWorkItem, } from '../store' import { createWorkItem, pollWork, ackWork, stopWork, heartbeatWork, reconnectWorkForEnvironment, } from '../services/work-dispatch' describe('Work Dispatch', () => { let envId: string let sessionId: string beforeEach(() => { storeReset() const env = storeCreateEnvironment({ secret: 's' }) envId = env.id const session = storeCreateSession({ environmentId: envId }) sessionId = session.id }) describe('createWorkItem', () => { test('creates work item for active environment', async () => { const workId = await createWorkItem(envId, sessionId) expect(workId).toMatch(/^work_/) const item = storeGetWorkItem(workId) expect(item?.state).toBe('pending') expect(item?.sessionId).toBe(sessionId) }) test('throws for non-existent environment', async () => { await expect(createWorkItem('env_no', sessionId)).rejects.toThrow( 'not found', ) }) test('throws for inactive environment', async () => { const inactiveEnv = storeCreateEnvironment({ secret: 's2' }) // Manually set status to deregistered const { storeUpdateEnvironment } = await import('../store') storeUpdateEnvironment(inactiveEnv.id, { status: 'deregistered' }) await expect(createWorkItem(inactiveEnv.id, sessionId)).rejects.toThrow( 'not active', ) }) test('encodes work secret as base64 JSON', async () => { const workId = await createWorkItem(envId, sessionId) const item = storeGetWorkItem(workId) const decoded = JSON.parse( Buffer.from(item!.secret, 'base64url').toString(), ) expect(decoded.version).toBe(1) expect(decoded.session_ingress_token).toBe('test-api-key') expect(decoded.api_base_url).toBe('http://localhost:3000') }) }) describe('pollWork', () => { test('returns null when no work available (timeout)', async () => { const result = await pollWork(envId, 0.1) expect(result).toBeNull() }) test('returns pending work and marks as dispatched', async () => { const workId = await createWorkItem(envId, sessionId) const result = await pollWork(envId, 1) expect(result).not.toBeNull() expect(result!.id).toBe(workId) expect(result!.state).toBe('dispatched') expect(result!.data.type).toBe('session') expect(result!.data.id).toBe(sessionId) // Work should no longer be pending expect(storeGetPendingWorkItem(envId)).toBeUndefined() }) test('does not return work for different environment', async () => { const env2 = storeCreateEnvironment({ secret: 's2' }) await createWorkItem(envId, sessionId) const result = await pollWork(env2.id, 0.1) expect(result).toBeNull() }) }) describe('ackWork', () => { test('marks work as acked', async () => { const workId = await createWorkItem(envId, sessionId) ackWork(workId) expect(storeGetWorkItem(workId)?.state).toBe('acked') }) }) describe('stopWork', () => { test('marks work as completed', async () => { const workId = await createWorkItem(envId, sessionId) stopWork(workId) expect(storeGetWorkItem(workId)?.state).toBe('completed') }) }) describe('heartbeatWork', () => { test('extends lease and returns heartbeat info', async () => { const workId = await createWorkItem(envId, sessionId) const result = heartbeatWork(workId) expect(result.lease_extended).toBe(true) expect(result.ttl_seconds).toBe(40) // heartbeatInterval * 2 expect(result.last_heartbeat).toBeTruthy() }) test('returns default state for non-existent work', async () => { const result = heartbeatWork('work_no') expect(result.state).toBe('acked') }) }) describe('reconnectWorkForEnvironment', () => { test('creates work items for idle sessions in environment', async () => { // Create another idle session storeCreateSession({ environmentId: envId }) const workIds = await reconnectWorkForEnvironment(envId) expect(workIds).toHaveLength(2) for (const id of workIds) { expect(storeGetWorkItem(id)?.state).toBe('pending') } }) test('skips non-idle sessions', async () => { const activeSession = storeCreateSession({ environmentId: envId }) const { storeUpdateSession } = await import('../store') storeUpdateSession(activeSession.id, { status: 'active' }) const workIds = await reconnectWorkForEnvironment(envId) // Only the original idle session should get work expect(workIds).toHaveLength(1) }) test('returns empty for environment with no sessions', async () => { const emptyEnv = storeCreateEnvironment({ secret: 's_empty' }) const workIds = await reconnectWorkForEnvironment(emptyEnv.id) expect(workIds).toHaveLength(0) }) }) })