mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-11-01 16:15:24 +00:00
145 lines
4.2 KiB
TypeScript
145 lines
4.2 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
|
|
const execCommand = vi.fn();
|
|
vi.mock("../../../src/backend/proxmox/common-utils.js", () => ({
|
|
execCommand: (...args: unknown[]) => execCommand(...args),
|
|
toFixedNum: (n: number | null | undefined, digits = 2) => {
|
|
if (typeof n !== "number" || !Number.isFinite(n)) return null;
|
|
return Number(n.toFixed(digits));
|
|
},
|
|
}));
|
|
|
|
import { collectProxmoxGuestsSummary } from "../../../src/backend/proxmox/guests-collector.js";
|
|
import type { Client } from "ssh2";
|
|
|
|
const fakeClient = {} as Client;
|
|
|
|
function result(stdout: string, code: number | null = 0) {
|
|
return { stdout, stderr: "", code };
|
|
}
|
|
|
|
beforeEach(() => {
|
|
execCommand.mockReset();
|
|
});
|
|
|
|
describe("collectProxmoxGuestsSummary", () => {
|
|
it("filters to the target node, excludes templates, and computes percentages", async () => {
|
|
execCommand.mockResolvedValueOnce(
|
|
result(
|
|
JSON.stringify([
|
|
{
|
|
type: "qemu",
|
|
node: "pve1",
|
|
vmid: 100,
|
|
name: "vm-a",
|
|
status: "running",
|
|
cpu: 0.25,
|
|
mem: 2 * 1024 ** 3,
|
|
maxmem: 4 * 1024 ** 3,
|
|
disk: 10 * 1024 ** 3,
|
|
maxdisk: 40 * 1024 ** 3,
|
|
uptime: 3600,
|
|
},
|
|
{
|
|
type: "lxc",
|
|
node: "pve1",
|
|
vmid: 101,
|
|
name: "ct-b",
|
|
status: "stopped",
|
|
cpu: 0,
|
|
mem: 0,
|
|
maxmem: 512 * 1024 ** 2,
|
|
disk: 0,
|
|
maxdisk: 8 * 1024 ** 3,
|
|
uptime: 0,
|
|
},
|
|
{
|
|
// different node - excluded
|
|
type: "qemu",
|
|
node: "pve2",
|
|
vmid: 200,
|
|
name: "elsewhere",
|
|
status: "running",
|
|
},
|
|
{
|
|
// template - excluded
|
|
type: "qemu",
|
|
node: "pve1",
|
|
vmid: 999,
|
|
name: "template",
|
|
status: "stopped",
|
|
template: 1,
|
|
},
|
|
{
|
|
// non-guest resource type - excluded
|
|
type: "storage",
|
|
node: "pve1",
|
|
},
|
|
]),
|
|
),
|
|
);
|
|
|
|
const res = await collectProxmoxGuestsSummary(fakeClient, "pve1");
|
|
|
|
expect(res.guests).toHaveLength(2);
|
|
expect(res.counts).toEqual({ running: 1, stopped: 1, total: 2 });
|
|
|
|
const vmA = res.guests.find((g) => g.vmid === 100)!;
|
|
expect(vmA.cpuPercent).toBe(25);
|
|
expect(vmA.memPercent).toBe(50);
|
|
expect(vmA.diskPercent).toBe(25);
|
|
});
|
|
|
|
it("reports null disk fields (not a false 0%) when maxdisk is 0", async () => {
|
|
execCommand.mockResolvedValueOnce(
|
|
result(
|
|
JSON.stringify([
|
|
{
|
|
type: "qemu",
|
|
node: "pve1",
|
|
vmid: 100,
|
|
name: "vm-no-agent",
|
|
status: "running",
|
|
cpu: 0.1,
|
|
mem: 1024,
|
|
maxmem: 2048,
|
|
disk: 0,
|
|
maxdisk: 0,
|
|
uptime: 10,
|
|
},
|
|
]),
|
|
),
|
|
);
|
|
|
|
const res = await collectProxmoxGuestsSummary(fakeClient, "pve1");
|
|
expect(res.guests[0].diskPercent).toBeNull();
|
|
expect(res.guests[0].diskUsedGiB).toBeNull();
|
|
expect(res.guests[0].diskTotalGiB).toBeNull();
|
|
});
|
|
|
|
it("returns an empty guest list when there are no matching resources", async () => {
|
|
execCommand.mockResolvedValueOnce(result(JSON.stringify([]), 0));
|
|
const res = await collectProxmoxGuestsSummary(fakeClient, "pve1");
|
|
expect(res.guests).toEqual([]);
|
|
expect(res.counts).toEqual({ running: 0, stopped: 0, total: 0 });
|
|
});
|
|
|
|
it("returns an empty result when pvesh is missing (non-zero exit)", async () => {
|
|
execCommand.mockResolvedValueOnce(result("", 127));
|
|
const res = await collectProxmoxGuestsSummary(fakeClient, "pve1");
|
|
expect(res.guests).toEqual([]);
|
|
});
|
|
|
|
it("returns an empty result on malformed JSON", async () => {
|
|
execCommand.mockResolvedValueOnce(result("{not json", 0));
|
|
const res = await collectProxmoxGuestsSummary(fakeClient, "pve1");
|
|
expect(res.guests).toEqual([]);
|
|
});
|
|
|
|
it("rejects an unsafe node name before running any command", async () => {
|
|
const res = await collectProxmoxGuestsSummary(fakeClient, "../etc");
|
|
expect(res.guests).toEqual([]);
|
|
expect(execCommand).not.toHaveBeenCalled();
|
|
});
|
|
});
|