- 引入共享 ValueMatcher(equals/contains/regex/exists/empty/gt/gte/lt/lte) - 引入共享 ContentRules 数组(direct/json/css/xpath 提取器) - 引入共享 KeyValueExpect(动态键值断言,字面量等价 equals) - maxDurationMs → durationMs: ValueMatcher(所有 checker) - match → regex(固定无 flags) - Ping max* → packetLossPercent/avgLatencyMs/maxLatencyMs(ValueMatcher) - LLM finishReason/rawFinishReason → ValueMatcher - DB 新增 result: ContentRules - TCP banner → ContentRules 数组 - 删除旧模块:operator.ts、validate-operator.ts、duration.ts、body.ts、text.ts、output.ts - 更新全部 checker schema/validate/expect/execute - 更新 probe-config.schema.json、probes.example.yaml - 更新 README.md、DEVELOPMENT.md(含 expect 字段选择规范) - 同步 10 个 delta specs 到主 specs,归档 change
192 lines
6.1 KiB
TypeScript
192 lines
6.1 KiB
TypeScript
import { describe, expect, test } from "bun:test";
|
|
|
|
import type { CheckerValidationInput } from "../../../../../src/server/checker/runner/types";
|
|
|
|
import { validateTcpConfig } from "../../../../../src/server/checker/runner/tcp/validate";
|
|
|
|
function makeInput(targets: unknown[], defaults?: Record<string, unknown>): CheckerValidationInput {
|
|
return {
|
|
defaults: defaults ?? {},
|
|
targets: targets as CheckerValidationInput["targets"],
|
|
};
|
|
}
|
|
|
|
describe("validateTcpConfig", () => {
|
|
test("合法 tcp target 无错误", () => {
|
|
const issues = validateTcpConfig(makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80 }, type: "tcp" }]));
|
|
expect(issues).toHaveLength(0);
|
|
});
|
|
|
|
test("缺少 tcp 分组", () => {
|
|
const issues = validateTcpConfig(makeInput([{ id: "t1", type: "tcp" }]));
|
|
expect(issues.length).toBeGreaterThan(0);
|
|
expect(issues.some((i) => i.message.includes("tcp"))).toBe(true);
|
|
});
|
|
|
|
test("缺少 host", () => {
|
|
const issues = validateTcpConfig(makeInput([{ id: "t1", tcp: { port: 80 }, type: "tcp" }]));
|
|
expect(issues.some((i) => i.path.includes("host"))).toBe(true);
|
|
});
|
|
|
|
test("缺少 port", () => {
|
|
const issues = validateTcpConfig(makeInput([{ id: "t1", tcp: { host: "127.0.0.1" }, type: "tcp" }]));
|
|
expect(issues.some((i) => i.path.includes("port"))).toBe(true);
|
|
});
|
|
|
|
test("端口超范围", () => {
|
|
const issues = validateTcpConfig(makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 99999 }, type: "tcp" }]));
|
|
expect(issues.some((i) => i.path.includes("port"))).toBe(true);
|
|
});
|
|
|
|
test("端口为 0", () => {
|
|
const issues = validateTcpConfig(makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 0 }, type: "tcp" }]));
|
|
expect(issues.some((i) => i.path.includes("port"))).toBe(true);
|
|
});
|
|
|
|
test("readBanner 非布尔值", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80, readBanner: "yes" }, type: "tcp" }]),
|
|
);
|
|
expect(issues.some((i) => i.path.includes("readBanner"))).toBe(true);
|
|
});
|
|
|
|
test("bannerReadTimeout 非数字", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { bannerReadTimeout: "slow", host: "127.0.0.1", port: 80 }, type: "tcp" }]),
|
|
);
|
|
expect(issues.some((i) => i.path.includes("bannerReadTimeout"))).toBe(true);
|
|
});
|
|
|
|
test("tcp 分组未知字段", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80, tls: true }, type: "tcp" }]),
|
|
);
|
|
expect(issues.some((i) => i.message.includes("未知字段"))).toBe(true);
|
|
});
|
|
|
|
test("expect.banner 未开启 readBanner", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([
|
|
{
|
|
expect: { banner: [{ contains: "ESMTP" }] },
|
|
id: "t1",
|
|
tcp: { host: "127.0.0.1", port: 25 },
|
|
type: "tcp",
|
|
},
|
|
]),
|
|
);
|
|
expect(issues.some((i) => i.message.includes("readBanner"))).toBe(true);
|
|
});
|
|
|
|
test("expect.banner 开启 readBanner 无错误", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([
|
|
{
|
|
expect: { banner: [{ contains: "ESMTP" }] },
|
|
id: "t1",
|
|
tcp: { host: "127.0.0.1", port: 25, readBanner: true },
|
|
type: "tcp",
|
|
},
|
|
]),
|
|
);
|
|
expect(issues).toHaveLength(0);
|
|
});
|
|
|
|
test("expect connected 非布尔值", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([
|
|
{
|
|
expect: { connected: "yes" },
|
|
id: "t1",
|
|
tcp: { host: "127.0.0.1", port: 80 },
|
|
type: "tcp",
|
|
},
|
|
]),
|
|
);
|
|
expect(issues.some((i) => i.path.includes("connected"))).toBe(true);
|
|
});
|
|
|
|
test("expect durationMs 非 matcher", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([
|
|
{
|
|
expect: { durationMs: "slow" },
|
|
id: "t1",
|
|
tcp: { host: "127.0.0.1", port: 80 },
|
|
type: "tcp",
|
|
},
|
|
]),
|
|
);
|
|
expect(issues.some((i) => i.path.includes("durationMs"))).toBe(true);
|
|
});
|
|
|
|
test("expect 未知字段", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([
|
|
{
|
|
expect: { status: [200] },
|
|
id: "t1",
|
|
tcp: { host: "127.0.0.1", port: 80 },
|
|
type: "tcp",
|
|
},
|
|
]),
|
|
);
|
|
expect(issues.some((i) => i.message.includes("未知字段"))).toBe(true);
|
|
});
|
|
|
|
test("expect.banner regex 正则非法", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([
|
|
{
|
|
expect: { banner: [{ regex: "[invalid" }] },
|
|
id: "t1",
|
|
tcp: { host: "127.0.0.1", port: 25, readBanner: true },
|
|
type: "tcp",
|
|
},
|
|
]),
|
|
);
|
|
expect(issues.some((i) => i.message.includes("正则"))).toBe(true);
|
|
});
|
|
|
|
test("非 tcp 类型 target 跳过", () => {
|
|
const issues = validateTcpConfig(makeInput([{ http: { url: "http://example.com" }, id: "t1", type: "http" }]));
|
|
expect(issues).toHaveLength(0);
|
|
});
|
|
|
|
test("defaults.tcp 合法字段无错误", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80 }, type: "tcp" }], {
|
|
tcp: { bannerReadTimeout: 1000, maxBannerBytes: "8KB" },
|
|
}),
|
|
);
|
|
expect(issues).toHaveLength(0);
|
|
});
|
|
|
|
test("defaults.tcp 未知字段", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80 }, type: "tcp" }], {
|
|
tcp: { bannerReadTimeout: 1000, host: "127.0.0.1" },
|
|
}),
|
|
);
|
|
expect(issues.some((i) => i.message.includes("未知字段"))).toBe(true);
|
|
});
|
|
|
|
test("defaults.tcp bannerReadTimeout 非法", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80 }, type: "tcp" }], {
|
|
tcp: { bannerReadTimeout: "slow" },
|
|
}),
|
|
);
|
|
expect(issues.some((i) => i.path.includes("bannerReadTimeout"))).toBe(true);
|
|
});
|
|
|
|
test("defaults.tcp maxBannerBytes 非法", () => {
|
|
const issues = validateTcpConfig(
|
|
makeInput([{ id: "t1", tcp: { host: "127.0.0.1", port: 80 }, type: "tcp" }], {
|
|
tcp: { maxBannerBytes: true },
|
|
}),
|
|
);
|
|
expect(issues.some((i) => i.path.includes("maxBannerBytes"))).toBe(true);
|
|
});
|
|
});
|