import http from 'node:http'; import { readAllChunks, tryParse } from '../../src/util.js'; export class MockServer { /** @type {string} */ host; /** @type {number} */ port; /** @type {import('http').Server} */ server; /** * Creates an instance of MockServer. * @param {object} [param] Options object. * @param {string} [param.host] The hostname or IP address to bind the server to. * @param {number} [param.port] The port number to listen on. */ constructor({ host, port } = {}) { this.host = host ?? '127.0.0.1'; this.port = port ?? 3000; } /** * Handles Chat Completions requests. * @param {object} jsonBody The parsed JSON body from the request. * @returns {object} Mock response object. */ handleChatCompletions(jsonBody) { const messages = jsonBody?.messages; const lastMessage = messages?.[messages.length - 1]; const mockResponse = { choices: [ { finish_reason: 'stop', index: 0, message: { role: 'assistant', reasoning_content: `${jsonBody?.model}\n${messages?.length}\n${jsonBody?.max_tokens}`, content: String(lastMessage?.content ?? 'No prompt messages.'), }, }, ], created: 0, model: jsonBody?.model, }; return mockResponse; } /** * Starts the mock server. * @returns {Promise} */ async start() { return new Promise((resolve, reject) => { this.server = http.createServer(async (req, res) => { try { const body = await readAllChunks(req); const jsonBody = tryParse(body.toString()); if (req.method === 'POST' && req.url === '/v1/chat/completions') { const mockResponse = this.handleChatCompletions(jsonBody); res.writeHead(200, { 'Content-Type': 'application/json' }); res.end(JSON.stringify(mockResponse)); } else { res.writeHead(404); res.end(); } } catch (error) { res.writeHead(500); res.end(); } }); this.server.on('error', (err) => { reject(err); }); this.server.listen(this.port, this.host, () => { resolve(); }); }); } /** * Stops the mock server. * @returns {Promise} */ async stop() { return new Promise((resolve, reject) => { if (!this.server) { return reject(new Error('Server is not running.')); } this.server.closeAllConnections(); this.server.close(( /** @type {NodeJS.ErrnoException|undefined} */ err) => { if (err && (err?.code !== 'ERR_SERVER_NOT_RUNNING')) { return reject(err); } resolve(); }); }); } }