1
0
Files
DiAL/tests/server/middleware.test.ts
lanyuanxiaoyao 7926514986 feat: 配置变量系统与 target id/name 双字段标识
- 新增顶层 variables 段支持 string/number/boolean 字面量
- target 字符串字段支持 、、{...} 转义语法
- 变量解析优先级: variables -> process.env -> 默认值 -> 报错
- 完整引用保留原始类型,部分引用拼接为字符串
- 变量替换在 YAML 解析后、AJV 校验前执行
- 替换仅作用于 targets,跳过 id/type 字段
- target 新增必填 id 字段作为唯一标识,name 改为可选展示名称
- 数据库存储/API/前端全面迁移到 id 标识
- 统一 checker 运行时类型检查为 es-toolkit predicates
- 同步 delta specs 到主 specs,归档 config-variables 变更
2026-05-17 00:37:54 +08:00

172 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, test } from "bun:test";
import {
validateDashboardWindow,
validateMetricsBucket,
validatePagination,
validateRecentLimit,
validateTargetId,
validateTimeRange,
} from "../../src/server/middleware";
describe("validateTargetId", () => {
test("有效的 target ID 返回字符串", () => {
const result = validateTargetId("api-health_01", "production");
expect(result).not.toHaveProperty("status");
expect((result as { id: string }).id).toBe("api-health_01");
});
test("无效的 target ID 返回 400", () => {
const invalid = ["-1", "_abc", "has space", "1.5", ""];
for (const id of invalid) {
const result = validateTargetId(id, "production");
expect(result).toHaveProperty("status", 400);
}
});
});
describe("validateTimeRange", () => {
test("有效的 from/to 返回 ISO 字符串", () => {
const result = validateTimeRange("2024-01-01T00:00:00.000Z", "2024-01-02T00:00:00.000Z", "production");
expect(result).not.toHaveProperty("status");
expect((result as { from: string; to: string }).from).toBe("2024-01-01T00:00:00.000Z");
expect((result as { from: string; to: string }).to).toBe("2024-01-02T00:00:00.000Z");
});
test("缺失 from 或 to 返回 400", () => {
const missingFrom = validateTimeRange(null, "2024-01-02T00:00:00.000Z", "production");
const missingTo = validateTimeRange("2024-01-01T00:00:00.000Z", null, "production");
const missingBoth = validateTimeRange(null, null, "production");
expect(missingFrom).toHaveProperty("status", 400);
expect(missingTo).toHaveProperty("status", 400);
expect(missingBoth).toHaveProperty("status", 400);
});
test("空字符串 from 或 to 返回 400", () => {
const emptyFrom = validateTimeRange("", "2024-01-02T00:00:00.000Z", "production");
const emptyTo = validateTimeRange("2024-01-01T00:00:00.000Z", "", "production");
expect(emptyFrom).toHaveProperty("status", 400);
expect(emptyTo).toHaveProperty("status", 400);
});
test("无效的日期格式返回 400", () => {
const result = validateTimeRange("invalid-date", "2024-01-02T00:00:00.000Z", "production");
expect(result).toHaveProperty("status", 400);
});
test("from 晚于 to 返回 400", () => {
const result = validateTimeRange("2024-01-02T00:00:00.000Z", "2024-01-01T00:00:00.000Z", "production");
expect(result).toHaveProperty("status", 400);
});
});
describe("validatePagination", () => {
test("默认值page=1, pageSize=20", () => {
const result = validatePagination(null, null, "production");
expect(result).toEqual({ page: 1, pageSize: 20 });
});
test("有效的 page 和 pageSize 参数", () => {
const result = validatePagination("2", "50", "production");
expect(result).toEqual({ page: 2, pageSize: 50 });
});
test("无效的 page 参数返回 400", () => {
const invalidPage = ["0", "-1", "abc", "1.5"];
for (const page of invalidPage) {
const result = validatePagination(page, "20", "production");
expect(result).toHaveProperty("status", 400);
}
});
test("无效的 pageSize 参数返回 400", () => {
const invalidPageSize = ["0", "-1", "abc", "1.5"];
for (const pageSize of invalidPageSize) {
const result = validatePagination("1", pageSize, "production");
expect(result).toHaveProperty("status", 400);
}
});
test("pageSize 超过上限返回 400", () => {
const result = validatePagination("1", "201", "production");
expect(result).toHaveProperty("status", 400);
});
test("pageSize 等于上限 200 返回成功", () => {
const result = validatePagination("1", "200", "production");
expect(result).toEqual({ page: 1, pageSize: 200 });
});
});
describe("validateRecentLimit", () => {
test("默认值recentLimit=30", () => {
const result = validateRecentLimit(null, "production");
expect(result).toEqual({ recentLimit: 30 });
});
test("有效的 recentLimit 参数", () => {
const result = validateRecentLimit("50", "production");
expect(result).toEqual({ recentLimit: 50 });
});
test("无效的 recentLimit 参数返回 400", () => {
const invalid = ["0", "-1", "abc", "1.5"];
for (const limit of invalid) {
const result = validateRecentLimit(limit, "production");
expect(result).toHaveProperty("status", 400);
}
});
test("recentLimit 超过上限返回 400", () => {
const result = validateRecentLimit("201", "production");
expect(result).toHaveProperty("status", 400);
});
test("recentLimit 等于上限 200 返回成功", () => {
const result = validateRecentLimit("200", "production");
expect(result).toEqual({ recentLimit: 200 });
});
});
describe("validateDashboardWindow", () => {
test("默认值window=24h", () => {
const result = validateDashboardWindow(null, "production");
expect(result).not.toHaveProperty("status");
expect((result as { label: string }).label).toBe("24h");
});
test("window=24h 返回成功", () => {
const result = validateDashboardWindow("24h", "production");
expect(result).not.toHaveProperty("status");
expect((result as { label: string }).label).toBe("24h");
});
test("不支持的 window 参数返回 400", () => {
const result = validateDashboardWindow("7d", "production");
expect(result).toHaveProperty("status", 400);
});
});
describe("validateMetricsBucket", () => {
test("默认值bucket=1h", () => {
const result = validateMetricsBucket(null, "production");
expect(result).toEqual({ bucket: "1h" });
});
test("bucket=1h 返回成功", () => {
const result = validateMetricsBucket("1h", "production");
expect(result).toEqual({ bucket: "1h" });
});
test("不支持的 bucket 参数返回 400", () => {
const result = validateMetricsBucket("5m", "production");
expect(result).toHaveProperty("status", 400);
});
});