97 lines
4.2 KiB
JavaScript
97 lines
4.2 KiB
JavaScript
/**
|
|
* Token 服务单元测试
|
|
* 覆盖:多项目关联、名称唯一、全部 Token 均为 MCP 令牌、历史 MCP 配置迁移
|
|
* 运行:npm test
|
|
*/
|
|
const test = require("node:test");
|
|
const assert = require("node:assert");
|
|
const fs = require("node:fs");
|
|
const os = require("node:os");
|
|
const path = require("node:path");
|
|
|
|
// 使用临时数据目录,避免污染真实 data/
|
|
const tmpDataDir = fs.mkdtempSync(path.join(os.tmpdir(), "registry-token-test-"));
|
|
process.env.REGISTRY_DATA_DIR = tmpDataDir;
|
|
|
|
const { init } = require("../src/persistence/duckdbAdapter");
|
|
const tokenService = require("../src/services/tokenService");
|
|
|
|
test.before(async () => {
|
|
await init();
|
|
});
|
|
|
|
test("创建 Token:支持多个关联项目与全部项目", async () => {
|
|
const multi = await tokenService.createToken({
|
|
name: "multi-proj",
|
|
projectIds: ["proj-a", "proj-b"],
|
|
expiresInDays: 0,
|
|
});
|
|
assert.deepStrictEqual(multi.projectIds, ["proj-a", "proj-b"]);
|
|
assert.strictEqual(tokenService.coversProject(multi, "proj-a"), true);
|
|
assert.strictEqual(tokenService.coversProject(multi, "proj-b"), true);
|
|
assert.strictEqual(tokenService.coversProject(multi, "proj-c"), false);
|
|
|
|
const all = await tokenService.createToken({ name: "all-proj", projectIds: ["all"] });
|
|
assert.deepStrictEqual(all.projectIds, ["all"]);
|
|
assert.strictEqual(tokenService.coversProject(all, "任意项目"), true);
|
|
|
|
const legacyProjectId = await tokenService.createToken({ name: "legacy-field", projectId: "proj-x" });
|
|
assert.deepStrictEqual(legacyProjectId.projectIds, ["proj-x"]);
|
|
});
|
|
|
|
test("Token 名称唯一:重复名称创建与更新均报错", async () => {
|
|
await tokenService.createToken({ name: "dup-name", projectIds: ["all"] });
|
|
await assert.rejects(
|
|
() => tokenService.createToken({ name: "dup-name", projectIds: ["all"] }),
|
|
/名称已存在/
|
|
);
|
|
|
|
// 更新为已存在的名称也报错
|
|
const other = await tokenService.createToken({ name: "dup-other", projectIds: ["all"] });
|
|
await assert.rejects(
|
|
() => tokenService.updateToken(other.id, { name: "dup-name" }),
|
|
/名称已存在/
|
|
);
|
|
|
|
// 更新自身名称不改动、且可改成唯一名
|
|
await tokenService.updateToken(other.id, { name: "dup-other" });
|
|
await tokenService.updateToken(other.id, { name: "dup-renamed" });
|
|
assert.strictEqual((await tokenService.findById(other.id)).name, "dup-renamed");
|
|
});
|
|
|
|
test("所有 Token 均为 MCP 令牌:全部生效 Token 明文可获取,通过 resolveActiveToken 鉴权", async () => {
|
|
const t = await tokenService.createToken({ name: "mcp-all", projectIds: ["all"] });
|
|
const values = await tokenService.getActiveTokenValues();
|
|
assert.ok(values.includes(t.value), "新 Token 应直接生效于 MCP");
|
|
|
|
const resolved = await tokenService.resolveActiveToken(t.value);
|
|
assert.strictEqual(resolved.name, "mcp-all");
|
|
assert.strictEqual(await tokenService.resolveActiveToken("bad-token"), null);
|
|
});
|
|
|
|
test("吊销或过期后 Token 不再生效", async () => {
|
|
const t = await tokenService.createToken({ name: "will-revoke", projectIds: ["all"], expiresInDays: 30 });
|
|
assert.ok((await tokenService.getActiveTokenValues()).includes(t.value));
|
|
await tokenService.revokeToken(t.id);
|
|
assert.ok(!(await tokenService.getActiveTokenValues()).includes(t.value));
|
|
assert.strictEqual(await tokenService.resolveActiveToken(t.value), null);
|
|
});
|
|
|
|
test("migrateLegacyMcpToken 把历史 mcp_kv 配置迁移为 Token 记录", async () => {
|
|
const { loadApiTokens, saveApiTokens, saveMcpConfig, loadMcpConfig } = require("../src/persistence/duckdbAdapter");
|
|
const existing = await loadApiTokens();
|
|
await saveMcpConfig({ enabled: true, token: "legacy-mcp-token-abc" });
|
|
await tokenService.migrateLegacyMcpToken();
|
|
|
|
const tokens = await loadApiTokens();
|
|
const migrated = tokens.find((t) => t.value === "legacy-mcp-token-abc");
|
|
assert.ok(migrated, "应生成一条包含旧 token 的记录");
|
|
assert.strictEqual(migrated.projectIds[0], "all");
|
|
assert.ok((await tokenService.getActiveTokenValues()).includes("legacy-mcp-token-abc"));
|
|
// 旧配置已清空
|
|
const mcp = await loadMcpConfig();
|
|
assert.strictEqual(mcp.token, "");
|
|
|
|
// 清掉迁移产生的记录,避免影响后续测试
|
|
await saveApiTokens(existing);
|
|
}); |