import { describe, it, expect } from 'vitest'; import { EventQueue } from '../src/queue.js'; import { TaskType, Complexity, Harness, Provider, Outcome, TaskCompletionEvent, } from '../src/types/events.js'; function makeEvent(id: string): TaskCompletionEvent { return { instance_id: 'test-instance', event_id: id, schema_version: '1.0', timestamp: new Date().toISOString(), task_duration_ms: 1000, task_type: TaskType.IMPLEMENTATION, complexity: Complexity.MEDIUM, harness: Harness.CLAUDE_CODE, model: 'claude-3-opus', provider: Provider.ANTHROPIC, estimated_input_tokens: 1000, estimated_output_tokens: 500, actual_input_tokens: 1100, actual_output_tokens: 550, estimated_cost_usd_micros: 50000, actual_cost_usd_micros: 55000, quality_gate_passed: true, quality_gates_run: [], quality_gates_failed: [], context_compactions: 0, context_rotations: 0, context_utilization_final: 0.5, outcome: Outcome.SUCCESS, retry_count: 0, }; } describe('EventQueue', () => { it('should enqueue and drain events', () => { const queue = new EventQueue(10); const event = makeEvent('e1'); queue.enqueue(event); expect(queue.size).toBe(1); expect(queue.isEmpty).toBe(false); const drained = queue.drain(10); expect(drained).toHaveLength(1); expect(drained[0].event_id).toBe('e1'); expect(queue.isEmpty).toBe(true); }); it('should respect maxSize with FIFO eviction', () => { const queue = new EventQueue(3); queue.enqueue(makeEvent('e1')); queue.enqueue(makeEvent('e2')); queue.enqueue(makeEvent('e3')); expect(queue.size).toBe(3); // Adding a 4th should evict the oldest (e1) queue.enqueue(makeEvent('e4')); expect(queue.size).toBe(3); const drained = queue.drain(10); expect(drained.map((e) => e.event_id)).toEqual(['e2', 'e3', 'e4']); }); it('should drain up to maxItems', () => { const queue = new EventQueue(10); queue.enqueue(makeEvent('e1')); queue.enqueue(makeEvent('e2')); queue.enqueue(makeEvent('e3')); const drained = queue.drain(2); expect(drained).toHaveLength(2); expect(drained.map((e) => e.event_id)).toEqual(['e1', 'e2']); expect(queue.size).toBe(1); }); it('should remove drained items from the queue', () => { const queue = new EventQueue(10); queue.enqueue(makeEvent('e1')); queue.enqueue(makeEvent('e2')); queue.drain(1); expect(queue.size).toBe(1); const remaining = queue.drain(10); expect(remaining[0].event_id).toBe('e2'); }); it('should report isEmpty correctly', () => { const queue = new EventQueue(5); expect(queue.isEmpty).toBe(true); queue.enqueue(makeEvent('e1')); expect(queue.isEmpty).toBe(false); queue.drain(1); expect(queue.isEmpty).toBe(true); }); it('should report size correctly', () => { const queue = new EventQueue(10); expect(queue.size).toBe(0); queue.enqueue(makeEvent('e1')); expect(queue.size).toBe(1); queue.enqueue(makeEvent('e2')); expect(queue.size).toBe(2); queue.drain(1); expect(queue.size).toBe(1); }); it('should return empty array when draining empty queue', () => { const queue = new EventQueue(5); const drained = queue.drain(10); expect(drained).toEqual([]); }); it('should prepend events to the front of the queue', () => { const queue = new EventQueue(10); queue.enqueue(makeEvent('e3')); queue.prepend([makeEvent('e1'), makeEvent('e2')]); expect(queue.size).toBe(3); const drained = queue.drain(10); expect(drained.map((e) => e.event_id)).toEqual(['e1', 'e2', 'e3']); }); it('should respect maxSize when prepending', () => { const queue = new EventQueue(3); queue.enqueue(makeEvent('e3')); queue.enqueue(makeEvent('e4')); // Only 1 slot available, so only first event should be prepended queue.prepend([makeEvent('e1'), makeEvent('e2')]); expect(queue.size).toBe(3); const drained = queue.drain(10); expect(drained.map((e) => e.event_id)).toEqual(['e1', 'e3', 'e4']); }); });