mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
feat: add the feature for user save combo
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const originalDataDir = process.env.DATA_DIR;
|
||||
let tempDir;
|
||||
let db;
|
||||
let ownerOne;
|
||||
let ownerTwo;
|
||||
|
||||
beforeAll(async () => {
|
||||
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "9router-cli-tool-config-"));
|
||||
process.env.DATA_DIR = tempDir;
|
||||
try { global._dbAdapter?.instance?.close?.(); } catch {}
|
||||
delete global._dbAdapter;
|
||||
vi.resetModules();
|
||||
db = await import("@/lib/db/index.js");
|
||||
await db.initDb();
|
||||
ownerOne = await db.createUser({ username: "cli-owner-one", password: "password", role: "admin" });
|
||||
ownerTwo = await db.createUser({ username: "cli-owner-two", password: "password", role: "user" });
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
try { global._dbAdapter?.instance?.close?.(); } catch {}
|
||||
delete global._dbAdapter;
|
||||
if (tempDir) fs.rmSync(tempDir, { recursive: true, force: true });
|
||||
if (originalDataDir === undefined) delete process.env.DATA_DIR;
|
||||
else process.env.DATA_DIR = originalDataDir;
|
||||
});
|
||||
|
||||
const claudeConfig = (model) => ({
|
||||
baseUrl: "https://router.example/v1",
|
||||
apiKeyMode: "managed",
|
||||
apiKeyId: null,
|
||||
claudeModels: { sonnet: model, opus: "", haiku: "" },
|
||||
claudeThinking: { sonnet: "high" },
|
||||
});
|
||||
|
||||
describe("CLI tool configuration persistence", () => {
|
||||
it("round-trips and atomically overwrites one owner/tool row", async () => {
|
||||
const created = await db.upsertCliToolConfig(ownerOne.id, "claude", claudeConfig("cc/sonnet-a"));
|
||||
expect(created).toMatchObject({ ownerId: ownerOne.id, toolId: "claude", config: claudeConfig("cc/sonnet-a") });
|
||||
|
||||
const updated = await db.upsertCliToolConfig(ownerOne.id, "claude", claudeConfig("cc/sonnet-b"));
|
||||
expect(updated.config.claudeModels.sonnet).toBe("cc/sonnet-b");
|
||||
expect((await db.getCliToolConfigsByOwnerId(ownerOne.id)).filter((row) => row.toolId === "claude")).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("isolates users and permits concurrent saves to different tools", async () => {
|
||||
await Promise.all([
|
||||
db.upsertCliToolConfig(ownerOne.id, "cursor", {
|
||||
apiKeyMode: "custom",
|
||||
selectedModels: ["cc/a", "cx/b"],
|
||||
}),
|
||||
db.upsertCliToolConfig(ownerTwo.id, "cursor", {
|
||||
apiKeyMode: "managed",
|
||||
apiKeyId: null,
|
||||
selectedModels: ["gg/c"],
|
||||
}),
|
||||
db.upsertCliToolConfig(ownerOne.id, "codex", {
|
||||
baseUrl: "https://router.example/v1",
|
||||
apiKeyMode: "managed",
|
||||
apiKeyId: null,
|
||||
codexModel: "cx/gpt",
|
||||
codexThinking: "high",
|
||||
}),
|
||||
]);
|
||||
|
||||
expect((await db.getCliToolConfig(ownerOne.id, "cursor")).config.selectedModels).toEqual(["cc/a", "cx/b"]);
|
||||
expect((await db.getCliToolConfig(ownerTwo.id, "cursor")).config.selectedModels).toEqual(["gg/c"]);
|
||||
expect((await db.getCliToolConfig(ownerOne.id, "codex")).config.codexModel).toBe("cx/gpt");
|
||||
});
|
||||
|
||||
it("includes valid configurations in export/import and skips malformed rows", async () => {
|
||||
const exported = await db.exportDb();
|
||||
expect(exported.cliToolConfigs).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ ownerId: ownerOne.id, toolId: "claude" }),
|
||||
expect.objectContaining({ ownerId: ownerTwo.id, toolId: "cursor" }),
|
||||
]));
|
||||
|
||||
exported.cliToolConfigs.push({
|
||||
ownerId: ownerOne.id,
|
||||
toolId: "kiro",
|
||||
config: { apiKey: "must-not-import" },
|
||||
});
|
||||
await db.importDb(exported);
|
||||
|
||||
expect(await db.getCliToolConfig(ownerOne.id, "claude")).not.toBeNull();
|
||||
expect(await db.getCliToolConfig(ownerOne.id, "kiro")).toBeNull();
|
||||
});
|
||||
|
||||
it("removes configurations when their owner is deleted", async () => {
|
||||
const disposable = await db.createUser({ username: "cli-disposable", password: "password", role: "user" });
|
||||
await db.upsertCliToolConfig(disposable.id, "cursor", {
|
||||
apiKeyMode: "managed",
|
||||
apiKeyId: null,
|
||||
selectedModels: ["cc/a"],
|
||||
});
|
||||
|
||||
expect(await db.deleteUser(disposable.id)).toBe(true);
|
||||
expect(await db.getCliToolConfig(disposable.id, "cursor")).toBeNull();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user