1
0
Files
DiAL/tests/server/checker/runner/cpu/calculate.test.ts
lanyuanxiaoyao 3390eb5e8d 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、异常和边界输入
2026-05-27 16:33:39 +08:00

178 lines
6.9 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from "bun:test";
import type { CpuCoreSnapshot } from "../../../../../src/server/checker/runner/cpu/types";
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 } };
}
describe("calculateCpuStats", () => {
test("单核心完全空闲", () => {
const before = [makeCore(0, 0, 0, 100, 0)];
const after = [makeCore(0, 0, 0, 200, 0)];
const stats = calculateCpuStats(before, after);
expect(stats.usagePercent).toBe(0);
expect(stats.idlePercent).toBe(100);
expect(stats.maxCoreUsagePercent).toBe(0);
expect(stats.minCoreUsagePercent).toBe(0);
expect(stats.logicalCoreCount).toBe(1);
});
test("单核心完全忙碌idle 不变)", () => {
const before = [makeCore(100, 0, 0, 100, 0)];
const after = [makeCore(200, 0, 0, 100, 0)];
// idle delta = 0, total delta = 100
// idlePercent = 0, usagePercent = 100
const stats = calculateCpuStats(before, after);
expect(stats.usagePercent).toBe(100);
expect(stats.idlePercent).toBe(0);
});
test("单核心部分使用", () => {
const before = [makeCore(100, 0, 0, 900, 0)];
const after = [makeCore(150, 0, 0, 950, 0)];
// idle delta = 50, total delta = 100
// idlePercent = 50, usagePercent = 50
const stats = calculateCpuStats(before, after);
expect(stats.usagePercent).toBe(50);
expect(stats.idlePercent).toBe(50);
});
test("多核心加权平均", () => {
// 核心 0: idle delta = 200, total delta = 1000 -> 80% usage
// 核心 1: idle delta = 800, total delta = 1000 -> 20% usage
const before = [makeCore(0, 0, 0, 1000, 0), makeCore(0, 0, 0, 1000, 0)];
const after = [makeCore(800, 0, 0, 1200, 0), makeCore(200, 0, 0, 1800, 0)];
const stats = calculateCpuStats(before, after);
// 总 idle = 200+800=1000, 总 delta = 1000+1000=2000
// idlePercent = 1000/2000*100 = 50
// usagePercent = 100 - 50 = 50
expect(stats.idlePercent).toBe(50);
expect(stats.usagePercent).toBe(50);
expect(stats.maxCoreUsagePercent).toBe(80);
expect(stats.minCoreUsagePercent).toBe(20);
expect(stats.logicalCoreCount).toBe(2);
expect(stats.perCoreUsagePercent).toEqual([80, 20]);
});
test("四核心各不相同", () => {
const bf = [
makeCore(1000, 0, 0, 9000, 0), // core 0 baseline
makeCore(1000, 0, 0, 9000, 0), // core 1
makeCore(1000, 0, 0, 9000, 0), // core 2
makeCore(1000, 0, 0, 9000, 0), // core 3
];
const af = [
makeCore(1900, 0, 0, 9100, 0), // delta: user=900, idle=100, total=1000 -> 90% usage, 10% idle
makeCore(1500, 0, 0, 9500, 0), // delta: user=500, idle=500, total=1000 -> 50% usage
makeCore(1200, 0, 0, 9800, 0), // delta: user=200, idle=800, total=1000 -> 20% usage
makeCore(1010, 0, 0, 9990, 0), // delta: user=10, idle=990, total=1000 -> 1% usage
];
const stats = calculateCpuStats(bf, af);
// 总 idle = 100+500+800+990 = 2390, 总 delta = 4000
// idlePercent = 2390/4000*100 = 59.75 -> 59.8
expect(stats.idlePercent).toBe(59.8);
expect(stats.usagePercent).toBe(40.2);
expect(stats.maxCoreUsagePercent).toBe(90);
expect(stats.minCoreUsagePercent).toBe(1);
expect(stats.perCoreUsagePercent).toEqual([90, 50, 20, 1]);
expect(stats.logicalCoreCount).toBe(4);
});
test("delta 为 0 时返回 0", () => {
const before = [makeCore(100, 0, 0, 100, 0)];
const after = [makeCore(100, 0, 0, 100, 0)];
const stats = calculateCpuStats(before, after);
expect(stats.usagePercent).toBe(0);
expect(stats.idlePercent).toBe(0);
});
test("保留 1 位小数", () => {
// 总 idle = 333, 总 delta = 1000 -> idlePercent = 33.3
const before = [makeCore(0, 0, 0, 1000, 0)];
const after = [makeCore(667, 0, 0, 1333, 0)];
const stats = calculateCpuStats(before, after);
// idle delta = 333, total delta = 1000
expect(stats.idlePercent).toBe(33.3);
expect(stats.usagePercent).toBe(66.7);
});
test("nice 和 irq 计入 total 但不影响 idle", () => {
const bf = [makeCore(0, 0, 0, 0, 0)];
const af = [makeCore(300, 100, 100, 400, 100)];
// total delta = 300+100+100+400+100 = 1000
// idle delta = 400
// idlePercent = 400/1000*100 = 40
const stats = calculateCpuStats(bf, af);
expect(stats.idlePercent).toBe(40);
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);
});
});