- Update generated types from new openapi.yaml (capsule stats, usage, metrics, pause/resume lifecycle, host/channel management, auth flow) - Add Capsule pause/resume/ping/getMetrics lifecycle methods - Add Capsule.waitForReady abort signal support - Add PtyManager.connect and PtySession disposal - Fix HttpClient empty-body response handling (content-length: 0) - Add streamProcess() to CommandManager for background process streams - Add integration tests for capsule lifecycle, git, and PTY features - Add unit tests for AsyncQueue error paths, PtySession.close, Git.checkout without create, Git.add single string, Notebook.execCell error case, and PtyStartOptions fields
90 lines
2.3 KiB
TypeScript
90 lines
2.3 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import { Capsule } from "../src/capsule.js";
|
|
import { CodeInterpreter } from "../src/code-interpreter/index.js";
|
|
|
|
describe("CodeInterpreter", () => {
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
});
|
|
|
|
it("creates a capsule with the jupyter template by default", async () => {
|
|
const create = vi.spyOn(Capsule, "create").mockResolvedValue(
|
|
new Capsule("cap_1", {
|
|
baseUrl: "https://api.example.com",
|
|
}),
|
|
);
|
|
|
|
const interpreter = await CodeInterpreter.create({
|
|
baseUrl: "https://api.example.com",
|
|
});
|
|
|
|
expect(interpreter.capsule.id).toBe("cap_1");
|
|
expect(create).toHaveBeenCalledWith("jupyter", {
|
|
baseUrl: "https://api.example.com",
|
|
});
|
|
});
|
|
|
|
it("connects to an existing capsule", () => {
|
|
const interpreter = CodeInterpreter.connect("cap_1", {
|
|
baseUrl: "https://api.example.com",
|
|
});
|
|
|
|
expect(interpreter.capsule.id).toBe("cap_1");
|
|
});
|
|
|
|
it("executes notebook cells through python3", async () => {
|
|
const capsule = new Capsule("cap_1", {
|
|
baseUrl: "https://api.example.com",
|
|
});
|
|
const exec = vi.spyOn(capsule.commands, "exec").mockResolvedValue({
|
|
exit_code: 0,
|
|
stderr: "",
|
|
stdout: "42\n",
|
|
});
|
|
const interpreter = new CodeInterpreter(capsule);
|
|
|
|
await expect(
|
|
interpreter.notebook.execCell("print(6 * 7)"),
|
|
).resolves.toEqual({
|
|
exitCode: 0,
|
|
stderr: "",
|
|
stdout: "42\n",
|
|
});
|
|
expect(exec).toHaveBeenCalledWith("python3", {
|
|
args: ["-c", "print(6 * 7)"],
|
|
timeoutSec: 30,
|
|
});
|
|
});
|
|
|
|
it("returns stderr and non-zero exit code on failure", async () => {
|
|
const capsule = new Capsule("cap_1", {
|
|
baseUrl: "https://api.example.com",
|
|
});
|
|
vi.spyOn(capsule.commands, "exec").mockResolvedValue({
|
|
exit_code: 1,
|
|
stderr: "SyntaxError: invalid syntax\n",
|
|
stdout: "",
|
|
});
|
|
const interpreter = new CodeInterpreter(capsule);
|
|
|
|
await expect(interpreter.notebook.execCell("invalid(")).resolves.toEqual({
|
|
exitCode: 1,
|
|
stderr: "SyntaxError: invalid syntax\n",
|
|
stdout: "",
|
|
});
|
|
});
|
|
|
|
it("disposes the wrapped capsule", async () => {
|
|
const capsule = new Capsule("cap_1", {
|
|
baseUrl: "https://api.example.com",
|
|
});
|
|
const dispose = vi.spyOn(capsule, Symbol.asyncDispose).mockResolvedValue();
|
|
const interpreter = new CodeInterpreter(capsule);
|
|
|
|
await interpreter[Symbol.asyncDispose]();
|
|
|
|
expect(dispose).toHaveBeenCalledOnce();
|
|
});
|
|
});
|