openclaw / src /cli /fleet-cli /register.test.ts
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
eb3f11e verified
Raw
History Blame Contribute Delete
6.39 kB
import { Command } from "commander";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { registerFleetCli } from "../fleet-cli.js";
const mocks = await vi.hoisted(async () => {
const { createCliRuntimeMock } = await import("../test-runtime-mock.js");
return {
...createCliRuntimeMock(vi),
runFleetCreateCommand: vi.fn(),
runFleetListCommand: vi.fn(),
runFleetStatusCommand: vi.fn(),
runFleetLogsCommand: vi.fn(),
runFleetLifecycleCommand: vi.fn(),
runFleetUpgradeCommand: vi.fn(),
runFleetRemoveCommand: vi.fn(),
runFleetBackupCommand: vi.fn(),
runFleetRestoreCommand: vi.fn(),
runFleetDoctorCommand: vi.fn(),
};
});
vi.mock("../../runtime.js", () => ({
defaultRuntime: mocks.defaultRuntime,
}));
vi.mock("./commands.runtime.js", () => ({
runFleetCreateCommand: mocks.runFleetCreateCommand,
runFleetListCommand: mocks.runFleetListCommand,
runFleetStatusCommand: mocks.runFleetStatusCommand,
runFleetLogsCommand: mocks.runFleetLogsCommand,
runFleetLifecycleCommand: mocks.runFleetLifecycleCommand,
runFleetUpgradeCommand: mocks.runFleetUpgradeCommand,
runFleetRemoveCommand: mocks.runFleetRemoveCommand,
runFleetBackupCommand: mocks.runFleetBackupCommand,
runFleetRestoreCommand: mocks.runFleetRestoreCommand,
runFleetDoctorCommand: mocks.runFleetDoctorCommand,
}));
function createProgram(): Command {
const program = new Command();
program.exitOverride();
program.configureOutput({
writeErr: () => undefined,
writeOut: () => undefined,
});
registerFleetCli(program);
return program;
}
async function runFleetCli(argv: string[]): Promise<void> {
await createProgram().parseAsync(["fleet", ...argv], { from: "user" });
}
describe("fleet cli", () => {
beforeEach(() => {
vi.clearAllMocks();
mocks.runtimeLogs.length = 0;
mocks.runtimeErrors.length = 0;
});
it("normalizes create options", async () => {
await runFleetCli([
"create",
"tenant-a",
"--image",
"registry.example/openclaw:v1",
"--runtime",
"podman",
"--port",
"19123",
"--memory",
"3g",
"--cpus",
"1.5",
"--disk",
"10GB",
"--network",
"internal",
"--pids-limit",
"256",
"--env",
"CHANNEL_ID=alpha",
"--env",
"FEATURE_FLAG=1",
"--gateway-token",
"test-token",
"--no-start",
"--json",
]);
expect(mocks.runFleetCreateCommand).toHaveBeenCalledOnce();
expect(mocks.runFleetCreateCommand).toHaveBeenCalledWith({
tenant: "tenant-a",
image: "registry.example/openclaw:v1",
runtime: "podman",
port: 19_123,
memory: "3g",
cpus: "1.5",
disk: "10GB",
network: "internal",
pidsLimit: 256,
env: ["CHANNEL_ID=alpha", "FEATURE_FLAG=1"],
gatewayToken: "test-token",
start: false,
json: true,
});
});
it("applies create defaults", async () => {
await runFleetCli(["create", "tenant-b"]);
expect(mocks.runFleetCreateCommand).toHaveBeenCalledWith({
tenant: "tenant-b",
image: "ghcr.io/openclaw/openclaw:latest",
runtime: "docker",
port: undefined,
memory: "2g",
cpus: "2",
disk: undefined,
network: "bridge",
pidsLimit: 512,
env: [],
gatewayToken: undefined,
start: true,
json: false,
});
});
it.each(["list", "ls"])("routes fleet %s JSON output", async (command) => {
await runFleetCli([command, "--json"]);
expect(mocks.runFleetListCommand).toHaveBeenCalledOnce();
expect(mocks.runFleetListCommand).toHaveBeenCalledWith({ json: true });
});
it("normalizes logs options", async () => {
await runFleetCli([
"logs",
"acme",
"--follow",
"--timestamps",
"--tail",
"100",
"--since",
"10m",
]);
expect(mocks.runFleetLogsCommand).toHaveBeenCalledWith({
tenant: "acme",
follow: true,
timestamps: true,
tail: 100,
since: "10m",
});
});
it("normalizes remove safety flags", async () => {
await runFleetCli(["rm", "tenant-a", "--purge-data", "--force"]);
expect(mocks.runFleetRemoveCommand).toHaveBeenCalledOnce();
expect(mocks.runFleetRemoveCommand).toHaveBeenCalledWith({
tenant: "tenant-a",
purgeData: true,
force: true,
});
});
it("registers backup, restore, logs, and doctor options", async () => {
await runFleetCli([
"backup",
"tenant-a",
"--out",
"/tmp/cell.tgz",
"--max-bytes",
"42",
"--json",
]);
await runFleetCli(["restore", "tenant-a", "--from", "/tmp/cell.tgz", "--force", "--json"]);
await runFleetCli(["logs", "tenant-a", "--tail", "500", "--since", "10m"]);
await runFleetCli(["doctor", "tenant-a", "--json"]);
expect(mocks.runFleetBackupCommand).toHaveBeenCalledWith({
tenant: "tenant-a",
out: "/tmp/cell.tgz",
maxBytes: 42,
json: true,
});
expect(mocks.runFleetRestoreCommand).toHaveBeenCalledWith({
tenant: "tenant-a",
from: "/tmp/cell.tgz",
force: true,
json: true,
});
expect(mocks.runFleetLogsCommand).toHaveBeenCalledWith({
tenant: "tenant-a",
follow: false,
timestamps: false,
tail: 500,
since: "10m",
});
expect(mocks.runFleetDoctorCommand).toHaveBeenCalledWith({ tenant: "tenant-a", json: true });
});
it.each([
[["create", "tenant-a", "--runtime", "containerd"], /--runtime must be docker or podman/],
[["create", "tenant-a", "--port", "65536"], /--port must be between 1 and 65535/],
[["create", "tenant-a", "--cpus", "0"], /--cpus must be a positive number/],
[["create", "tenant-a", "--cpus", "0x10"], /--cpus must be a positive number/],
[["logs", "tenant-a", "--tail", "1.5"], /--tail must be a positive integer/],
[["create", "tenant-a", "--disk", "10 g"], /--disk/],
[["create", "tenant-a", "--network", "none"], /--network must be bridge or internal/],
[["restore", "tenant-a"], /required option '--from/],
])("rejects invalid options: %s", async (argv, error) => {
await expect(runFleetCli(argv)).rejects.toThrow(error);
expect(mocks.runFleetCreateCommand).not.toHaveBeenCalled();
expect(mocks.runFleetLogsCommand).not.toHaveBeenCalled();
});
});