1
0
Files
DiAL/tests/server/checker/runner/mem/execute.test.ts
lanyuanxiaoyao 2f8fd8bd9c refactor: 将 memory checker 重命名为 mem
- 类型标识符 memory → mem
- 类名 MemoryChecker → MemChecker
- 内部类型名统一 Memory* → Mem*
- 内部函数名统一 *Memory* → *Mem*
- 目录重命名 memory/ → mem/(源码、测试、文档)
- 配置键 memory: → mem:
- 重新生成 probe-config.schema.json
- 保留中文"内存"用户提示

破坏性变更:无向后兼容
2026-05-27 18:19:29 +08:00

245 lines
8.4 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 type { Systeminformation } from "systeminformation";
import { describe, expect, test } from "bun:test";
import type { RawTargetConfig } from "../../../../../src/server/checker/types";
import { MemChecker } from "../../../../../src/server/checker/runner/mem/execute";
function makeMemData(overrides: Partial<Systeminformation.MemData> = {}): Systeminformation.MemData {
return {
active: 4294967296,
available: 8589934592,
buffcache: 1073741824,
buffers: 536870912,
cached: 536870912,
dirty: null,
free: 4294967296,
reclaimable: 0,
slab: 0,
swapfree: 0,
swaptotal: 0,
swapused: 0,
total: 17179869184,
used: 8589934592,
writeback: null,
...overrides,
};
}
function makeResolveContext(
overrides: Partial<{ configDir: string; defaultIntervalMs: number; defaultTimeoutMs: number }> = {},
) {
return {
configDir: "/test",
defaultIntervalMs: 30000,
defaultTimeoutMs: 10000,
...overrides,
};
}
describe("MemChecker resolve", () => {
const checker = new MemChecker();
test("默认值mem 为空对象", () => {
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
expect(resolved.mem).toEqual({});
});
test("无 expect 时 expect 为 undefined", () => {
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
expect(resolved.expect).toBeUndefined();
});
test("保留 expect 字段", () => {
const target: RawTargetConfig = {
expect: { usagePercent: { lte: 85 } },
id: "mem-test",
mem: {},
type: "mem",
};
const resolved = checker.resolve(target, makeResolveContext());
expect(resolved.expect).toEqual({ usagePercent: { lte: 85 } });
});
test("type 为 mem", () => {
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
expect(resolved.type).toBe("mem");
});
});
describe("MemChecker execute", () => {
test("成功匹配", async () => {
const data = makeMemData({ active: 4294967296, total: 8589934592 });
const reader = () => Promise.resolve(data);
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
resolved.expect = { usagePercent: { lte: 85 } };
const ctx = { signal: new AbortController().signal };
const result = await checker.execute(resolved, ctx);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
expect(result.observation).toMatchObject({
totalBytes: 8589934592,
usagePercent: 50,
});
});
test("usagePercent mismatch", async () => {
const data = makeMemData({ active: 7730941132, total: 8589934592 });
const reader = () => Promise.resolve(data);
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
resolved.expect = { usagePercent: { lte: 50 } };
const ctx = { signal: new AbortController().signal };
const result = await checker.execute(resolved, ctx);
expect(result.matched).toBe(false);
expect(result.failure?.phase).toBe("usage");
});
test("observation 包含所有字段", async () => {
const data = makeMemData();
const reader = () => Promise.resolve(data);
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
const ctx = { signal: new AbortController().signal };
const result = await checker.execute(resolved, ctx);
const obs = result.observation!;
expect(obs).toHaveProperty("activeBytes");
expect(obs).toHaveProperty("activePercent");
expect(obs).toHaveProperty("availableBytes");
expect(obs).toHaveProperty("availablePercent");
expect(obs).toHaveProperty("buffcacheBytes");
expect(obs).toHaveProperty("freeBytes");
expect(obs).toHaveProperty("freePercent");
expect(obs).toHaveProperty("swapFreeBytes");
expect(obs).toHaveProperty("swapTotalBytes");
expect(obs).toHaveProperty("swapUsagePercent");
expect(obs).toHaveProperty("swapUsedBytes");
expect(obs).toHaveProperty("totalBytes");
expect(obs).toHaveProperty("usagePercent");
expect(obs).toHaveProperty("usedBytes");
expect(obs).toHaveProperty("usedPercent");
});
test("reader reject 返回失败结果", async () => {
const reader = () => Promise.reject(new Error("read error"));
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
const ctx = { signal: new AbortController().signal };
const result = await checker.execute(resolved, ctx);
expect(result.matched).toBe(false);
expect(result.failure?.phase).toBe("mem");
expect(result.failure?.path).toBe("snapshot");
expect(result.observation).toBeNull();
});
test("signal 已 abort 时返回 timeout failure", async () => {
const reader = () => Promise.resolve(makeMemData());
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
const controller = new AbortController();
controller.abort();
const result = await checker.execute(resolved, { signal: controller.signal });
expect(result.matched).toBe(false);
expect(result.failure?.phase).toBe("mem");
expect(result.failure?.path).toBe("timeout");
expect(result.observation).toBeNull();
});
test("pending reader 被 signal abort 后返回 timeout failure", async () => {
const reader = () =>
new Promise<Systeminformation.MemData>(() => {
// 故意永不 resolve模拟悬挂的 reader
});
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
const controller = new AbortController();
const executePromise = checker.execute(resolved, { signal: controller.signal });
controller.abort();
const result = await executePromise;
expect(result.matched).toBe(false);
expect(result.failure?.phase).toBe("mem");
expect(result.failure?.path).toBe("timeout");
expect(result.observation).toBeNull();
});
test("reader 在 abort 前 resolve 时返回正常结果", async () => {
const data = makeMemData({ active: 4294967296, total: 8589934592 });
const reader = () => Promise.resolve(data);
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
resolved.expect = { usagePercent: { lte: 85 } };
const ctx = { signal: new AbortController().signal };
const result = await checker.execute(resolved, ctx);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
expect(result.observation).toMatchObject({
totalBytes: 8589934592,
usagePercent: 50,
});
});
test("detail 格式", async () => {
const data = makeMemData({ active: 4294967296, total: 8589934592 });
const reader = () => Promise.resolve(data);
const checker = new MemChecker(reader);
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
const ctx = { signal: new AbortController().signal };
const result = await checker.execute(resolved, ctx);
const detail = checker.buildDetail(result.observation!);
expect(detail).toContain("usage");
expect(detail).toContain("%");
expect(detail).toContain("total");
});
});
describe("MemChecker serialize", () => {
test("序列化输出", () => {
const checker = new MemChecker();
const target: RawTargetConfig = { id: "mem-test", mem: {}, type: "mem" };
const resolved = checker.resolve(target, makeResolveContext());
const result = checker.serialize(resolved);
expect(result.target).toBe("mem");
const config = JSON.parse(result.config) as Record<string, unknown>;
expect(config).toEqual({});
});
});