1
0

feat: DNS checker,自研 codec/transport,支持 system/server 双模式,UDP/TCP + TC fallback

This commit is contained in:
2026-05-24 17:06:22 +08:00
parent 4f33fba793
commit 483cdc596b
21 changed files with 5686 additions and 16 deletions

View File

@@ -0,0 +1,226 @@
import { describe, expect, it } from "bun:test";
import type { ContentExpectations } from "../../../../../src/server/checker/expect/types";
import {
checkAnswerCount,
checkDnsValues,
checkFlag,
checkRcode,
checkResponded,
checkResult,
checkTtlMax,
checkTtlMin,
checkValueCount,
} from "../../../../../src/server/checker/runner/dns/expect";
describe("checkResponded", () => {
it("responded=true 期望 true → 匹配", () => {
const result = checkResponded(true, true);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("responded=false 期望 true → 不匹配", () => {
const result = checkResponded(false, true);
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("responded");
expect(result.failure!.message).toContain("未收到");
});
it("responded=true 期望 false → 不匹配", () => {
const result = checkResponded(true, false);
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("responded");
expect(result.failure!.message).toContain("收到响应");
});
it("responded=false 期望 false → 匹配", () => {
const result = checkResponded(false, false);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
});
describe("checkRcode", () => {
it("NOERROR 在 [NOERROR] → 匹配", () => {
const result = checkRcode("NOERROR", ["NOERROR"]);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("NXDOMAIN 在 [NOERROR] → 不匹配", () => {
const result = checkRcode("NXDOMAIN", ["NOERROR"]);
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("rcode");
});
it("NXDOMAIN 在 [NXDOMAIN, SERVFAIL] → 匹配", () => {
const result = checkRcode("NXDOMAIN", ["NXDOMAIN", "SERVFAIL"]);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
});
describe("checkDnsValues", () => {
it("exact: 相同集合不同顺序 → 匹配", () => {
const result = checkDnsValues(["2.2.2.2", "1.1.1.1"], { exact: ["1.1.1.1", "2.2.2.2"] });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("exact: 不同集合 → 不匹配", () => {
const result = checkDnsValues(["1.1.1.1"], { exact: ["2.2.2.2"] });
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("values");
});
it("exact: 数量不同 → 不匹配", () => {
const result = checkDnsValues(["1.1.1.1", "2.2.2.2"], { exact: ["1.1.1.1"] });
expect(result.matched).toBe(false);
});
it("include: 全部存在 → 匹配", () => {
const result = checkDnsValues(["1.1.1.1", "2.2.2.2"], { include: ["1.1.1.1"] });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("include: 缺少一个 → 不匹配", () => {
const result = checkDnsValues(["1.1.1.1"], { include: ["3.3.3.3"] });
expect(result.matched).toBe(false);
expect(result.failure!.message).toContain("3.3.3.3");
});
it("exclude: 全不存在 → 匹配", () => {
const result = checkDnsValues(["1.1.1.1"], { exclude: ["3.3.3.3"] });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("exclude: 存在一个 → 不匹配", () => {
const result = checkDnsValues(["1.1.1.1", "2.2.2.2"], { exclude: ["2.2.2.2"] });
expect(result.matched).toBe(false);
expect(result.failure!.message).toContain("2.2.2.2");
});
it("include + exclude 组合:全部满足 → 匹配", () => {
const result = checkDnsValues(["1.1.1.1", "2.2.2.2"], { exclude: ["3.3.3.3"], include: ["1.1.1.1"] });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("include + exclude 组合include 失败 → 不匹配", () => {
const result = checkDnsValues(["1.1.1.1"], { exclude: ["3.3.3.3"], include: ["4.4.4.4"] });
expect(result.matched).toBe(false);
});
it("空 expectation → 匹配", () => {
const result = checkDnsValues(["1.1.1.1"], {});
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
});
describe("checkValueCount", () => {
it("count=3 gte=1 → 匹配", () => {
const result = checkValueCount(3, { gte: 1 });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("count=0 gte=1 → 不匹配", () => {
const result = checkValueCount(0, { gte: 1 });
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("valueCount");
});
});
describe("checkAnswerCount", () => {
it("count=2 gte=2 → 匹配", () => {
const result = checkAnswerCount(2, { gte: 2 });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("count=1 gte=2 → 不匹配", () => {
const result = checkAnswerCount(1, { gte: 2 });
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("answerCount");
});
});
describe("checkTtlMin", () => {
it("ttl=300 gte=60 → 匹配", () => {
const result = checkTtlMin(300, { gte: 60 });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("ttl=30 gte=60 → 不匹配", () => {
const result = checkTtlMin(30, { gte: 60 });
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("ttlMin");
});
});
describe("checkTtlMax", () => {
it("ttl=100 lte=3600 → 匹配", () => {
const result = checkTtlMax(100, { lte: 3600 });
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("ttl=5000 lte=3600 → 不匹配", () => {
const result = checkTtlMax(5000, { lte: 3600 });
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("ttlMax");
});
});
describe("checkFlag", () => {
it("匹配 → matched", () => {
const result = checkFlag(true, true, "authoritative");
expect(result!.matched).toBe(true);
expect(result!.failure).toBeNull();
});
it("不匹配 → mismatch", () => {
const result = checkFlag(false, true, "authoritative");
expect(result!.matched).toBe(false);
expect(result!.failure!.kind).toBe("mismatch");
expect(result!.failure!.phase).toBe("authoritative");
});
it("undefined 期望 → 跳过返回 null", () => {
const result = checkFlag(true, undefined, "authoritative");
expect(result).toBeNull();
});
});
describe("checkResult", () => {
it("单条 contains 匹配 JSON 字符串", () => {
const observation = { answers: ["1.1.1.1"], rcode: "NOERROR" };
const expectations: ContentExpectations = [{ kind: "value", matcher: { contains: "NOERROR" } }];
const result = checkResult(observation, expectations);
expect(result.matched).toBe(true);
expect(result.failure).toBeNull();
});
it("单条 contains 不匹配 → 不匹配", () => {
const observation = { rcode: "SERVFAIL" };
const expectations: ContentExpectations = [{ kind: "value", matcher: { contains: "NOERROR" } }];
const result = checkResult(observation, expectations);
expect(result.matched).toBe(false);
expect(result.failure!.kind).toBe("mismatch");
expect(result.failure!.phase).toBe("result");
});
});