Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 28 additions & 8 deletions apps/worker/src/sandbox/poll-agent.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { Sandbox } from "@vercel/sandbox";

const mockRunCommand = vi.fn();
const mockStop = vi.fn();
Expand All @@ -17,6 +16,7 @@ vi.mock("@vercel/sandbox", () => ({

vi.mock("./credentials.js", () => ({ getSandboxCredentials: () => ({}) }));

const { Sandbox } = await import("@vercel/sandbox");
const mockSandboxGet = Sandbox.get as unknown as ReturnType<typeof vi.fn>;

function resetSandboxMocks() {
Expand Down Expand Up @@ -162,18 +162,27 @@ describe("collectPhaseOutput", () => {

it("bounds an artifact read that never settles with the deterministic deadline error", async () => {
vi.useFakeTimers();
mockRunCommand.mockImplementationOnce(() => new Promise(() => {}));
let rejectRunCommand!: (reason: Error) => void;
const pendingRunCommand = new Promise<ReturnType<typeof result>>((_resolve, reject) => {
rejectRunCommand = reject;
});
const pendingRunCommandSettled = pendingRunCommand.catch(() => undefined);
mockRunCommand.mockImplementation(() => pendingRunCommand);
let failure: unknown;
void collectPhaseOutput("sbx-test-123", "/tmp/stdout", "/tmp/stderr").catch(
(error) => {
failure = error;
},
);

await vi.advanceTimersByTimeAsync(0);
for (let i = 0; i < 100 && mockRunCommand.mock.calls.length === 0; i += 1) {
await vi.advanceTimersByTimeAsync(1);
}
await vi.advanceTimersByTimeAsync(60_000);

expect(failure).toMatchObject({ name: "SandboxDeadlineError", deadlineMs: 60_000 });
rejectRunCommand(new Error("test cleanup"));
await pendingRunCommandSettled;
});

it("aborts a stdout stream that never settles when the artifact deadline expires", async () => {
Expand All @@ -183,7 +192,7 @@ describe("collectPhaseOutput", () => {
signal.addEventListener("abort", () => reject(signal.reason));
}),
);
mockRunCommand.mockResolvedValueOnce({ ...result(), stdout });
mockRunCommand.mockImplementation(() => Promise.resolve({ ...result(), stdout }));

let failure: unknown;
void collectPhaseOutput("sbx-test-123", "/tmp/stdout", "/tmp/stderr").catch(
Expand Down Expand Up @@ -247,15 +256,22 @@ describe("collectPhase", () => {
exitCode: "/tmp/exit-code",
}).catch((error) => { failure = error; });

await vi.advanceTimersByTimeAsync(0);
for (let i = 0; i < 100 && mockSandboxGet.mock.calls.length === 0; i += 1) {
await vi.advanceTimersByTimeAsync(1);
}
await vi.advanceTimersByTimeAsync(60_000);

expect(failure).toMatchObject({ name: "SandboxDeadlineError", deadlineMs: 60_000 });
});

it("bounds an artifact read that never settles with the deterministic deadline error", async () => {
vi.useFakeTimers();
mockRunCommand.mockImplementationOnce(() => new Promise(() => {}));
let rejectRunCommand!: (reason: Error) => void;
const pendingRunCommand = new Promise<ReturnType<typeof result>>((_resolve, reject) => {
rejectRunCommand = reject;
});
const pendingRunCommandSettled = pendingRunCommand.catch(() => undefined);
mockRunCommand.mockImplementation(() => pendingRunCommand);
let failure: unknown;
void collectPhase("sbx-test-123", {
stdout: "/tmp/stdout",
Expand All @@ -264,10 +280,14 @@ describe("collectPhase", () => {
exitCode: "/tmp/exit-code",
}).catch((error) => { failure = error; });

await vi.advanceTimersByTimeAsync(0);
for (let i = 0; i < 100 && mockRunCommand.mock.calls.length === 0; i += 1) {
await vi.advanceTimersByTimeAsync(1);
}
await vi.advanceTimersByTimeAsync(60_000);

expect(failure).toMatchObject({ name: "SandboxDeadlineError", deadlineMs: 60_000 });
rejectRunCommand(new Error("test cleanup"));
await pendingRunCommandSettled;
});

it("aborts a stdout stream that never settles when the artifact deadline expires", async () => {
Expand All @@ -277,7 +297,7 @@ describe("collectPhase", () => {
signal.addEventListener("abort", () => reject(signal.reason));
}),
);
mockRunCommand.mockResolvedValueOnce({ ...result(), stdout });
mockRunCommand.mockImplementation(() => Promise.resolve({ ...result(), stdout }));

let failure: unknown;
void collectPhase("sbx-test-123", {
Expand Down
Loading