Files
tutti/packages/agent/gui/shared/query/abortableSingleFlight.spec.ts
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

129 lines
4.1 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { AbortableSingleFlight } from "./abortableSingleFlight";
describe("AbortableSingleFlight", () => {
it("shares concurrent callers for the same key", async () => {
const pending = deferred<string>();
const flight = new AbortableSingleFlight<string, string>();
let starts = 0;
const first = flight.acquire("room-1", () => {
starts += 1;
return pending.promise;
});
const second = flight.acquire("room-1", async () => {
starts += 1;
return "unexpected";
});
expect(first.shared).toBe(false);
expect(second.shared).toBe(true);
expect(starts).toBe(1);
pending.resolve("ready");
await expect(Promise.all([first.promise, second.promise])).resolves.toEqual(
["ready", "ready"]
);
});
it("only aborts the shared operation after the final caller leaves", async () => {
const pending = deferred<string>();
const flight = new AbortableSingleFlight<string, string>();
let sharedSignal: AbortSignal | undefined;
const firstController = new AbortController();
const secondController = new AbortController();
const start = ({ signal }: { signal: AbortSignal }): Promise<string> => {
sharedSignal = signal;
return pending.promise;
};
const first = flight.acquire("room-1", start, firstController.signal);
const second = flight.acquire("room-1", start, secondController.signal);
firstController.abort();
await expect(first.promise).rejects.toMatchObject({ name: "AbortError" });
expect(sharedSignal?.aborted).toBe(false);
pending.resolve("ready");
await expect(second.promise).resolves.toBe("ready");
});
it("evicts an aborted entry before an immediate retry can acquire it", async () => {
const first = deferred<string>();
const second = deferred<string>();
const flight = new AbortableSingleFlight<string, string>();
const firstController = new AbortController();
let starts = 0;
const firstRequest = flight.acquire(
"room-1",
({ signal }) => {
starts += 1;
signal.addEventListener(
"abort",
() => first.reject(new Error("aborted")),
{ once: true }
);
return first.promise;
},
firstController.signal
);
firstController.abort();
await expect(firstRequest.promise).rejects.toMatchObject({
name: "AbortError"
});
const retry = flight.acquire("room-1", () => {
starts += 1;
return second.promise;
});
expect(retry.shared).toBe(false);
expect(starts).toBe(2);
second.resolve("retry-ready");
await expect(retry.promise).resolves.toBe("retry-ready");
});
it("does not let an old completion remove a replacement entry", async () => {
const first = deferred<string>();
const second = deferred<string>();
const flight = new AbortableSingleFlight<string, string>();
const firstController = new AbortController();
const firstRequest = flight.acquire(
"room-1",
({ signal }) => {
signal.addEventListener("abort", () => first.resolve("stale"), {
once: true
});
return first.promise;
},
firstController.signal
);
firstController.abort();
await expect(firstRequest.promise).rejects.toMatchObject({
name: "AbortError"
});
const retry = flight.acquire("room-1", () => second.promise);
first.resolve("late-stale");
await Promise.resolve();
const third = flight.acquire("room-1", () => Promise.resolve("unexpected"));
expect(third.shared).toBe(true);
second.resolve("fresh");
await expect(retry.promise).resolves.toBe("fresh");
await expect(third.promise).resolves.toBe("fresh");
});
});
function deferred<T>(): {
promise: Promise<T>;
resolve: (value: T) => void;
reject: (error: unknown) => void;
} {
let resolve!: (value: T) => void;
let reject!: (error: unknown) => void;
const promise = new Promise<T>((resolvePromise, rejectPromise) => {
resolve = resolvePromise;
reject = rejectPromise;
});
return { promise, reject, resolve };
}