test: refactored test suites to eliminate time-based sleeps and polling loops

- Replaced time-based sleeps and polling loops with event-driven promise resolvers and fake timers across agent and tool tests.
- Migrated test suites to share in-memory auth storage and fixtures using lifecycle hooks.
- Updated catalog model definitions, metadata, and configurations.
This commit is contained in:
can1357
2026-08-13 19:30:27 +02:00
parent 28997c0d46
commit b279db1790
263 changed files with 4603 additions and 6625 deletions
+14 -22
View File
@@ -2216,7 +2216,7 @@ describe("agentLoop with AgentMessage", () => {
let steerReady = false;
let drained = false;
let observedAbort = false;
let resolvedByTimeout = false;
const toolRelease = Promise.withResolvers<void>();
const tool: AgentTool<typeof toolSchema, Record<string, never>> = {
name: "wait",
@@ -2226,24 +2226,7 @@ describe("agentLoop with AgentMessage", () => {
interruptible: params => params.op === "wait",
async execute(_toolCallId, _params, signal) {
steerReady = true;
const { promise, resolve } = Promise.withResolvers<void>();
if (signal?.aborted) {
resolve();
} else {
const timer = setTimeout(() => {
resolvedByTimeout = true;
resolve();
}, 300);
signal?.addEventListener(
"abort",
() => {
clearTimeout(timer);
resolve();
},
{ once: true },
);
}
await promise;
if (!signal?.aborted) await toolRelease.promise;
observedAbort = signal?.aborted === true;
return { content: [{ type: "text", text: "waited" }], details: {} };
},
@@ -2260,7 +2243,11 @@ describe("agentLoop with AgentMessage", () => {
model: mock.model,
convertToLlm: identityConverter,
interruptMode: "immediate",
hasSteeringMessages: () => steerReady && !drained,
hasSteeringMessages: () => {
const queued = steerReady && !drained;
if (queued) toolRelease.resolve();
return queued;
},
getSteeringMessages: async () => {
if (steerReady && !drained) {
drained = true;
@@ -2276,7 +2263,7 @@ describe("agentLoop with AgentMessage", () => {
}
expect(observedAbort).toBe(false);
expect(resolvedByTimeout).toBe(true);
expect(steerReady).toBe(true);
expect(drained).toBe(true);
expect(
events.some(e => e.type === "message_start" && e.message.role === "user" && e.message.content === "interrupt"),
@@ -3203,7 +3190,12 @@ describe("agentLoop event-driven steering watch", () => {
// drain
}
})();
const completed = await Promise.race([drain.then(() => true), Bun.sleep(1000).then(() => false)]);
// This is the behavior under test, so retain a deadline; cancel its timer
// when teardown succeeds instead of leaving a losing sleep alive.
const timeout = Promise.withResolvers<boolean>();
const timeoutId = setTimeout(() => timeout.resolve(false), 1000);
const completed = await Promise.race([drain.then(() => true), timeout.promise]);
clearTimeout(timeoutId);
try {
expect(completed).toBe(true);
expect(executed).toEqual(["only"]);
+33 -13
View File
@@ -36,17 +36,27 @@ describe("agentPauseGate", () => {
const context: AgentContext = { systemPrompt: ["Test"], messages: [], tools: [] };
const config: AgentLoopConfig = { model: mock.model, convertToLlm: identityConverter };
const parked = Promise.withResolvers<void>();
const originalWait = agentPauseGate.waitUntilResumed;
agentPauseGate.waitUntilResumed = (signal?: AbortSignal) => {
parked.resolve();
return originalWait.call(agentPauseGate, signal);
};
expect(agentPauseGate.pause()).toBe(true);
expect(agentPauseGate.pause()).toBe(false); // already engaged
const result = agentLoop([createUserMessage("hi")], context, config, undefined, mock.stream).result();
await Bun.sleep(20);
await parked.promise;
expect(mock.calls.length).toBe(0); // parked before the first provider call
expect(agentPauseGate.resume()).toBeGreaterThanOrEqual(0);
const messages = await result;
expect(mock.calls.length).toBe(1);
expect(messages[messages.length - 1].role).toBe("assistant");
try {
expect(agentPauseGate.resume()).toBeGreaterThanOrEqual(0);
const messages = await result;
expect(mock.calls.length).toBe(1);
expect(messages[messages.length - 1].role).toBe("assistant");
} finally {
agentPauseGate.waitUntilResumed = originalWait;
}
});
it("holds tool execution at the tool boundary when paused mid-turn", async () => {
@@ -96,6 +106,12 @@ describe("agentPauseGate", () => {
const config: AgentLoopConfig = { model: mock.model, convertToLlm: identityConverter };
const abortController = new AbortController();
const parked = Promise.withResolvers<void>();
const originalWait = agentPauseGate.waitUntilResumed;
agentPauseGate.waitUntilResumed = (signal?: AbortSignal) => {
parked.resolve();
return originalWait.call(agentPauseGate, signal);
};
agentPauseGate.pause();
const result = agentLoop(
[createUserMessage("hi")],
@@ -104,19 +120,23 @@ describe("agentPauseGate", () => {
abortController.signal,
mock.stream,
).result();
await Bun.sleep(20);
await parked.promise;
abortController.abort("user interrupt");
// The run must terminate as aborted promptly (not stay parked until
// resume). The provider request itself carries the aborted signal, so
// whether the transport is entered at all is an implementation detail.
const messages = await result;
const last = messages[messages.length - 1];
expect(last.role).toBe("assistant");
if (last.role === "assistant") {
expect(last.stopReason).toBe("aborted");
try {
const messages = await result;
const last = messages[messages.length - 1];
expect(last.role).toBe("assistant");
if (last.role === "assistant") {
expect(last.stopReason).toBe("aborted");
}
expect(agentPauseGate.paused).toBe(true); // aborting one run never resumes the process
} finally {
agentPauseGate.waitUntilResumed = originalWait;
}
expect(agentPauseGate.paused).toBe(true); // aborting one run never resumes the process
});
it("re-parks a waiter when the gate is re-engaged in the same tick as resume", async () => {
@@ -128,7 +148,7 @@ describe("agentPauseGate", () => {
agentPauseGate.resume();
agentPauseGate.pause(); // re-engage before the waiter's microtask runs
await Bun.sleep(10);
await Promise.resolve();
expect(released).toBe(false);
agentPauseGate.resume();