All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
151 lines
4.1 KiB
TypeScript
151 lines
4.1 KiB
TypeScript
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"]);
|
|
});
|
|
});
|