92 lines
2.7 KiB
TypeScript
92 lines
2.7 KiB
TypeScript
import { afterAll, describe, expect, it } from "vitest";
|
|
import processPlugin from "@composio/ao-plugin-runtime-process";
|
|
import type { RuntimeHandle } from "@composio/ao-core";
|
|
import { sleep } from "./helpers/polling.js";
|
|
|
|
describe("runtime-process (integration)", () => {
|
|
const runtime = processPlugin.create();
|
|
const sessionId = `proc-inttest-${Date.now()}`;
|
|
let handle: RuntimeHandle;
|
|
|
|
afterAll(async () => {
|
|
try {
|
|
await runtime.destroy(handle);
|
|
} catch {
|
|
/* best-effort cleanup */
|
|
}
|
|
}, 30_000);
|
|
|
|
it("creates a child process", async () => {
|
|
handle = await runtime.create({
|
|
sessionId,
|
|
workspacePath: "/tmp",
|
|
launchCommand: "cat", // cat echoes stdin to stdout
|
|
environment: { AO_TEST: "1" },
|
|
});
|
|
|
|
expect(handle.id).toBe(sessionId);
|
|
expect(handle.runtimeName).toBe("process");
|
|
expect(handle.data.pid).toBeTypeOf("number");
|
|
});
|
|
|
|
it("isAlive returns true for running process", async () => {
|
|
expect(await runtime.isAlive(handle)).toBe(true);
|
|
});
|
|
|
|
it("sendMessage writes to stdin and output is captured", async () => {
|
|
await runtime.sendMessage(handle, "hello from test");
|
|
await sleep(200); // give time for stdout to be captured
|
|
const output = await runtime.getOutput(handle);
|
|
expect(output).toContain("hello from test");
|
|
});
|
|
|
|
it("getMetrics returns uptime", async () => {
|
|
const metrics = await runtime.getMetrics!(handle);
|
|
expect(metrics.uptimeMs).toBeGreaterThan(0);
|
|
});
|
|
|
|
it("getAttachInfo returns PID", async () => {
|
|
const info = await runtime.getAttachInfo!(handle);
|
|
expect(info.type).toBe("process");
|
|
expect(info.target).toMatch(/^\d+$/);
|
|
});
|
|
|
|
it("rejects duplicate session IDs", async () => {
|
|
await expect(
|
|
runtime.create({
|
|
sessionId,
|
|
workspacePath: "/tmp",
|
|
launchCommand: "cat",
|
|
environment: {},
|
|
}),
|
|
).rejects.toThrow("already exists");
|
|
});
|
|
|
|
it("sendMessage throws for unknown session", async () => {
|
|
await expect(
|
|
runtime.sendMessage({ id: "nonexistent", runtimeName: "process", data: {} }, "hi"),
|
|
).rejects.toThrow("No process found");
|
|
});
|
|
|
|
it("destroy kills the process", async () => {
|
|
await runtime.destroy(handle);
|
|
await sleep(200); // give time for exit handler
|
|
expect(await runtime.isAlive(handle)).toBe(false);
|
|
});
|
|
|
|
it("getOutput returns empty for destroyed session", async () => {
|
|
const output = await runtime.getOutput(handle);
|
|
expect(output).toBe("");
|
|
});
|
|
|
|
it("isAlive returns false for unknown session", async () => {
|
|
expect(await runtime.isAlive({ id: "nonexistent", runtimeName: "process", data: {} })).toBe(
|
|
false,
|
|
);
|
|
});
|
|
|
|
it("destroy is idempotent", async () => {
|
|
await runtime.destroy(handle); // should not throw
|
|
});
|
|
});
|