'use strict'; const assert = require('assert'); const fs = require('fs'); const os = require('os'); const path = require('path'); const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'openai-auth-db-')); const Config = require('../src/core/config'); Config.DATA_DIR = tempDir; Config.DB_PATH = path.join(tempDir, 'accounts.db'); const database = require('../src/core/database'); try { database.initDB(); const columns = database.getDb().pragma('table_info(accounts)').map(row => row.name); assert(columns.includes('openai_auth_status')); assert(columns.includes('openai_auth_json')); for (const column of [ 'openai_plan_status', 'openai_plan_type', 'openai_usage_percent', 'openai_subscription_expires_at', 'openai_plan_checked_at', ]) assert(columns.includes(column), `缺少套餐查询字段: ${column}`); const email = 'independent@example.com'; const sessionJson = JSON.stringify({ user: { email }, accessToken: 'session-token' }); const authJson = JSON.stringify({ code: 'code-1', access_token: 'access-1', refresh_token: 'refresh-1', id_token: 'id-1', }); database.upsertAccount({ email, password: 'secret' }); assert.strictEqual(database.updateAccountChatgptResult(email, '已登录', sessionJson), true); assert.strictEqual(database.updateAccountOpenAIAuth(email, '已提取 JSON', authJson), true); let account = database.getAccount(email); assert.strictEqual(account.chatgpt_session, sessionJson); assert.strictEqual(account.openai_auth_json, authJson); assert.strictEqual(account.openai_auth_status, '已提取 JSON'); assert.strictEqual(database.updateAccountOpenAIAuthStatus(email, '提取失败'), true); account = database.getAccount(email); assert.strictEqual(account.openai_auth_json, authJson, '失败状态不得清空旧授权 JSON'); assert.strictEqual(account.chatgpt_session, sessionJson, '授权状态更新不得覆盖 Session'); const refreshedAuthJson = JSON.stringify({ access_token: 'access-2', refresh_token: 'refresh-2', plan_type: 'plus', usage: { rate_limit: { primary_window: { used_percent: 25 } } }, subscription_expires_at: '2027-02-01T00:00:00.000Z', }); assert.strictEqual(database.updateAccountOpenAIPlan( email, '查询成功', 'plus', 25, '2027-02-01T00:00:00.000Z', refreshedAuthJson, ), true); account = database.getAccount(email); assert.strictEqual(account.openai_plan_status, '查询成功'); assert.strictEqual(account.openai_plan_type, 'plus'); assert.strictEqual(account.openai_usage_percent, 25); assert.strictEqual(account.openai_subscription_expires_at, '2027-02-01T00:00:00.000Z'); assert.strictEqual(account.openai_auth_json, refreshedAuthJson, '刷新后的 Token 必须与套餐结果原子保存'); assert.ok(account.openai_plan_checked_at); assert.strictEqual(database.updateAccountOpenAIPlanStatus(email, '查询失败'), true); account = database.getAccount(email); assert.strictEqual(account.openai_plan_status, '查询失败'); assert.strictEqual(account.openai_plan_type, 'plus', '查询失败不得清空上次成功套餐'); assert.strictEqual(account.openai_usage_percent, 25, '查询失败不得清空上次用量'); assert.strictEqual(account.openai_auth_json, refreshedAuthJson, '查询失败不得改写授权 JSON'); const preservedStatus = account.status; const preservedChatgptStatus = account.chatgpt_status; assert.strictEqual(database.updateAccountOpenAIAuthStatus(email, '需要手机号'), true); account = database.getAccount(email); assert.strictEqual(account.openai_auth_status, '需要手机号'); assert.strictEqual(account.message, '需要手机号', '手机号状态必须同步写入处理结论'); assert.strictEqual(account.status_reason, 'OPENAI_PHONE_REQUIRED'); assert.strictEqual(account.status, preservedStatus, '手机号结果不得修改账号总状态'); assert.strictEqual(account.chatgpt_status, preservedChatgptStatus, '手机号结果不得修改 ChatGPT 状态'); assert.strictEqual(account.openai_auth_json, refreshedAuthJson, '手机号结果不得清空旧授权 JSON'); assert.strictEqual(account.chatgpt_session, sessionJson, '手机号结果不得覆盖 Session'); const staged = database.stageAccounts([email], '授权JSON暂存测试', ['email', 'openai_auth_json']); assert.strictEqual(staged.count, 1); const batch = database.getStagingBatch(staged.batchId); assert.deepStrictEqual(JSON.parse(batch.batch.selected_fields), ['email', 'openai_auth_json']); console.log('openai_auth_database.test.js: PASS'); } finally { try { database.getDb().close(); } catch (_) {} fs.rmSync(tempDir, { recursive: true, force: true }); }