test: tighten async wait boundaries

This commit is contained in:
Peter Steinberger
2026-04-18 17:41:47 +01:00
parent 54f121f843
commit ca1aa08709
6 changed files with 43 additions and 24 deletions

View File

@@ -323,6 +323,7 @@ describe("emitExecSystemEvent", () => {
});
expect(requestHeartbeatNowMock).toHaveBeenCalledWith(
expect.objectContaining({
coalesceMs: 0,
reason: "exec-event",
sessionKey: "agent:ops:main",
}),
@@ -341,6 +342,7 @@ describe("emitExecSystemEvent", () => {
});
expect(requestHeartbeatNowMock).toHaveBeenCalledWith(
expect.objectContaining({
coalesceMs: 0,
reason: "exec-event",
}),
);

View File

@@ -305,7 +305,7 @@ describe("exec approvals", () => {
await expect
.poll(() => (invokeParams as { params?: { runId?: string } } | undefined)?.params?.runId, {
timeout: 2000,
interval: 20,
interval: 1,
})
.toBe(approvalId);
expect(
@@ -313,7 +313,7 @@ describe("exec approvals", () => {
).toMatchObject({
suppressNotifyOnExit: true,
});
await expect.poll(() => agentParams, { timeout: 2_000, interval: 20 }).toBeTruthy();
await expect.poll(() => agentParams, { timeout: 2_000, interval: 1 }).toBeTruthy();
});
it("skips approval when node allowlist is satisfied", async () => {
@@ -768,7 +768,7 @@ describe("exec approvals", () => {
});
expect(result.details.status).toBe("approval-pending");
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 20 }).toBe(1);
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 1 }).toBe(1);
expect(agentCalls[0]).toEqual(
expect.objectContaining({
sessionKey: "agent:main:main",
@@ -809,7 +809,7 @@ describe("exec approvals", () => {
});
expect(result.details.status).toBe("approval-pending");
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 20 }).toBe(1);
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 1 }).toBe(1);
expect(agentCalls[0]).toEqual(
expect.objectContaining({
sessionKey: "agent:main:discord:channel:123",
@@ -887,7 +887,7 @@ describe("exec approvals", () => {
resolveDecision?.({ decision: "allow-once" });
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 20 }).toBe(1);
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 1 }).toBe(1);
expect(agentCalls[0]).toEqual(
expect.objectContaining({
sessionKey: "agent:main:discord:channel:123",
@@ -945,7 +945,7 @@ describe("exec approvals", () => {
expect(result.details.status).toBe("approval-pending");
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 20 }).toBe(1);
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 1 }).toBe(1);
expect(agentCalls[0]).toEqual(
expect.objectContaining({
sessionKey: "agent:main:main",
@@ -998,7 +998,7 @@ describe("exec approvals", () => {
});
expect(result.details.status).toBe("approval-pending");
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 20 }).toBe(1);
await expect.poll(() => agentCalls.length, { timeout: 3_000, interval: 1 }).toBe(1);
expect(typeof agentCalls[0]?.message).toBe("string");
expect(agentCalls[0]?.message).toContain("An async command did not run.");
expect(agentCalls[0]?.message).toContain(

View File

@@ -106,6 +106,15 @@ function buildConfig(enableNoVnc: boolean): SandboxConfig {
};
}
type EnsureSandboxBrowserParams = Parameters<typeof import("./browser.js").ensureSandboxBrowser>[0];
async function ensureTestSandboxBrowser(params: Omit<EnsureSandboxBrowserParams, "bridgeAuth">) {
return await ensureSandboxBrowser({
...params,
bridgeAuth: { token: "test-bridge-token" },
});
}
describe("ensureSandboxBrowser create args", () => {
beforeAll(async () => {
await loadFreshBrowserModulesForTest();
@@ -164,7 +173,7 @@ describe("ensureSandboxBrowser create args", () => {
});
it("publishes noVNC on loopback and injects noVNC password env", async () => {
const result = await ensureSandboxBrowser({
const result = await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -186,7 +195,7 @@ describe("ensureSandboxBrowser create args", () => {
});
it("does not inject noVNC password env when noVNC is disabled", async () => {
const result = await ensureSandboxBrowser({
const result = await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -205,7 +214,7 @@ describe("ensureSandboxBrowser create args", () => {
const cfg = buildConfig(false);
cfg.workspaceAccess = "none";
await ensureSandboxBrowser({
await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -222,7 +231,7 @@ describe("ensureSandboxBrowser create args", () => {
const cfg = buildConfig(false);
cfg.workspaceAccess = "rw";
await ensureSandboxBrowser({
await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -237,7 +246,7 @@ describe("ensureSandboxBrowser create args", () => {
});
it("stamps the mount format version label on browser containers", async () => {
await ensureSandboxBrowser({
await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -270,7 +279,7 @@ describe("ensureSandboxBrowser create args", () => {
cfg.browser.autoStartTimeoutMs = 1;
await expect(
ensureSandboxBrowser({
ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -287,7 +296,7 @@ describe("ensureSandboxBrowser create args", () => {
it("auto-derives CDP source range from Docker network gateway", async () => {
dockerMocks.readDockerNetworkGateway.mockResolvedValue("172.21.0.1");
await ensureSandboxBrowser({
await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -304,7 +313,7 @@ describe("ensureSandboxBrowser create args", () => {
const cfg = buildConfig(false);
cfg.browser.cdpSourceRange = "10.0.0.0/24";
await ensureSandboxBrowser({
await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -321,7 +330,7 @@ describe("ensureSandboxBrowser create args", () => {
dockerMocks.readDockerNetworkGateway.mockResolvedValue("fd12::1");
await expect(
ensureSandboxBrowser({
ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -334,7 +343,7 @@ describe("ensureSandboxBrowser create args", () => {
dockerMocks.readDockerNetworkGateway.mockResolvedValue(null);
await expect(
ensureSandboxBrowser({
ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -348,7 +357,7 @@ describe("ensureSandboxBrowser create args", () => {
dockerMocks.readDockerNetworkGateway.mockResolvedValue("172.21.0.1");
await expect(
ensureSandboxBrowser({
ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",
@@ -364,7 +373,7 @@ describe("ensureSandboxBrowser create args", () => {
const cfg = buildConfig(false);
cfg.browser.network = "none";
const result = await ensureSandboxBrowser({
const result = await ensureTestSandboxBrowser({
scopeKey: "session:test",
workspaceDir: "/tmp/workspace",
agentWorkspaceDir: "/tmp/workspace",

View File

@@ -66,7 +66,11 @@ async function waitForSandboxCdp(params: { cdpPort: number; timeoutMs: number })
} catch {
// ignore
}
await new Promise((r) => setTimeout(r, 150));
const remainingMs = deadline - Date.now();
if (remainingMs <= 0) {
break;
}
await new Promise((r) => setTimeout(r, Math.min(150, remainingMs)));
}
return false;
}

View File

@@ -85,7 +85,7 @@ async function expectActiveInProcessLockIsNotReclaimed(params?: {
await expect(
acquireSessionWriteLock({
sessionFile,
timeoutMs: 50,
timeoutMs: 5,
allowReentrant: false,
}),
).rejects.toThrow(/session file locked/);
@@ -165,7 +165,7 @@ describe("acquireSessionWriteLock", () => {
const lockPath = `${sessionFile}.lock`;
await fs.writeFile(
lockPath,
JSON.stringify({ pid: 123456, createdAt: new Date(Date.now() - 60_000).toISOString() }),
JSON.stringify({ pid: 2 ** 30, createdAt: new Date(Date.now() - 60_000).toISOString() }),
"utf8",
);
@@ -183,7 +183,7 @@ describe("acquireSessionWriteLock", () => {
await fs.writeFile(lockPath, "{}", "utf8");
await expect(
acquireSessionWriteLock({ sessionFile, timeoutMs: 50, staleMs: 60_000 }),
acquireSessionWriteLock({ sessionFile, timeoutMs: 5, staleMs: 60_000 }),
).rejects.toThrow(/session file locked/);
await expect(fs.access(lockPath)).resolves.toBeUndefined();
} finally {

View File

@@ -566,7 +566,11 @@ export async function acquireSessionWriteLock(params: {
continue;
}
const delay = Math.min(1000, 50 * attempt);
const remainingMs = timeoutMs - (Date.now() - startedAt);
if (remainingMs <= 0) {
break;
}
const delay = Math.min(1000, 50 * attempt, remainingMs);
await new Promise((r) => setTimeout(r, delay));
}
}