1
0
Files
DiAL/tests/server/checker/runner/shared/value-matcher-shorthand.test.ts
lanyuanxiaoyao 60a54b483f refactor: expect 类型模型重构,Raw/Resolved 双层分离与断言基础设施内聚
- 重命名 ContentRules→ContentExpectations, KeyValueExpect→KeyedExpectations
- 新增 Raw/Resolved 双层模型:resolve 阶段物化为执行计划,store 持久化 Raw 快照
- HTTP body 按需读取:status/headers 失败或无 body expectation 时不读取 body
- 新增 displayValueExpectation() 解包 failure.expected 用户可读展示
- 修复 checkEarlyTimeout 独立 lte/lt 检查,修复 KeyedExpectations JSON Schema
- 新增 expect/value.ts(resolve/check/display)、keyed.ts、content.ts、headers.ts、status.ts
- 删除旧 normalize.ts/matcher.ts/validate-matcher.ts/key-value.ts
- 更新 DEVELOPMENT.md:expect 五层管线表、displayValueExpectation、1.7↔1.10 交叉引用
- 同步 13 个 main specs,归档 refactor-expect-type-model 变更(62/62 tasks)
2026-05-20 16:12:48 +08:00

117 lines
3.9 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import type { CheckerValidationInput } from "../../../../../src/server/checker/runner/types";
import { validateCommandConfig } from "../../../../../src/server/checker/runner/cmd/validate";
import { validateDbConfig } from "../../../../../src/server/checker/runner/db/validate";
import { validateHttpConfig } from "../../../../../src/server/checker/runner/http/validate";
import { validatePingConfig } from "../../../../../src/server/checker/runner/icmp/validate";
import { validateLlmConfig } from "../../../../../src/server/checker/runner/llm/validate";
import { validateTcpConfig } from "../../../../../src/server/checker/runner/tcp/validate";
import { validateUdpConfig } from "../../../../../src/server/checker/runner/udp/validate";
function input(target: Record<string, unknown>): CheckerValidationInput {
return { defaults: {}, targets: [target as CheckerValidationInput["targets"][number]] };
}
describe("ValueMatcher primitive shorthand in checker validators", () => {
test("accepts shorthand for all checker ValueMatcher fields", () => {
const targets = [
{
expect: { durationMs: 100 },
http: { url: "https://example.com" },
id: "http",
type: "http",
validate: validateHttpConfig,
},
{
expect: { durationMs: 100 },
id: "tcp",
tcp: { host: "127.0.0.1", port: 80 },
type: "tcp",
validate: validateTcpConfig,
},
{
expect: { durationMs: 100, responseSize: 1, sourceHost: "127.0.0.1", sourcePort: 53 },
id: "udp",
type: "udp",
udp: { host: "127.0.0.1", port: 53 },
validate: validateUdpConfig,
},
{
expect: { avgLatencyMs: 1, durationMs: 100, maxLatencyMs: 2, packetLossPercent: 0 },
icmp: { host: "127.0.0.1" },
id: "icmp",
type: "icmp",
validate: validatePingConfig,
},
{
cmd: { exec: "true" },
expect: { durationMs: 100 },
id: "cmd",
type: "cmd",
validate: validateCommandConfig,
},
{
db: { url: "sqlite://:memory:" },
expect: { durationMs: 100, rowCount: 1 },
id: "db",
type: "db",
validate: validateDbConfig,
},
{
expect: {
durationMs: 100,
finishReason: "stop",
rawFinishReason: null,
stream: { firstTokenMs: 10 },
usage: { inputTokens: 1, outputTokens: 2, totalTokens: 3 },
},
id: "llm",
llm: {
mode: "stream",
model: "test-model",
prompt: "hello",
provider: "openai",
url: "https://example.com/v1/chat/completions",
},
type: "llm",
validate: validateLlmConfig,
},
];
for (const target of targets) {
const { validate, ...config } = target;
const original = structuredClone(config);
expect(validate(input(config))).toHaveLength(0);
expect(config).toEqual(original);
}
});
test("rejects array and object shorthand while accepting explicit equals", () => {
const arrayTarget = {
expect: { durationMs: [1, 2] },
http: { url: "https://example.com" },
id: "array",
type: "http",
};
const objectTarget = {
expect: { durationMs: { foo: "bar" } },
http: { url: "https://example.com" },
id: "object",
type: "http",
};
const equalsObjectTarget = {
expect: { durationMs: { equals: { foo: "bar" } } },
http: { url: "https://example.com" },
id: "equals-object",
type: "http",
};
expect(validateHttpConfig(input(arrayTarget)).some((issue) => issue.path.includes("durationMs"))).toBe(true);
expect(validateHttpConfig(input(objectTarget)).some((issue) => issue.code === "unknown-matcher")).toBe(true);
expect(validateHttpConfig(input(equalsObjectTarget))).toHaveLength(0);
});
});