const {spawn} = require('node:child_process'); const http = require('node:http'); const fs = require('node:fs'); const os = require('node:os'); const path = require('node:path'); const runDir = fs.mkdtempSync(path.join(os.tmpdir(), 'flood-smoke-')); const child = spawn('npm', ['run', 'start', '--', '--host=127.0.0.1', '--port=3000', `--rundir=${runDir}`], {stdio: 'inherit', detached: true}); let startupError; child.on('error', error => { startupError = error; }); const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); const check = () => new Promise(resolve => { const req = http.get('http://127.0.0.1:3000/', response => { let bytes = 0; response.on('data', chunk => { bytes += chunk.length; }); response.on('end', () => resolve(response.statusCode === 200 && bytes > 0)); }); req.setTimeout(1000, () => req.destroy()); req.on('error', () => resolve(false)); }); (async () => { try { const deadline = Date.now() + 60000; while (Date.now() < deadline) { if (startupError) throw startupError; if (child.exitCode !== null || child.signalCode !== null) { throw new Error(`Flood exited before serving HTTP: ${child.exitCode ?? child.signalCode}`); } if (await check()) { console.log('Flood startup smoke test passed: HTTP 200 with response body'); return; } await sleep(500); } throw new Error('Flood did not serve HTTP within 60 seconds'); } catch (error) { console.error(error); process.exitCode = 1; } finally { if (child.pid) { try { process.kill(-child.pid, 'SIGTERM'); } catch (error) { if (error.code !== 'ESRCH') throw error; } await sleep(500); try { process.kill(-child.pid, 'SIGKILL'); } catch (error) { if (error.code !== 'ESRCH') throw error; } } fs.rmSync(runDir, {recursive: true, force: true}); } })();