feat-chv-closeup:收尾(executor 覆盖到 100%、合并/灰度准备,堆叠于 #264)
- 后端新增 cloud/tests/test_chv_closeup.py 85 项:唤醒失败 (vm.create/vm.boot/API 超时/guest 就绪超时/host key 不匹配/ provisioned 缺钉死)、恢复与快照失败、取消与清理(残留 socket/登记/磁盘/密钥、脏标记)、中途死亡分类、只读 execute 归类、入口校验、preflight 事后改写、防御性 except、worker_adapter 剩余分支;executor.py 覆盖 100%。 - 前端新增 src/api/chv.closeup.test.ts 13 项:显式 false、 undefined、可用性优先级、Workers 旧 bug 文案不复发、 120 秒边界;控制按钮与新页面仍不做。 - 新增 tools/chv_merge_precheck.py(只读):逐个核 base/head/ mergeable/CI/链衔接,实测 11 个 PR 全 NOT-READY(CI 全 FAIL、mergeState 全 UNSTABLE),退出码 1,绝不合并。 - docs/chv-production-readiness.md 新增 §14:审计落盘运维 runbook(定位/轮转/读取/清理,ADR-14 取舍不变)、mypy 默认口径 2 错评估(沙箱验证过的标注修法,本轨不改 其它链文件)、灰度三阶段可执行清单、V-1~V-9 检查表 (全部未验证)、逐项评分。 - 安全语义不变:egress、key seed 投递、磁盘删除、默认 provisioned、tap 校验、前端不绕后端白名单均未放宽。 - 只到 PR OPEN,不合并、不部署;CI 账单仍是硬门禁。
This commit is contained in:
1 parent
2f3ff8b3ec
commit
54f20dfe55
4 files changed
+1759
No files matched your search
@@ -0,0 +1,76 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { chvAttachmentBlocked, chvAvailability, chvAvailabilityText, chvQueueHint, chvVmBadge, chvVmDisplay, chvVmStatusText, countChvWorkers, isWorkerAlive } from "./chv";
|
||||
|
||||
// closeup 轨补边角:上一轨 chv.test.ts 已覆主路径后仍缺的
|
||||
// 显式 false、undefined、优先级与“旧 bug 文案不复发”断言。
|
||||
// 只测 chv.ts 纯逻辑,不渲染组件、不发请求。
|
||||
describe("chvVmDisplay 边角(closeup)", () => {
|
||||
it("字段显式 false 与 absent 同属 not-reported", () => {
|
||||
const d = chvVmDisplay({ executor: "cloud-hypervisor", chv_vm_dead: false });
|
||||
expect(d.state).toBe("not-reported");
|
||||
expect(d.text).toContain("不代表 VM 活着");
|
||||
});
|
||||
it("任务 undefined 与 null 同属 unknown", () => {
|
||||
expect(chvVmDisplay(undefined).state).toBe("unknown");
|
||||
expect(chvVmDisplay(undefined).text).toContain("无法判断");
|
||||
});
|
||||
it("非 CHV 且无 executor 字段时也是 not-applicable", () => {
|
||||
expect(chvVmDisplay({}).state).toBe("not-applicable");
|
||||
expect(chvVmDisplay({ executor: undefined }).text).toBe("");
|
||||
expect(chvVmStatusText({ executor: "cloud-hypervisor", chv_vm_dead: false })).toContain("未报告 VM 死亡");
|
||||
});
|
||||
it("列表徽标:显式 false 不出徽标", () => {
|
||||
expect(chvVmBadge({ executor: "cloud-hypervisor", chv_vm_dead: false })).toBe("");
|
||||
});
|
||||
});
|
||||
|
||||
describe("chvAvailability 优先级(closeup)", () => {
|
||||
it("加载失败优先于聚合文案:不把失败写成 aggregate-only", () => {
|
||||
expect(chvAvailability(null, "完整 worker 清单仅全局管理员可见", "加载失败:x")).toEqual(
|
||||
{ state: "unknown", reason: "load-failed" },
|
||||
);
|
||||
});
|
||||
it("有清单时忽略错误与聚合文案", () => {
|
||||
expect(chvAvailability([{ executor: "cloud-hypervisor", alive: false }], "完整 worker 清单仅全局管理员可见", "加载失败:x")).toEqual(
|
||||
{ state: "known", online: 0, total: 1 },
|
||||
);
|
||||
});
|
||||
it("空清单与空文案是 not-loaded,不是已知 0", () => {
|
||||
expect(chvAvailability(null, "", "")).toEqual({ state: "unknown", reason: "not-loaded" });
|
||||
});
|
||||
it("空 worker 数组是已知 0(与 null 区分)", () => {
|
||||
expect(chvAvailability([], "", "")).toEqual({ state: "known", online: 0, total: 0 });
|
||||
expect(countChvWorkers([])).toEqual({ online: 0, total: 0 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("chvAvailabilityText:Workers 旧 bug 不复发(closeup)", () => {
|
||||
it("load-failed / not-loaded 绝不写“仅全局管理员可见”", () => {
|
||||
expect(chvAvailabilityText({ state: "unknown", reason: "load-failed" })).not.toContain("仅全局管理员可见");
|
||||
expect(chvAvailabilityText({ state: "unknown", reason: "not-loaded" })).not.toContain("仅全局管理员可见");
|
||||
});
|
||||
it("known 总数为 0 时仍是已知 0,不写未知", () => {
|
||||
const text = chvAvailabilityText({ state: "known", online: 0, total: 0 });
|
||||
expect(text).toContain("在线 0 / 共 0");
|
||||
expect(text).not.toContain("未知");
|
||||
});
|
||||
});
|
||||
|
||||
describe("附件拦截与排队提示边角(closeup)", () => {
|
||||
it("executor 为 undefined/null 时附件不拦", () => {
|
||||
expect(chvAttachmentBlocked(undefined, true)).toBe(false);
|
||||
expect(chvAttachmentBlocked(null, true)).toBe(false);
|
||||
});
|
||||
it("排队提示:未知三原因一律为空串", () => {
|
||||
for (const reason of ["aggregate-only", "load-failed", "not-loaded"] as const) {
|
||||
expect(chvQueueHint("cloud-hypervisor", "queued", { state: "unknown", reason })).toBe("");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("isWorkerAlive 边界(closeup)", () => {
|
||||
it("last_seen 恰好 120 秒算在线(<=120)", () => {
|
||||
const now = Date.now() / 1000;
|
||||
expect(isWorkerAlive({ executor: "cloud-hypervisor", last_seen: now - 120 })).toBe(true);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user