/** * Unit Tests — task-queue.js */ import { describe, it, expect, beforeEach, afterEach } from 'vitest'; const { TaskQueue, FAST_TIMEOUT, MAX_CONCURRENT } = require('../../src/engine/../../../server/services/task-queue'); describe('TaskQueue', () => { let queue; let mockChatService; beforeEach(() => { // Mock chat service with controllable sessions mockChatService = { sessions: new Map(), getSession(id) { return this.sessions.get(id) || null; }, createSession(id) { const session = { id, status: 'disconnected', connect: async () => { session.status = 'connected'; }, sendMessage: async (msg) => ({ result: `Echo: ${msg.substring(0, 50)}` }), }; this.sessions.set(id, session); return session; }, }; queue = new TaskQueue(mockChatService); }); afterEach(() => queue.stop()); describe('start / stop', () => { it('should start heartbeat without error', () => { expect(() => queue.start()).not.toThrow(); }); it('should stop heartbeat without error', () => { queue.start(); expect(() => queue.stop()).not.toThrow(); }); it('should not double-start', () => { queue.start(); queue.start(); // should be a no-op queue.stop(); }); }); describe('getTask / listTasks', () => { it('should return null for non-existent task', () => { expect(queue.getTask('no-such-task')).toBeNull(); }); it('should return empty list initially', () => { expect(queue.listTasks()).toEqual([]); }); }); describe('dispatch', () => { it('should create a task', async () => { const result = await queue.dispatch('Test message', {}); expect(result.mode).toBe('async'); expect(result.taskId).toBeDefined(); expect(result.sessionId).toBeDefined(); }); it('should reject when max concurrent reached', async () => { // Fill up to MAX_CONCURRENT for (let i = 0; i < MAX_CONCURRENT; i++) { // Create tasks that stay running (use slow sessions) mockChatService.createSession = (id) => { const s = { id, status: 'disconnected', connect: async () => { s.status = 'connected'; }, sendMessage: () => new Promise(() => {}), // never resolves }; mockChatService.sessions.set(id, s); return s; }; await queue.dispatch(`Task ${i}`); } // Wait for tasks to start await new Promise(r => setTimeout(r, 50)); // Next dispatch should be rejected const result = await queue.dispatch('Overflow task'); expect(result.mode).toBe('rejected'); }); it('should track dispatched task', async () => { const result = await queue.dispatch('Hello'); const task = queue.getTask(result.taskId); expect(task).not.toBeNull(); expect(task.status).toBeDefined(); }); }); describe('listTasks', () => { it('should filter by status', async () => { await queue.dispatch('Test 1'); await new Promise(r => setTimeout(r, 50)); const completed = queue.listTasks({ status: 'completed' }); expect(Array.isArray(completed)).toBe(true); }); it('should respect limit', async () => { await queue.dispatch('A'); await queue.dispatch('B'); const tasks = queue.listTasks({ limit: 1 }); expect(tasks).toHaveLength(1); }); }); describe('constants', () => { it('should export FAST_TIMEOUT as 15s', () => { expect(FAST_TIMEOUT).toBe(15000); }); it('should export MAX_CONCURRENT as 3', () => { expect(MAX_CONCURRENT).toBe(3); }); }); });