| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- #!/usr/bin/env node
- const assert = require('assert');
- const http = require('http');
- const { loadCatalog, searchEndpoints, findEndpoint } = require('../mcp/src/core/api-catalog');
- const { searchQiweApis, getQiweApiDoc, callQiweApi } = require('../mcp/src/tools/qiwe-api-catalog-run');
- const {
- qiweLoginStatus,
- qiweLoginStart,
- qiweLoginCheck,
- qiweLoginVerify
- } = require('../mcp/src/tools/qiwe-login-run');
- const {
- qiweSubscriptionStatus,
- qiweSubscribe,
- qiweSubscriptionAutoRenew
- } = require('../mcp/src/tools/qiwe-subscription-run');
- const PRIVATE_PROVIDER_NAME = ['private', 'provider'].join('-');
- const PRIVATE_PROVIDER_HOST = ['private', 'provider', 'invalid'].join('.');
- const PRIVATE_CREDENTIAL_KEY = ['token', 'Id'].join('');
- function assertProviderHidden(value) {
- const output = JSON.stringify(value);
- assert(!output.includes(PRIVATE_PROVIDER_NAME));
- assert(!output.includes(PRIVATE_PROVIDER_HOST));
- assert(!output.includes('server-only-guid'));
- assert(!output.includes('server-only-token'));
- }
- function readBody(req) {
- return new Promise(resolve => {
- let body = '';
- req.setEncoding('utf8');
- req.on('data', chunk => {
- body += chunk;
- });
- req.on('end', () => resolve(body ? JSON.parse(body) : undefined));
- });
- }
- async function startMockGateway() {
- const requests = [];
- const server = http.createServer(async (req, res) => {
- const body = await readBody(req);
- const url = new URL(req.url, 'http://localhost');
- requests.push({
- method: req.method,
- path: url.pathname,
- query: Object.fromEntries(url.searchParams.entries()),
- authorization: req.headers.authorization,
- body
- });
- let data;
- if (url.pathname === '/doApi') {
- data = {
- nickname: '测试账号',
- echoedMethod: body.method,
- guid: 'server-only-guid',
- [PRIVATE_CREDENTIAL_KEY]: 'server-only-token',
- provider: PRIVATE_PROVIDER_NAME,
- providerName: PRIVATE_PROVIDER_NAME,
- providerHost: PRIVATE_PROVIDER_HOST,
- supportUrl: `https://${PRIVATE_PROVIDER_HOST}/help`,
- diagnostic: `See https://${PRIVATE_PROVIDER_HOST}/diagnostic`
- };
- } else if (url.pathname === '/login/status') {
- data = { configured: true, online: true, statusCode: 2 };
- } else if (url.pathname === '/login/start') {
- data = { uid: body.uid, guid: 'server-only-guid', loginQrcodeBase64Data: Buffer.from('mock-png').toString('base64') };
- } else if (url.pathname === '/login/check') {
- data = { uid: body.uid, guid: 'server-only-guid', status: 2, detail: { nickname: '测试账号', userId: 'u-1' } };
- } else if (url.pathname === '/login/verify') {
- data = { accepted: true };
- } else if (url.pathname === '/subscribe/status') {
- data = {
- subscribed: true,
- seats: 2,
- usedSeats: 1,
- expireAt: '2026-08-10T00:00:00.000Z',
- autoRenew: true,
- balance: 1000
- };
- } else if (url.pathname === '/subscribe') {
- data = { seats: body.seats || 1, expireAt: '2026-08-10T00:00:00.000Z', autoRenew: true };
- } else if (url.pathname === '/subscribe/autoRenew') {
- data = { autoRenew: body.autoRenew };
- } else {
- res.writeHead(404, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ code: 404, mess: 'not found' }));
- return;
- }
- res.writeHead(200, { 'Content-Type': 'application/json' });
- res.end(JSON.stringify({ code: 200, data }));
- });
- await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
- const address = server.address();
- return {
- requests,
- apiBase: `http://127.0.0.1:${address.port}`,
- close: () => new Promise(resolve => server.close(resolve))
- };
- }
- async function main() {
- const catalog = loadCatalog();
- assert(catalog.endpoints.length >= 100, 'catalog should contain 100+ endpoints');
- assert(catalog.gateway.baseUrl.includes('server.fmode.cn/api/qiwe'));
- assert(catalog.endpoints.every(endpoint => !Object.hasOwn(endpoint, 'docUrl')));
- assertProviderHidden(catalog);
- console.log(`[ok] catalog loaded: ${catalog.endpoints.length} endpoints`);
- const hits = searchEndpoints({ query: '发送 文本' });
- assert(hits.length > 0 && hits[0].module === 'msg');
- assert(findEndpoint('/login/getLoginQrcode'));
- const searchResult = await searchQiweApis({ query: '朋友圈' });
- assert(searchResult.status === 'ok' && searchResult.data.endpoints.length > 0);
- assertProviderHidden(searchResult);
- const doc = await getQiweApiDoc({ id: 'user.getProfile' });
- assert(doc.status === 'ok' && doc.data.callTemplate);
- assertProviderHidden(doc);
- assert(!JSON.stringify(doc).includes('"guid"'));
- console.log('[ok] catalog search and docs');
- const gateway = await startMockGateway();
- const common = {
- authToken: 'sk-test-relay-token',
- uid: 'qiwe-smoke-device',
- apiBase: gateway.apiBase,
- persistConfig: false
- };
- try {
- const call = await callQiweApi({ ...common, id: 'user.getProfile', params: {} });
- assert.strictEqual(call.status, 'ok');
- const apiRequest = gateway.requests.at(-1);
- assert.strictEqual(apiRequest.path, '/doApi');
- assert.strictEqual(apiRequest.authorization, 'Bearer sk-test-relay-token');
- assert.deepStrictEqual(apiRequest.body, {
- uid: 'qiwe-smoke-device',
- method: '/user/getProfile',
- params: {}
- });
- assert(!JSON.stringify(apiRequest.body).includes('tokenId'));
- assert(!JSON.stringify(apiRequest.body).includes('guid'));
- assertProviderHidden(call);
- console.log('[ok] qiwe_api_call uses the Fmode gateway envelope without private credentials');
- const blocked = await callQiweApi({ ...common, rawMethod: '/login/manualLogin', params: {} });
- assert.strictEqual(blocked.status, 'error');
- assert.strictEqual(gateway.requests.at(-1), apiRequest);
- const subscription = await qiweSubscriptionStatus(common);
- assert.strictEqual(subscription.status, 'ok');
- assert.strictEqual(subscription.summary.subscribed, true);
- const subscribed = await qiweSubscribe({ ...common, seats: 3 });
- assert.strictEqual(subscribed.status, 'ok');
- assert.strictEqual(gateway.requests.at(-1).body.seats, 3);
- const autoRenew = await qiweSubscriptionAutoRenew({ ...common, autoRenew: false });
- assert.strictEqual(autoRenew.status, 'ok');
- assert.strictEqual(gateway.requests.at(-1).body.autoRenew, false);
- console.log('[ok] subscription tools use Fmode gateway routes');
- const status = await qiweLoginStatus(common);
- assert.strictEqual(status.status, 'ok');
- assert.strictEqual(gateway.requests.at(-1).query.uid, common.uid);
- const start = await qiweLoginStart({ ...common, openBrowser: false });
- assert.strictEqual(start.status, 'ok');
- assertProviderHidden(start);
- const check = await qiweLoginCheck(common);
- assert.strictEqual(check.status, 'ok');
- assert.strictEqual(check.summary.loggedIn, true);
- assertProviderHidden(check);
- const verify = await qiweLoginVerify({ ...common, code: '123456' });
- assert.strictEqual(verify.status, 'ok');
- assert.deepStrictEqual(gateway.requests.at(-1).body, { uid: common.uid, code: '123456' });
- console.log('[ok] login tools use uid-based Fmode gateway routes and hide internal identifiers');
- for (const request of gateway.requests) {
- assert.strictEqual(request.authorization, 'Bearer sk-test-relay-token');
- }
- console.log(`[ok] ${gateway.requests.length} mock Fmode gateway requests authenticated`);
- } finally {
- await gateway.close();
- }
- console.log('\nAll smoke tests passed.');
- }
- main().catch(error => {
- console.error('smoke test failed:', error);
- process.exit(1);
- });
|