fix: 强化 CPU/memory checker 错误处理、timeout 遵守和快照校验
- Memory checker: reader 与 ctx.signal race,abort 返回 memory/timeout,reject 保持 memory/snapshot - CPU checker: 第二次快照异常返回 cpu/snapshot,计算前校验空数组/核心数不一致/非有限值/负 delta - CPU 计算: 零 delta 安全处理,observation 不含 NaN/Infinity - 文档: CPU 互补描述修正,Memory timeout 约束说明 - 测试: +18 覆盖 timeout、异常和边界输入
This commit is contained in:
@@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test";
|
||||
|
||||
import type { CpuCoreSnapshot } from "../../../../../src/server/checker/runner/cpu/types";
|
||||
|
||||
import { calculateCpuStats } from "../../../../../src/server/checker/runner/cpu/calculate";
|
||||
import { calculateCpuStats, validateCpuSnapshots } from "../../../../../src/server/checker/runner/cpu/calculate";
|
||||
|
||||
function makeCore(user: number, nice: number, sys: number, idle: number, irq: number): CpuCoreSnapshot {
|
||||
return { times: { idle, irq, nice, sys, user } };
|
||||
@@ -110,3 +110,68 @@ describe("calculateCpuStats", () => {
|
||||
expect(stats.usagePercent).toBe(60);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateCpuSnapshots", () => {
|
||||
test("合法 snapshot 返回 null", () => {
|
||||
const before = [makeCore(100, 0, 0, 900, 0)];
|
||||
const after = [makeCore(200, 0, 0, 800, 0)];
|
||||
expect(validateCpuSnapshots(before, after)).toBeNull();
|
||||
});
|
||||
|
||||
test("空 before snapshot", () => {
|
||||
const after = [makeCore(0, 0, 0, 0, 0)];
|
||||
expect(validateCpuSnapshots([], after)).toBe("CPU 快照为空");
|
||||
});
|
||||
|
||||
test("空 after snapshot", () => {
|
||||
const before = [makeCore(0, 0, 0, 0, 0)];
|
||||
expect(validateCpuSnapshots(before, [])).toBe("CPU 快照为空");
|
||||
});
|
||||
|
||||
test("核心数不一致", () => {
|
||||
const before = [makeCore(0, 0, 0, 0, 0)];
|
||||
const after = [makeCore(0, 0, 0, 0, 0), makeCore(0, 0, 0, 0, 0)];
|
||||
expect(validateCpuSnapshots(before, after)).toBe("CPU 快照核心数不一致: before=1, after=2");
|
||||
});
|
||||
|
||||
test("before 包含 NaN time 值", () => {
|
||||
const before = [{ times: { idle: NaN, irq: 0, nice: 0, sys: 0, user: 0 } }];
|
||||
const after = [makeCore(0, 0, 0, 0, 0)];
|
||||
const error = validateCpuSnapshots(before, after);
|
||||
expect(error).toContain("非有限值");
|
||||
expect(error).toContain("before[0]");
|
||||
});
|
||||
|
||||
test("after 包含 Infinity time 值", () => {
|
||||
const before = [makeCore(0, 0, 0, 0, 0)];
|
||||
const after = [{ times: { idle: Infinity, irq: 0, nice: 0, sys: 0, user: 0 } }];
|
||||
const error = validateCpuSnapshots(before, after);
|
||||
expect(error).toContain("非有限值");
|
||||
expect(error).toContain("after[0]");
|
||||
});
|
||||
|
||||
test("负数 total delta", () => {
|
||||
const before = [makeCore(1000, 0, 0, 0, 0)];
|
||||
const after = [makeCore(100, 0, 0, 0, 0)];
|
||||
const error = validateCpuSnapshots(before, after);
|
||||
expect(error).toContain("负数 delta");
|
||||
});
|
||||
|
||||
test("零 delta 合法", () => {
|
||||
const before = [makeCore(100, 0, 0, 100, 0)];
|
||||
const after = [makeCore(100, 0, 0, 100, 0)];
|
||||
expect(validateCpuSnapshots(before, after)).toBeNull();
|
||||
});
|
||||
|
||||
test("零 delta 不产生除零错误", () => {
|
||||
const before = [makeCore(100, 0, 0, 100, 0)];
|
||||
const after = [makeCore(100, 0, 0, 100, 0)];
|
||||
const stats = calculateCpuStats(before, after);
|
||||
expect(Number.isFinite(stats.usagePercent)).toBe(true);
|
||||
expect(Number.isFinite(stats.idlePercent)).toBe(true);
|
||||
expect(Number.isFinite(stats.maxCoreUsagePercent)).toBe(true);
|
||||
expect(Number.isFinite(stats.minCoreUsagePercent)).toBe(true);
|
||||
expect(stats.usagePercent).toBe(0);
|
||||
expect(stats.idlePercent).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user