Files
js-sdk/tests/integration/capsule.integration.test.ts
Tasnim Kabir Sadik 349b230913 feat: align SDK with updated OpenAPI spec and add missing unit tests
- 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
2026-05-16 19:14:55 +06:00

126 lines
3.3 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { Capsule, type CapsuleCreateOptions } from "../../src/capsule.js";
import { DEFAULT_BASE_URL } from "../../src/config.js";
const baseUrl = process.env.WRENN_BASE_URL ?? DEFAULT_BASE_URL;
const apiKey = process.env.WRENN_API_KEY;
const template = process.env.WRENN_TEST_TEMPLATE ?? "minimal";
const waitTimeoutMs = Number(process.env.WRENN_TEST_WAIT_TIMEOUT_MS ?? 120_000);
const describeWithApiKey = apiKey ? describe : describe.skip;
const clientOpts: CapsuleCreateOptions = { baseUrl };
if (apiKey) clientOpts.apiKey = apiKey;
describeWithApiKey("Capsule live integration", () => {
it(
"creates, waits for, inspects, pings, and destroys a live capsule",
async () => {
let capsule: Capsule | undefined;
try {
capsule = await Capsule.create(template, {
...clientOpts,
timeout_sec: 60,
});
expect(capsule.id).toBeTypeOf("string");
expect(capsule.id.length).toBeGreaterThan(0);
const ready = await capsule.waitForReady({
intervalMs: 2_000,
timeoutMs: waitTimeoutMs,
});
expect(ready).toMatchObject({ id: capsule.id, status: "running" });
const connected = Capsule.connect(capsule.id, clientOpts);
const info = await connected.getInfo();
expect(info.id).toBe(capsule.id);
await expect(connected.ping()).resolves.toBeUndefined();
const metrics = await connected.getMetrics({ range: "10m" });
expect(metrics).toBeTypeOf("object");
await connected.close();
await connected[Symbol.asyncDispose]();
await Capsule.destroy(capsule.id, clientOpts);
capsule = undefined;
} finally {
if (capsule) {
await Capsule.destroy(capsule.id, clientOpts).catch(() => undefined);
}
}
},
waitTimeoutMs + 30_000,
);
it(
"pauses and resumes a live capsule through high-level methods",
async () => {
let capsule: Capsule | undefined;
try {
capsule = await Capsule.create(template, {
...clientOpts,
timeout_sec: 60,
});
await capsule.waitForReady({
intervalMs: 2_000,
timeoutMs: waitTimeoutMs,
});
const paused = await capsule.pause();
expect(paused).toMatchObject({ id: capsule.id });
expect(paused.status).toBe("paused");
const resumed = await capsule.resume({
intervalMs: 2_000,
timeoutMs: waitTimeoutMs,
wait: true,
});
expect(resumed).toMatchObject({ id: capsule.id, status: "running" });
} finally {
if (capsule) {
await Capsule.destroy(capsule.id, clientOpts).catch(() => undefined);
}
}
},
waitTimeoutMs * 2 + 30_000,
);
it(
"destroys an owned live capsule when async disposed",
async () => {
let capsuleId: string | undefined;
try {
const capsule = await Capsule.create(template, {
...clientOpts,
timeout_sec: 60,
});
capsuleId = capsule.id;
await capsule.waitForReady({
intervalMs: 2_000,
timeoutMs: waitTimeoutMs,
});
await capsule[Symbol.asyncDispose]();
await expect(
Capsule.connect(capsuleId, clientOpts).getInfo(),
).resolves.toMatchObject({ id: capsuleId, status: "stopped" });
capsuleId = undefined;
} finally {
if (capsuleId) {
await Capsule.destroy(capsuleId, clientOpts).catch(() => undefined);
}
}
},
waitTimeoutMs + 30_000,
);
});