credential-token-switch-smoke-test.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #!/usr/bin/env node
  2. 'use strict';
  3. const assert = require('assert/strict');
  4. const fs = require('fs');
  5. const os = require('os');
  6. const path = require('path');
  7. function envValue(filePath, key) {
  8. const content = fs.readFileSync(filePath, 'utf8');
  9. const match = content.match(new RegExp(`^${key}=(.*)$`, 'm'));
  10. return match ? match[1].trim() : undefined;
  11. }
  12. function json(data) {
  13. return new Response(JSON.stringify({ code: 200, data }), {
  14. status: 200,
  15. headers: { 'Content-Type': 'application/json' },
  16. });
  17. }
  18. async function main() {
  19. const packageRoot = path.resolve(__dirname, '..');
  20. const fixtureRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'qiwei-token-switch-'));
  21. const previousCwd = process.cwd();
  22. const previousEnv = { ...process.env };
  23. const originalFetch = global.fetch;
  24. let closeAgentWorkbenches = () => {};
  25. let stopMonitor = () => {};
  26. const requests = [];
  27. try {
  28. process.env.HOME = fixtureRoot;
  29. process.env.USERPROFILE = fixtureRoot;
  30. process.env.QIWEI_PACKAGE_ROOT = fixtureRoot;
  31. process.env.QIWEI_WORKSPACE_ROOT = fixtureRoot;
  32. process.env.QIWEI_OUTPUTS_DIR = path.join(fixtureRoot, 'outputs');
  33. process.env.QIWEI_AUTH_TOKEN = 'sk-old-account';
  34. process.env.QIWEI_UID = 'uid-old-account';
  35. process.env.QIWEI_GUID = 'guid-old-account';
  36. process.env.QIWEI_API_BASE = 'https://fixture.example/api/qiwei';
  37. process.chdir(fixtureRoot);
  38. fs.writeFileSync(path.join(fixtureRoot, '.env.local'), [
  39. 'QIWEI_AUTH_TOKEN=sk-old-account',
  40. 'QIWEI_UID=uid-old-account',
  41. 'QIWEI_GUID=guid-old-account',
  42. 'QIWEI_API_BASE=https://fixture.example/api/qiwei',
  43. '',
  44. ].join('\n'), 'utf8');
  45. global.fetch = async (rawUrl, options = {}) => {
  46. const url = new URL(String(rawUrl));
  47. const authorization = String(options.headers?.Authorization || options.headers?.authorization || '');
  48. requests.push({ path: url.pathname, authorization });
  49. if (url.pathname.endsWith('/trial/status')) {
  50. return json({ active: true, state: 'active', seats: 1, credentialReady: true, expireAt: '2099-01-01T00:00:00.000Z' });
  51. }
  52. if (url.pathname.endsWith('/subscribe/status')) {
  53. return json({ subscribed: false, seats: null, usedSeats: 0 });
  54. }
  55. if (url.pathname.endsWith('/login/status')) {
  56. const sameAccount = authorization.includes('sk-old-account') || authorization.includes('r:same-account');
  57. return json({
  58. configured: sameAccount,
  59. online: sameAccount,
  60. statusCode: sameAccount ? 2 : null,
  61. detail: sameAccount ? { userId: 'user-old', nickname: 'Old Account' } : {},
  62. });
  63. }
  64. throw new Error(`Unexpected fixture request: ${url.pathname}`);
  65. };
  66. const dashboardServer = require(path.join(packageRoot, 'mcp', 'src', 'dashboard', 'server'));
  67. const agentService = require(path.join(packageRoot, 'mcp', 'src', 'dashboard', 'agent-service'));
  68. const credentials = require(path.join(packageRoot, 'mcp', 'src', 'core', 'credentials'));
  69. closeAgentWorkbenches = agentService.closeAgentWorkbenches;
  70. stopMonitor = () => dashboardServer.__testing.accountConnectionMonitor.stop();
  71. const sameAccount = await dashboardServer.__testing.saveAuthToken('r:same-account');
  72. assert.equal(sameAccount.status, 'ok');
  73. assert.equal(sameAccount.summary.accountReset, false);
  74. assert.equal(envValue(path.join(fixtureRoot, '.env.local'), 'QIWEI_UID'), 'uid-old-account');
  75. assert.equal(credentials.readQiweiUid(), 'uid-old-account');
  76. const differentAccount = await dashboardServer.__testing.saveAuthToken('r:different-account');
  77. assert.equal(differentAccount.status, 'ok');
  78. assert.equal(differentAccount.summary.accountReset, true);
  79. assert.equal(differentAccount.summary.trialActive, true);
  80. assert.equal(envValue(path.join(fixtureRoot, '.env.local'), 'QIWEI_AUTH_TOKEN'), 'r:different-account');
  81. assert.equal(envValue(path.join(fixtureRoot, '.env.local'), 'QIWEI_UID'), '');
  82. assert.equal(envValue(path.join(fixtureRoot, '.env.local'), 'QIWEI_GUID'), '');
  83. assert.equal(credentials.readQiweiUid(), '');
  84. assert.equal(credentials.readQiweiGuid(), '');
  85. assert.equal(agentService.__testing.activeAccountMetadata().uid, '');
  86. assert.equal(agentService.__testing.activeAccountMetadata().guid, '');
  87. assert.equal(dashboardServer.__testing.accountConnectionMonitor.state.lastOutput, null);
  88. assert.equal(requests.some(item => item.path.endsWith('/login/start')), false);
  89. process.stdout.write(`${JSON.stringify({
  90. status: 'ok',
  91. checks: 16,
  92. coverage: [
  93. 'same_account_session_refresh_keeps_device_binding',
  94. 'different_account_token_clears_uid_and_guid',
  95. 'different_account_switch_resets_workbench_context',
  96. 'credential_switch_does_not_start_login',
  97. ],
  98. }, null, 2)}\n`);
  99. } finally {
  100. stopMonitor();
  101. closeAgentWorkbenches();
  102. global.fetch = originalFetch;
  103. process.chdir(previousCwd);
  104. for (const key of Object.keys(process.env)) {
  105. if (!(key in previousEnv)) delete process.env[key];
  106. }
  107. for (const [key, value] of Object.entries(previousEnv)) process.env[key] = value;
  108. fs.rmSync(fixtureRoot, { recursive: true, force: true });
  109. }
  110. }
  111. main().catch(error => {
  112. process.stderr.write(`${error.stack || error.message}\n`);
  113. process.exitCode = 1;
  114. });