doatlas-2 / artifacts /api-server /src /routes /__tests__ /evolution-strategy-patch.test.ts
Iostream-Li's picture
Add files using upload-large-folder tool
6d1fe92 verified
/**
* Task #228 — PATCH /api/admin/evolution/networks/:id/strategy 入参校验单测。
*
* 这一组测试专门覆盖 patchStrategy handler 中可被纯函数化的入参校验段
* (`validatePatchStrategyBody`),不依赖 Postgres / Express,跑得很快,
* 用来回归 reviewer (Task #228 code review) 提出的 "PATCH 路由
* success + unknown_strategy 路径需要小测试覆盖" 高影响项。
*
* 覆盖契约:
* 1. 缺 strategy 字段 → 400 strategy_required
* 2. strategy 字段非字符串 → 400 strategy_required
* 3. strategy 字段空字符串 → 400 strategy_required
* 4. 未注册的 strategy 名 → 400 unknown_strategy + 列出可选名
* 5. 已注册的 strategy 名 → ok=true, status=200, 回显 strategy
*
* 副作用段(requireNetwork → db.update → recordEvent)走另外的 e2e
* 测试覆盖,避免单测里再起一遍 ephemeral schema。
*/
import { test } from "node:test";
import assert from "node:assert/strict";
process.env.DATABASE_URL ??= "postgres://test:test@127.0.0.1:5432/test";
const { validatePatchStrategyBody } = await import("../evolutionFlywheel");
const { listEvolutionStrategyNames, DEFAULT_EVOLUTION_STRATEGY } = await import(
"../../lib/evolution/strategies"
);
test("validatePatchStrategyBody: 缺 strategy 字段 → 400 strategy_required", () => {
const r = validatePatchStrategyBody({});
assert.equal(r.ok, false);
assert.equal(r.status, 400);
assert.equal(r.body.error, "strategy_required");
assert.equal(r.body.strategy, undefined);
assert.equal(r.body.available, undefined);
});
test("validatePatchStrategyBody: body 为 null → 400 strategy_required", () => {
const r = validatePatchStrategyBody(null);
assert.equal(r.ok, false);
assert.equal(r.status, 400);
assert.equal(r.body.error, "strategy_required");
});
test("validatePatchStrategyBody: strategy 非字符串 → 400 strategy_required", () => {
for (const bad of [42, true, [], {}, { foo: "bar" }]) {
const r = validatePatchStrategyBody({ strategy: bad });
assert.equal(r.ok, false, `strategy=${JSON.stringify(bad)}`);
assert.equal(r.status, 400);
assert.equal(r.body.error, "strategy_required");
}
});
test("validatePatchStrategyBody: 空字符串 → 400 strategy_required", () => {
const r = validatePatchStrategyBody({ strategy: "" });
assert.equal(r.ok, false);
assert.equal(r.status, 400);
assert.equal(r.body.error, "strategy_required");
});
test("validatePatchStrategyBody: 未注册策略名 → 400 unknown_strategy + 列出可选名", () => {
const r = validatePatchStrategyBody({ strategy: "definitely_not_registered" });
assert.equal(r.ok, false);
assert.equal(r.status, 400);
assert.equal(r.body.error, "unknown_strategy");
// 列表必须非空且与注册表一致,前端要据此渲染下拉。
assert.ok(Array.isArray(r.body.available));
assert.deepEqual(r.body.available, listEvolutionStrategyNames());
assert.ok((r.body.available as string[]).length > 0);
// 默认策略名永远在列表里(回退路径的兜底实例)。
assert.ok((r.body.available as string[]).includes(DEFAULT_EVOLUTION_STRATEGY));
});
test("validatePatchStrategyBody: 已注册策略名 → ok=true, 回显 strategy", () => {
// hyperparameter_grid (默认) 与 fitness_guided 都已在 Task #228 注册。
for (const name of ["hyperparameter_grid", "fitness_guided"]) {
const r = validatePatchStrategyBody({ strategy: name });
assert.equal(r.ok, true, `strategy=${name}`);
assert.equal(r.status, 200);
assert.equal(r.body.strategy, name);
assert.equal(r.body.error, undefined);
assert.equal(r.body.available, undefined);
}
});
test("validatePatchStrategyBody: 未注册名 + 默认策略名永远可用作后续切换", () => {
// 这条测试锚定 reviewer 提到的 "未知名安全回退" 语义在 admin 层的体现:
// 即便用户写了未知名, 我们至少能把回退目标 (DEFAULT_EVOLUTION_STRATEGY)
// 列在 available 里,前端可一键切回安全态。
const r = validatePatchStrategyBody({ strategy: "unknown_xyz" });
assert.equal(r.ok, false);
const available = r.body.available as string[];
assert.ok(available.includes(DEFAULT_EVOLUTION_STRATEGY));
});