156 lines
7.1 KiB
TypeScript
156 lines
7.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
||
import { chvAttachmentBlocked, chvAvailability, chvAvailabilityText, chvQueueHint, chvVmBadge, chvVmDisplay, chvVmStatusText, countChvWorkers, isChvExecutor, isWorkerAlive } from "./chv";
|
||
|
||
// 纯逻辑测试:只测 chv.ts,不渲染组件、不发请求、不读 localStorage。
|
||
// alive 规则与 WorkersSection 现有口径一致:alive 字段优先,
|
||
// 缺失时用 last_seen 距今 <= 120 秒判定在线。
|
||
describe("isWorkerAlive", () => {
|
||
it("alive 字段优先", () => {
|
||
expect(isWorkerAlive({ executor: "cloud-hypervisor", alive: true })).toBe(true);
|
||
expect(isWorkerAlive({ executor: "cloud-hypervisor", alive: false, last_seen: Date.now() / 1000 })).toBe(false);
|
||
});
|
||
it("无 alive 时用 last_seen 120 秒门槛", () => {
|
||
const now = Date.now() / 1000;
|
||
expect(isWorkerAlive({ executor: "cloud-hypervisor", last_seen: now - 10 })).toBe(true);
|
||
expect(isWorkerAlive({ executor: "cloud-hypervisor", last_seen: now - 121 })).toBe(false);
|
||
expect(isWorkerAlive({ executor: "cloud-hypervisor" })).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe("countChvWorkers", () => {
|
||
it("只数 cloud-hypervisor,不数 docker/local", () => {
|
||
const now = Date.now() / 1000;
|
||
expect(countChvWorkers([
|
||
{ executor: "cloud-hypervisor", alive: true },
|
||
{ executor: "cloud-hypervisor", last_seen: now - 9999 },
|
||
{ executor: "docker", alive: true },
|
||
])).toEqual({ online: 1, total: 2 });
|
||
});
|
||
});
|
||
|
||
describe("chvAvailability", () => {
|
||
it("有清单时按清单数", () => {
|
||
expect(chvAvailability([{ executor: "cloud-hypervisor", alive: true }], "", "")).toEqual(
|
||
{ state: "known", online: 1, total: 1 },
|
||
);
|
||
});
|
||
it("无清单但聚合文案时是未知,不是 0", () => {
|
||
expect(chvAvailability(null, "在线 2 / 离线 1(共 3;完整 worker 清单仅全局管理员可见)", "")).toEqual(
|
||
{ state: "unknown", reason: "aggregate-only" },
|
||
);
|
||
});
|
||
it("无 worker 注册时是已知 0", () => {
|
||
expect(chvAvailability(null, "无 worker 注册", "")).toEqual({ state: "known", online: 0, total: 0 });
|
||
});
|
||
it("加载失败时是未知", () => {
|
||
expect(chvAvailability(null, "", "加载失败:x")).toEqual({ state: "unknown", reason: "load-failed" });
|
||
});
|
||
it("尚未加载时是未知", () => {
|
||
expect(chvAvailability(null, "未加载", "")).toEqual({ state: "unknown", reason: "not-loaded" });
|
||
});
|
||
});
|
||
|
||
describe("isChvExecutor", () => {
|
||
it("精确值才算 CHV,不做大小写/前缀宽松匹配", () => {
|
||
expect(isChvExecutor("cloud-hypervisor")).toBe(true);
|
||
expect(isChvExecutor("Cloud-Hypervisor")).toBe(false);
|
||
expect(isChvExecutor("cloud-hypervisor-x")).toBe(false);
|
||
expect(isChvExecutor("docker")).toBe(false);
|
||
expect(isChvExecutor(undefined)).toBe(false);
|
||
expect(isChvExecutor(null)).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe("chvAttachmentBlocked", () => {
|
||
it("仅 CHV + 带附件时拦(后端 400 的前端提示口径)", () => {
|
||
expect(chvAttachmentBlocked("cloud-hypervisor", true)).toBe(true);
|
||
expect(chvAttachmentBlocked("cloud-hypervisor", false)).toBe(false);
|
||
expect(chvAttachmentBlocked("docker", true)).toBe(false);
|
||
expect(chvAttachmentBlocked("cloud", true)).toBe(false);
|
||
});
|
||
});
|
||
|
||
describe("chvVmStatusText", () => {
|
||
it("已报告死亡时给死亡文案", () => {
|
||
expect(chvVmStatusText({ executor: "cloud-hypervisor", chv_vm_dead: true })).toContain("VM 中途死亡");
|
||
});
|
||
it("CHV 无字段时给未报告文案,绝不写成活着", () => {
|
||
const text = chvVmStatusText({ executor: "cloud-hypervisor" });
|
||
expect(text).toContain("未报告 VM 死亡");
|
||
expect(text).toContain("不代表 VM 活着");
|
||
});
|
||
it("非 CHV 任务不显示 VM 行", () => {
|
||
expect(chvVmStatusText({ executor: "docker" })).toBe("");
|
||
expect(chvVmStatusText({ executor: "docker", chv_vm_dead: true })).toBe("");
|
||
});
|
||
});
|
||
|
||
describe("chvVmBadge", () => {
|
||
it("只有 CHV + 已报告死亡时才出徽标", () => {
|
||
expect(chvVmBadge({ executor: "cloud-hypervisor", chv_vm_dead: true })).toBe("VM 已报告死亡");
|
||
expect(chvVmBadge({ executor: "cloud-hypervisor" })).toBe("");
|
||
expect(chvVmBadge({ executor: "docker", chv_vm_dead: true })).toBe("");
|
||
});
|
||
});
|
||
|
||
describe("chvQueueHint", () => {
|
||
it("仅 CHV + 排队 + 已知零在线时给提示", () => {
|
||
const knownZero = { state: "known" as const, online: 0, total: 0 };
|
||
expect(chvQueueHint("cloud-hypervisor", "queued", knownZero)).toContain("可能原因");
|
||
expect(chvQueueHint("docker", "queued", knownZero)).toBe("");
|
||
expect(chvQueueHint("cloud-hypervisor", "running", knownZero)).toBe("");
|
||
expect(chvQueueHint("cloud-hypervisor", "queued", { state: "unknown" as const, reason: "aggregate-only" })).toBe("");
|
||
expect(chvQueueHint("cloud-hypervisor", "queued", { state: "known" as const, online: 1, total: 1 })).toBe("");
|
||
});
|
||
});
|
||
|
||
describe("chvVmDisplay(to10 四态)", () => {
|
||
it("字段 present=true → dead", () => {
|
||
const d = chvVmDisplay({ executor: "cloud-hypervisor", chv_vm_dead: true });
|
||
expect(d.state).toBe("dead");
|
||
expect(d.text).toContain("VM 中途死亡");
|
||
});
|
||
it("字段 absent → not-reported,不猜 live", () => {
|
||
const d = chvVmDisplay({ executor: "cloud-hypervisor" });
|
||
expect(d.state).toBe("not-reported");
|
||
expect(d.text).toContain("不代表 VM 活着");
|
||
});
|
||
it("任务未加载 → unknown", () => {
|
||
const d = chvVmDisplay(null);
|
||
expect(d.state).toBe("unknown");
|
||
expect(d.text).toContain("无法判断");
|
||
});
|
||
it("非 CHV → not-applicable,text 为空", () => {
|
||
const d = chvVmDisplay({ executor: "docker", chv_vm_dead: true });
|
||
expect(d.state).toBe("not-applicable");
|
||
expect(d.text).toBe("");
|
||
});
|
||
it("旧入口仍是 display 的 text(unknown/not-applicable 回空)", () => {
|
||
expect(chvVmStatusText({ executor: "cloud-hypervisor", chv_vm_dead: true })).toContain("VM 中途死亡");
|
||
expect(chvVmStatusText(null)).toBe("");
|
||
expect(chvVmStatusText({ executor: "docker" })).toBe("");
|
||
});
|
||
});
|
||
|
||
describe("chvAvailabilityText(to10 四处统一文案)", () => {
|
||
it("known 零在线:不拦提交、后端是最终权威", () => {
|
||
const text = chvAvailabilityText({ state: "known", online: 0, total: 2 });
|
||
expect(text).toContain("在线 0 / 共 2");
|
||
expect(text).toContain("不拦提交");
|
||
expect(text).toContain("最终权威");
|
||
});
|
||
it("known 非零:只有在线数,无排队警告", () => {
|
||
const text = chvAvailabilityText({ state: "known", online: 1, total: 1 });
|
||
expect(text).toContain("在线 1 / 共 1");
|
||
expect(text).not.toContain("排队");
|
||
});
|
||
it("未知三原因各有不同文案,绝不写成 0", () => {
|
||
expect(chvAvailabilityText({ state: "unknown", reason: "aggregate-only" })).toContain("仅全局管理员可见");
|
||
expect(chvAvailabilityText({ state: "unknown", reason: "load-failed" })).toContain("加载失败");
|
||
expect(chvAvailabilityText({ state: "unknown", reason: "not-loaded" })).toContain("尚未加载");
|
||
for (const reason of ["aggregate-only", "load-failed", "not-loaded"] as const) {
|
||
expect(chvAvailabilityText({ state: "unknown", reason })).not.toContain("在线 0");
|
||
}
|
||
});
|
||
});
|