




















@@ -0,0 +1,116 @@
1+import { EventEmitter } from "node:events";
2+import { Readable } from "node:stream";
3+import { beforeEach, describe, expect, it, vi } from "vitest";
4+import { DEFAULT_SANDBOX_IMAGE } from "./constants.js";
5+6+type SpawnCall = {
7+command: string;
8+args: string[];
9+};
10+11+type MockDockerChild = EventEmitter & {
12+stdout: Readable;
13+stderr: Readable;
14+stdin: { end: (input?: string | Buffer) => void };
15+kill: (signal?: NodeJS.Signals) => void;
16+};
17+18+const spawnState = vi.hoisted(() => ({
19+calls: [] as SpawnCall[],
20+imageExists: true,
21+}));
22+23+function createMockDockerChild(): MockDockerChild {
24+const child = new EventEmitter() as MockDockerChild;
25+child.stdout = new Readable({ read() {} });
26+child.stderr = new Readable({ read() {} });
27+child.stdin = { end: () => undefined };
28+child.kill = () => undefined;
29+return child;
30+}
31+32+function spawnDockerProcess(command: string, args: string[]) {
33+spawnState.calls.push({ command, args });
34+const child = createMockDockerChild();
35+36+let code = 0;
37+let stderr = "";
38+if (command !== "docker") {
39+code = 1;
40+stderr = `unexpected command: ${command}`;
41+} else if (args[0] === "image" && args[1] === "inspect") {
42+code = spawnState.imageExists ? 0 : 1;
43+stderr = spawnState.imageExists ? "" : `Error response from daemon: No such image: ${args[2]}`;
44+} else if (args[0] === "pull" || args[0] === "tag") {
45+code = 0;
46+} else {
47+code = 1;
48+stderr = `unexpected docker args: ${args.join(" ")}`;
49+}
50+51+queueMicrotask(() => {
52+if (stderr) {
53+child.stderr.emit("data", Buffer.from(stderr));
54+}
55+child.emit("close", code);
56+});
57+return child;
58+}
59+60+async function createChildProcessMock() {
61+const actual = await vi.importActual<typeof import("node:child_process")>("node:child_process");
62+return {
63+ ...actual,
64+spawn: spawnDockerProcess,
65+};
66+}
67+68+vi.mock("node:child_process", async () => createChildProcessMock());
69+70+let ensureDockerImage: typeof import("./docker.js").ensureDockerImage;
71+72+async function loadFreshDockerModuleForTest() {
73+vi.resetModules();
74+vi.doMock("node:child_process", async () => createChildProcessMock());
75+({ ensureDockerImage } = await import("./docker.js"));
76+}
77+78+describe("ensureDockerImage", () => {
79+beforeEach(async () => {
80+spawnState.calls.length = 0;
81+spawnState.imageExists = true;
82+await loadFreshDockerModuleForTest();
83+});
84+85+it("returns when the configured image already exists", async () => {
86+await ensureDockerImage(DEFAULT_SANDBOX_IMAGE);
87+88+expect(spawnState.calls).toEqual([
89+{
90+command: "docker",
91+args: ["image", "inspect", DEFAULT_SANDBOX_IMAGE],
92+},
93+]);
94+});
95+96+it("does not satisfy the missing default sandbox image by tagging plain Debian", async () => {
97+spawnState.imageExists = false;
98+99+let err: unknown;
100+try {
101+await ensureDockerImage(DEFAULT_SANDBOX_IMAGE);
102+} catch (caught) {
103+err = caught;
104+}
105+106+expect(err).toBeInstanceOf(Error);
107+expect((err as Error).message).toContain("scripts/sandbox-setup.sh");
108+expect((err as Error).message).toContain("python3");
109+expect(spawnState.calls).toEqual([
110+{
111+command: "docker",
112+args: ["image", "inspect", DEFAULT_SANDBOX_IMAGE],
113+},
114+]);
115+});
116+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。