227 lines
7.5 KiB
TypeScript
227 lines
7.5 KiB
TypeScript
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");
|
||
});
|
||
});
|