|
1 | 1 | // Queue helper tests cover queue ordering and dedupe utility behavior. |
2 | 2 | import { describe, expect, it } from "vitest"; |
3 | 3 | import { |
| 4 | + applyQueueDropPolicy, |
4 | 5 | applyQueueRuntimeSettings, |
5 | 6 | buildQueueSummaryPrompt, |
6 | 7 | clearQueueSummaryState, |
7 | 8 | drainCollectItemIfNeeded, |
| 9 | + drainNextQueueItem, |
8 | 10 | hasCrossChannelItems, |
9 | 11 | previewQueueSummaryPrompt, |
10 | 12 | } from "./queue-helpers.js"; |
@@ -170,6 +172,57 @@ describe("drainCollectItemIfNeeded", () => { |
170 | 172 | }); |
171 | 173 | }); |
172 | 174 |
|
| 175 | +describe("drainNextQueueItem", () => { |
| 176 | + it("keeps overflow survivors when the queue mutates during an awaited drain", async () => { |
| 177 | + type Item = { id: string }; |
| 178 | + const queue = { |
| 179 | + items: [{ id: "m1" }], |
| 180 | + cap: 3, |
| 181 | + dropPolicy: "summarize" as const, |
| 182 | + droppedCount: 0, |
| 183 | + summaryLines: [], |
| 184 | + }; |
| 185 | + const delivered: string[] = []; |
| 186 | + const dropped: string[] = []; |
| 187 | + let release!: () => void; |
| 188 | + const gate = new Promise<void>((resolve) => { |
| 189 | + release = resolve; |
| 190 | + }); |
| 191 | + |
| 192 | + const firstDrain = drainNextQueueItem(queue.items, async (item: Item) => { |
| 193 | + delivered.push(item.id); |
| 194 | + await gate; |
| 195 | + }); |
| 196 | + await Promise.resolve(); |
| 197 | + |
| 198 | + for (let index = 2; index <= 8; index += 1) { |
| 199 | + const item = { id: `m${index}` }; |
| 200 | + const shouldEnqueue = applyQueueDropPolicy({ |
| 201 | + queue, |
| 202 | + summarize: (queued) => queued.id, |
| 203 | + onDrop: (items) => { |
| 204 | + dropped.push(...items.map((queued) => queued.id)); |
| 205 | + }, |
| 206 | + }); |
| 207 | + if (shouldEnqueue) { |
| 208 | + queue.items.push(item); |
| 209 | + } |
| 210 | + } |
| 211 | + |
| 212 | + release(); |
| 213 | + await firstDrain; |
| 214 | + while ( |
| 215 | + await drainNextQueueItem(queue.items, async (item) => { |
| 216 | + delivered.push(item.id); |
| 217 | + }) |
| 218 | + ) {} |
| 219 | + |
| 220 | + expect(delivered).toEqual(["m1", "m6", "m7", "m8"]); |
| 221 | + expect(dropped).toEqual(["m1", "m2", "m3", "m4", "m5"]); |
| 222 | + expect(queue.items).toEqual([]); |
| 223 | + }); |
| 224 | +}); |
| 225 | + |
173 | 226 | describe("hasCrossChannelItems", () => { |
174 | 227 | it("lets unresolved items join an otherwise single keyed route", () => { |
175 | 228 | const items = [ |
|
0 commit comments