tests/fixtures/server-process.js (2054 bytes)
1 // An ideamine server in its own process, as on a real server: its own IDEAMINE_HOME, sync off. The 2 // tests switch IDEAMINE_HOME between machines in the test process, so the server must not share it. 3 4 import { spawn } from 'node:child_process'; 5 import fs from 'node:fs'; 6 import net from 'node:net'; 7 import os from 'node:os'; 8 import path from 'node:path'; 9 import { fileURLToPath } from 'node:url'; 10 11 const BIN = fileURLToPath(new URL('../../bin/ideamine.js', import.meta.url)); 12 13 /** A port that nothing listens on now. */ 14 export async function freePort() { 15 const s = net.createServer(); 16 await new Promise((resolve) => s.listen(0, '127.0.0.1', resolve)); 17 const { port } = s.address(); 18 await new Promise((resolve) => s.close(resolve)); 19 return port; 20 } 21 22 /** Start `ideamine serve`. Resolves to { url, home, port, stop }. `env` adds settings. */ 23 export async function startServerProcess(env = {}) { 24 const home = fs.mkdtempSync(path.join(os.tmpdir(), 'ideamine-server-')); 25 const port = await freePort(); 26 const clean = { ...process.env }; 27 for (const key of Object.keys(clean)) if (key.startsWith('IDEAMINE_')) delete clean[key]; 28 const child = spawn(process.execPath, [BIN, 'serve', '--port', String(port)], { 29 env: { ...clean, IDEAMINE_HOME: home, IDEAMINE_EMBED_URL: 'http://127.0.0.1:9/v1', ...env }, 30 stdio: ['ignore', 'pipe', 'pipe'], 31 }); 32 let output = ''; 33 child.stdout.on('data', (d) => (output += d)); 34 child.stderr.on('data', (d) => (output += d)); 35 const url = `http://127.0.0.1:${port}/`; 36 for (let i = 0; ; i++) { 37 try { 38 if ((await fetch(`${url}api/ping`)).ok) break; 39 } catch { 40 // Not listening yet. 41 } 42 if (i > 100 || child.exitCode !== null) throw new Error(`the server did not start: ${output}`); 43 await new Promise((resolve) => setTimeout(resolve, 50)); 44 } 45 const stop = () => 46 new Promise((resolve) => { 47 if (child.exitCode !== null) return resolve(); 48 child.once('exit', resolve); 49 child.kill(); 50 }); 51 return { url, home, port, stop, output: () => output }; 52 }