import { describe, expect, test } from "bun:test"; import { createAuthoringConfigSchema, createNormalizedConfigSchema } from "../../../src/server/config/schema/builder"; import { createConfigJsonSchema } from "../../../src/server/config/schema/export"; import { createConfigAjv, issuesFromAjvErrors, validateConfigContract, } from "../../../src/server/config/schema/validate"; describe("导出 schema 生成", () => { test("createConfigJsonSchema 返回有效 JSON Schema", () => { const schema = createConfigJsonSchema(); expect(schema["$schema"]).toBe("http://json-schema.org/draft-07/schema#"); expect(schema["$id"]).toBe("https://app.local/config.schema.json"); expect(schema["type"]).toBe("object"); }); }); describe("Authoring schema 校验", () => { const ajv = createConfigAjv(); const validate = ajv.compile(createAuthoringConfigSchema()); test("接受空对象", () => { expect(validate({})).toBe(true); }); test("接受新布局 server.listen", () => { expect(validate({ server: { listen: { host: "127.0.0.1", port: 3000 } } })).toBe(true); }); test("接受变量引用语法", () => { expect(validate({ server: { listen: { port: "${PORT|3000}" } } })).toBe(true); }); test("接受 variables 字段", () => { expect(validate({ variables: { HOST: "127.0.0.1" } })).toBe(true); }); test("接受 server.storage.dataDir", () => { expect(validate({ server: { storage: { dataDir: "./data" } } })).toBe(true); }); test("接受 server.logging 合法配置", () => { expect( validate({ server: { logging: { console: { level: "debug" }, file: { level: "warn", path: "/var/log/app.log", rotation: { frequency: "daily", maxFiles: 14, size: "50MB" }, }, level: "info", }, }, }), ).toBe(true); }); test("接受 server.logging.level 变量引用", () => { expect(validate({ server: { logging: { level: "${LOG_LEVEL|info}" } } })).toBe(true); }); test("拒绝 server.logging 中未知字段", () => { expect(validate({ server: { logging: { unknownField: true } } })).toBe(false); }); test("拒绝 server.logging.level 非法枚举值", () => { expect(validate({ server: { logging: { level: "verbose" } } })).toBe(false); }); test("拒绝 unknown 字段 server.host", () => { expect(validate({ server: { host: "127.0.0.1" } })).toBe(false); const issues = issuesFromAjvErrors(validate.errors ?? [], {}); expect(issues.some((i) => i.code === "unknown-field")).toBe(true); }); test("拒绝未知字段 server.port", () => { expect(validate({ server: { port: 3000 } })).toBe(false); const issues = issuesFromAjvErrors(validate.errors ?? [], {}); expect(issues.some((i) => i.code === "unknown-field")).toBe(true); }); test("拒绝非法类型 port", () => { expect(validate({ server: { listen: { port: "not-a-number" } } })).toBe(false); }); test("拒绝超出范围的 port", () => { expect(validate({ server: { listen: { port: 70000 } } })).toBe(false); }); test("拒绝负数 port", () => { expect(validate({ server: { listen: { port: -1 } } })).toBe(false); }); test("拒绝顶层未知字段", () => { expect(validate({ unknown: true })).toBe(false); }); }); describe("Normalized schema 校验", () => { const ajv = createConfigAjv(); const validate = ajv.compile(createNormalizedConfigSchema()); test("接受新布局 server.listen", () => { expect(validate({ server: { listen: { host: "127.0.0.1", port: 3000 } } })).toBe(true); }); test("Normalized 不接受 variables 字段", () => { expect(validate({ variables: { HOST: "127.0.0.1" } })).toBe(false); }); test("Normalized 不接受变量引用语法", () => { expect(validate({ server: { listen: { port: "${PORT|3000}" } } })).toBe(false); }); test("接受 server.storage.dataDir", () => { expect(validate({ server: { storage: { dataDir: "./data" } } })).toBe(true); }); test("接受 server.logging 合法配置", () => { expect( validate({ server: { logging: { console: { level: "debug" }, file: { level: "warn", path: "/var/log/app.log", rotation: { frequency: "daily", maxFiles: 14, size: "50MB" }, }, level: "info", }, }, }), ).toBe(true); }); test("接受空对象", () => { expect(validate({})).toBe(true); }); }); describe("validateConfigContract", () => { test("有效配置通过校验", () => { const result = validateConfigContract({ server: { listen: { host: "0.0.0.0", port: 8080 } } }); expect(result.config).not.toBeNull(); }); test("空配置通过校验", () => { const result = validateConfigContract({}); expect(result.config).not.toBeNull(); }); test("包含未知字段的配置被拒绝", () => { const result = validateConfigContract({ server: { host: "bad" } }); expect(result.config).toBeNull(); expect(result.issues.length).toBeGreaterThan(0); }); }); describe("schema 同步测试", () => { test("config.schema.json 与 createConfigJsonSchema() 输出一致", async () => { const file = Bun.file("config.schema.json"); const existing = await file.text(); const generated = `${JSON.stringify(createConfigJsonSchema(), null, 2)}\n`; expect(existing).toBe(generated); }); });