Files
boss/tests/ai-account-onboarding.test.ts
2026-04-01 05:33:35 +08:00

252 lines
9.1 KiB
TypeScript

import test from "node:test";
import assert from "node:assert/strict";
import os from "node:os";
import path from "node:path";
import { mkdtemp, rm } from "node:fs/promises";
import { NextRequest } from "next/server";
let runtimeRoot = "";
let openAiOnboardRoute: (typeof import("../src/app/api/v1/accounts/onboard/openai-api/route"))["POST"];
let aliyunQwenOnboardRoute: (typeof import("../src/app/api/v1/accounts/onboard/aliyun-qwen/route"))["POST"];
let masterNodeOnboardRoute: (typeof import("../src/app/api/v1/accounts/onboard/master-node/route"))["POST"];
let createAuthSession: (typeof import("../src/lib/boss-data"))["createAuthSession"];
let readState: (typeof import("../src/lib/boss-data"))["readState"];
let AUTH_SESSION_COOKIE: string;
async function setup() {
if (runtimeRoot) return;
runtimeRoot = await mkdtemp(path.join(os.tmpdir(), "boss-ai-onboard-"));
process.env.BOSS_RUNTIME_ROOT = runtimeRoot;
process.env.BOSS_STATE_FILE = path.join(runtimeRoot, "boss-state.json");
const [openAiModule, aliyunModule, masterNodeModule, data, auth] = await Promise.all([
import("../src/app/api/v1/accounts/onboard/openai-api/route.ts"),
import("../src/app/api/v1/accounts/onboard/aliyun-qwen/route.ts"),
import("../src/app/api/v1/accounts/onboard/master-node/route.ts"),
import("../src/lib/boss-data.ts"),
import("../src/lib/boss-auth.ts"),
]);
openAiOnboardRoute = openAiModule.POST;
aliyunQwenOnboardRoute = aliyunModule.POST;
masterNodeOnboardRoute = masterNodeModule.POST;
createAuthSession = data.createAuthSession;
readState = data.readState;
AUTH_SESSION_COOKIE = auth.AUTH_SESSION_COOKIE;
}
test.after(async () => {
if (runtimeRoot) {
await rm(runtimeRoot, { recursive: true, force: true });
}
});
async function createAuthedJsonRequest(url: string, body: Record<string, unknown>) {
const session = await createAuthSession({
account: "17600003315",
role: "highest_admin",
displayName: "Boss 超级管理员",
loginMethod: "password",
});
return new NextRequest(url, {
method: "POST",
headers: {
"content-type": "application/json",
cookie: `${AUTH_SESSION_COOKIE}=${session.sessionToken}`,
},
body: JSON.stringify(body),
});
}
test("POST /api/v1/accounts/onboard/openai-api creates a primary openai account and activates it", async () => {
await setup();
const originalFetch = globalThis.fetch;
globalThis.fetch = (async (input, init) => {
if (typeof input === "string" && input === "https://api.openai.com/v1/responses") {
assert.equal(init?.method, "POST");
return new Response(JSON.stringify({ output_text: "连接正常" }), {
status: 200,
headers: {
"content-type": "application/json",
"x-request-id": "req-onboard-openai",
},
});
}
throw new Error(`unexpected fetch: ${String(input)}`);
}) as typeof fetch;
try {
const response = await openAiOnboardRoute(
await createAuthedJsonRequest("http://127.0.0.1:3000/api/v1/accounts/onboard/openai-api", {
label: "主 GPT",
displayName: "OpenAI 平台账号",
accountIdentifier: "sk-proj-demo",
model: "gpt-5.4",
apiKey: "sk-live-demo-123456",
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
accountId: string;
message: string;
activeIdentity: { accountId: string; provider: string; displayName: string };
};
assert.equal(payload.ok, true);
assert.equal(payload.accountId, "openai-api-primary");
assert.equal(payload.activeIdentity.accountId, "openai-api-primary");
assert.equal(payload.activeIdentity.provider, "openai_api");
assert.match(payload.message, /已登录/);
assert.match(payload.message, /当前主控/);
const state = await readState();
const account = state.aiAccounts.find((item) => item.accountId === "openai-api-primary");
assert.ok(account, "expected openai primary account to be created");
assert.equal(account?.provider, "openai_api");
assert.equal(account?.role, "primary");
assert.equal(account?.isActive, true);
assert.equal(account?.status, "ready");
assert.equal(account?.displayName, "OpenAI 平台账号");
assert.equal(account?.apiKey, "sk-live-demo-123456");
assert.match(account?.apiKeyMasked ?? "", /\.\.\./);
} finally {
globalThis.fetch = originalFetch;
}
});
test("POST /api/v1/accounts/onboard/master-node upserts a master node account and returns bound-device guidance", async () => {
await setup();
const response = await masterNodeOnboardRoute(
await createAuthedJsonRequest("http://127.0.0.1:3000/api/v1/accounts/onboard/master-node", {
label: "主 GPT",
displayName: "Mac 上的 Master Codex Node",
accountIdentifier: "17600003315",
nodeId: "mac-studio",
nodeLabel: "Mac Studio",
model: "gpt-5.4",
setActive: true,
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
accountId: string;
message: string;
validation: { status: string; message: string };
};
assert.equal(payload.ok, true);
assert.equal(payload.accountId, "master-codex-primary");
assert.match(payload.message, /当前主控|已绑定/);
assert.equal(payload.validation.status, "ready");
assert.match(payload.validation.message, /不在手机里直接登录/);
assert.match(payload.validation.message, /Mac Studio|绑定设备/);
const state = await readState();
const account = state.aiAccounts.find((item) => item.accountId === "master-codex-primary");
assert.ok(account, "expected master node primary account");
assert.equal(account?.provider, "master_codex_node");
assert.equal(account?.displayName, "Mac 上的 Master Codex Node");
assert.equal(account?.nodeId, "mac-studio");
assert.equal(account?.nodeLabel, "Mac Studio");
assert.equal(account?.isActive, true);
});
test("POST /api/v1/accounts/onboard/openai-api returns a clear network guidance when OpenAI is unreachable", async () => {
await setup();
const originalFetch = globalThis.fetch;
globalThis.fetch = (async () => {
const error = new TypeError("fetch failed");
(error as TypeError & { cause?: { code?: string; message?: string } }).cause = {
code: "ENETUNREACH",
message: "connect ENETUNREACH api.openai.com",
};
throw error;
}) as typeof fetch;
try {
const response = await openAiOnboardRoute(
await createAuthedJsonRequest("http://127.0.0.1:3000/api/v1/accounts/onboard/openai-api", {
label: "主 GPT",
displayName: "OpenAI 平台账号",
accountIdentifier: "sk-proj-demo",
model: "gpt-5.4",
apiKey: "sk-live-demo-123456",
}),
);
assert.equal(response.status, 400);
const payload = (await response.json()) as { ok: boolean; message: string };
assert.equal(payload.ok, false);
assert.match(payload.message, /无法访问 api\.openai\.com|无法连接 OpenAI API/);
} finally {
globalThis.fetch = originalFetch;
}
});
test("POST /api/v1/accounts/onboard/aliyun-qwen creates a backup aliyun qwen account", async () => {
await setup();
const originalFetch = globalThis.fetch;
globalThis.fetch = (async (input, init) => {
if (typeof input === "string" && input === "https://dashscope.aliyuncs.com/compatible-mode/v1/responses") {
assert.equal(init?.method, "POST");
return new Response(JSON.stringify({ output_text: "连接正常" }), {
status: 200,
headers: {
"content-type": "application/json",
"x-request-id": "req-onboard-aliyun",
},
});
}
throw new Error(`unexpected fetch: ${String(input)}`);
}) as typeof fetch;
try {
const response = await aliyunQwenOnboardRoute(
await createAuthedJsonRequest("http://127.0.0.1:3000/api/v1/accounts/onboard/aliyun-qwen", {
label: "阿里备用",
displayName: "阿里百炼备用账号",
accountIdentifier: "dashscope-demo",
model: "qwen3.5-plus",
apiKey: "sk-aliyun-demo-123456",
}),
);
assert.equal(response.status, 200);
const payload = (await response.json()) as {
ok: boolean;
accountId: string;
message: string;
account: { provider: string; role: string; model: string; isActive: boolean };
};
assert.equal(payload.ok, true);
assert.equal(payload.accountId, "aliyun-qwen-backup");
assert.equal(payload.account.provider, "aliyun_qwen_api");
assert.equal(payload.account.role, "backup");
assert.equal(payload.account.model, "qwen3.5-plus");
assert.equal(payload.account.isActive, false);
assert.match(payload.message, /备用/);
assert.match(payload.message, /阿里|百炼/);
const state = await readState();
const account = state.aiAccounts.find((item) => item.accountId === "aliyun-qwen-backup");
assert.ok(account, "expected aliyun backup account to be created");
assert.equal(account?.provider, "aliyun_qwen_api");
assert.equal(account?.role, "backup");
assert.equal(account?.model, "qwen3.5-plus");
assert.equal(account?.apiKey, "sk-aliyun-demo-123456");
} finally {
globalThis.fetch = originalFetch;
}
});