Spaces:
Sleeping
Sleeping
| import test from "node:test"; | |
| import assert from "node:assert/strict"; | |
| import fs from "node:fs/promises"; | |
| import os from "node:os"; | |
| import path from "node:path"; | |
| import { PoolStore } from "./pool-store.mjs"; | |
| async function makeTempRoot() { | |
| return fs.mkdtemp(path.join(os.tmpdir(), "pool-store-test-")); | |
| } | |
| test("PoolStore lists the fixed pools", () => { | |
| const store = new PoolStore(); | |
| assert.deepEqual( | |
| store.listPools().map((item) => item.id), | |
| ["codex-accounts", "codex-api", "claude-code-api"], | |
| ); | |
| }); | |
| test("PoolStore validates bad pool ids", async () => { | |
| const store = new PoolStore(); | |
| await assert.rejects( | |
| store.loadPool("missing-pool"), | |
| (error) => error?.statusCode === 404, | |
| ); | |
| }); | |
| test("PoolStore rejects invalid codex account items", () => { | |
| const store = new PoolStore(); | |
| const result = store.validatePoolItems("codex-accounts", [ | |
| { type: "codex", tokens: { access_token: "", account_id: "" } }, | |
| ]); | |
| assert.equal(result.ok, false); | |
| assert.ok(result.errors.length >= 2); | |
| }); | |
| test("PoolStore saves valid api pool items to pool.json", async () => { | |
| const root = await makeTempRoot(); | |
| const filePath = path.join(root, "api_pool", "codex", "pool.json"); | |
| const store = new PoolStore([ | |
| { | |
| id: "codex-api", | |
| label: "Codex API 池", | |
| category: "api", | |
| provider: "codex", | |
| filePath, | |
| }, | |
| ]); | |
| const result = await store.savePool("codex-api", [ | |
| { | |
| name: "main", | |
| type: "codex", | |
| baseUrl: "https://example.com/v1", | |
| apiKey: "sk-test", | |
| model: "gpt-5.4", | |
| disabled: false, | |
| }, | |
| ]); | |
| assert.equal(result.count, 1); | |
| const written = JSON.parse(await fs.readFile(result.pool.filePath, "utf8")); | |
| assert.equal(written[0].name, "main"); | |
| }); | |
| test("PoolStore uses injected definitions instead of workspace defaults", async () => { | |
| const root = await makeTempRoot(); | |
| const injectedFilePath = path.join(root, "custom", "pool.json"); | |
| const store = new PoolStore([ | |
| { | |
| id: "codex-api", | |
| label: "Injected Codex API 池", | |
| category: "api", | |
| provider: "codex", | |
| filePath: injectedFilePath, | |
| }, | |
| ]); | |
| const result = await store.savePool("codex-api", [ | |
| { | |
| name: "injected", | |
| type: "codex", | |
| baseUrl: "https://example.com/v1", | |
| apiKey: "sk-injected", | |
| model: "gpt-5.4", | |
| disabled: false, | |
| }, | |
| ]); | |
| assert.equal(result.pool.filePath, injectedFilePath); | |
| const written = JSON.parse(await fs.readFile(injectedFilePath, "utf8")); | |
| assert.equal(written[0].name, "injected"); | |
| }); | |
| test("PoolStore updates a codex account from local auth.json when account_id matches", async () => { | |
| const root = await makeTempRoot(); | |
| const poolFilePath = path.join(root, "acc_pool", "pool.json"); | |
| const authPath = path.join(root, "home", ".codex", "auth.json"); | |
| await fs.mkdir(path.dirname(poolFilePath), { recursive: true }); | |
| await fs.mkdir(path.dirname(authPath), { recursive: true }); | |
| await fs.writeFile( | |
| poolFilePath, | |
| `${JSON.stringify([ | |
| { | |
| type: "codex", | |
| email: "user@example.com", | |
| tokens: { | |
| access_token: "old-access", | |
| account_id: "acc-1", | |
| id_token: "old-id", | |
| refresh_token: "old-refresh", | |
| }, | |
| }, | |
| ], null, 2)}\n`, | |
| "utf8", | |
| ); | |
| await fs.writeFile( | |
| authPath, | |
| `${JSON.stringify({ | |
| auth_mode: "chatgpt", | |
| tokens: { | |
| access_token: "new-access", | |
| account_id: "acc-1", | |
| id_token: "new-id", | |
| refresh_token: "new-refresh", | |
| }, | |
| }, null, 2)}\n`, | |
| "utf8", | |
| ); | |
| const store = new PoolStore([ | |
| { | |
| id: "codex-accounts", | |
| label: "Codex 账号池", | |
| category: "accounts", | |
| provider: "codex", | |
| filePath: poolFilePath, | |
| }, | |
| ]); | |
| const result = await store.updateCodexAccountFromLocalAuth(0, { authPath }); | |
| assert.equal(result.items[0].tokens.access_token, "new-access"); | |
| assert.equal(result.items[0].tokens.refresh_token, "new-refresh"); | |
| }); | |
| test("PoolStore rejects local auth.json update when account_id mismatches", async () => { | |
| const root = await makeTempRoot(); | |
| const poolFilePath = path.join(root, "acc_pool", "pool.json"); | |
| const authPath = path.join(root, "home", ".codex", "auth.json"); | |
| await fs.mkdir(path.dirname(poolFilePath), { recursive: true }); | |
| await fs.mkdir(path.dirname(authPath), { recursive: true }); | |
| await fs.writeFile( | |
| poolFilePath, | |
| `${JSON.stringify([ | |
| { | |
| type: "codex", | |
| tokens: { | |
| access_token: "old-access", | |
| account_id: "acc-1", | |
| id_token: "old-id", | |
| refresh_token: "old-refresh", | |
| }, | |
| }, | |
| ], null, 2)}\n`, | |
| "utf8", | |
| ); | |
| await fs.writeFile( | |
| authPath, | |
| `${JSON.stringify({ | |
| auth_mode: "chatgpt", | |
| tokens: { | |
| access_token: "new-access", | |
| account_id: "acc-2", | |
| id_token: "new-id", | |
| refresh_token: "new-refresh", | |
| }, | |
| }, null, 2)}\n`, | |
| "utf8", | |
| ); | |
| const store = new PoolStore([ | |
| { | |
| id: "codex-accounts", | |
| label: "Codex 账号池", | |
| category: "accounts", | |
| provider: "codex", | |
| filePath: poolFilePath, | |
| }, | |
| ]); | |
| await assert.rejects( | |
| store.updateCodexAccountFromLocalAuth(0, { authPath }), | |
| (error) => error?.statusCode === 409, | |
| ); | |
| }); | |