From cf3dd365d6849835da510564b8f399d75ee8001d Mon Sep 17 00:00:00 2001 From: 0age <37939117+0age@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:44:56 -0800 Subject: [PATCH] fix hanging smoke test script --- scripts/smoke-test.js | 54 ++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/scripts/smoke-test.js b/scripts/smoke-test.js index bd7537c..8c50c8f 100644 --- a/scripts/smoke-test.js +++ b/scripts/smoke-test.js @@ -10,6 +10,7 @@ function waitForServer(command, args, timeoutMs) { let serverStarted = false; let output = ''; + let processExited = false; process.stdout.on('data', (data) => { const chunk = data.toString(); @@ -18,7 +19,7 @@ function waitForServer(command, args, timeoutMs) { // Check if server has started if (chunk.includes('Server listening')) { serverStarted = true; - resolve(); + resolve(process); } }); @@ -26,27 +27,34 @@ function waitForServer(command, args, timeoutMs) { const timeout = setTimeout(() => { if (!serverStarted) { process.kill('SIGTERM'); - reject(new Error('Server failed to start within timeout')); + reject(new Error(`Server failed to start within ${timeoutMs}ms timeout.\nOutput: ${output}`)); } }, timeoutMs); process.on('error', (error) => { clearTimeout(timeout); - reject(error); + reject(new Error(`Server process error: ${error.message}\nOutput: ${output}`)); }); process.on('exit', (code) => { clearTimeout(timeout); + processExited = true; if (!serverStarted) { - reject(new Error(`Process exited with code ${code}\nOutput: ${output}`)); + reject(new Error(`Process exited with code ${code} before server started\nOutput: ${output}`)); } }); - return process; + // Additional safety timeout - if process exits without starting + setTimeout(() => { + if (!serverStarted && !processExited) { + process.kill('SIGTERM'); + reject(new Error(`Server did not start or exit within ${timeoutMs * 2}ms\nOutput: ${output}`)); + } + }, timeoutMs * 2); }); } -// Kill process using port +// Kill process using port with timeout async function killProcessOnPort(port) { try { // Find process using port @@ -67,11 +75,23 @@ async function killProcessOnPort(port) { const kill = spawn('kill', ['-9', pid], { stdio: 'inherit', shell: true }); kill.on('exit', () => resolve()); }); - // Wait a bit for the process to die - await new Promise(resolve => setTimeout(resolve, 1000)); + + // Wait for port to be free with timeout + const maxAttempts = 10; + for (let i = 0; i < maxAttempts; i++) { + await new Promise(resolve => setTimeout(resolve, 500)); + const checkPort = spawn('lsof', ['-t', `-i:${port}`], { shell: true }); + const stillInUse = await new Promise(resolve => { + checkPort.on('close', code => resolve(code === 0)); + }); + if (!stillInUse) break; + if (i === maxAttempts - 1) { + throw new Error(`Port ${port} is still in use after ${maxAttempts} attempts to free it`); + } + } } } catch (e) { - // Ignore errors from kill commands + console.error(`Error killing process on port ${port}:`, e.message); } } @@ -79,17 +99,23 @@ async function killProcessOnPort(port) { const PORT = process.env.SMOKE_TEST_PORT || 3000; async function main() { + let devServer = null; + let prodServer = null; + try { // Ensure port is free before starting await killProcessOnPort(PORT); // Test development mode console.log(`Testing development mode (pnpm dev) on port ${PORT}...`); - await waitForServer('PORT=' + PORT + ' pnpm', ['dev'], 10000); + devServer = await waitForServer('PORT=' + PORT + ' pnpm', ['dev'], 10000); console.log('āœ“ Development server started successfully'); // Kill the development server - await killProcessOnPort(PORT); + if (devServer) { + devServer.kill('SIGTERM'); + await killProcessOnPort(PORT); + } // Test production mode console.log('\nTesting production mode (pnpm start)...'); @@ -103,7 +129,7 @@ async function main() { }); }); - await waitForServer('PORT=' + PORT + ' pnpm', ['start'], 10000); + prodServer = await waitForServer('PORT=' + PORT + ' pnpm', ['start'], 10000); console.log('āœ“ Production server started successfully'); console.log('\nāœ… All smoke tests passed!'); @@ -112,7 +138,9 @@ async function main() { console.error('\nāŒ Smoke tests failed:', error.message); process.exit(1); } finally { - // Cleanup: ensure port is free + // Cleanup: ensure all servers are stopped + if (devServer) devServer.kill('SIGTERM'); + if (prodServer) prodServer.kill('SIGTERM'); await killProcessOnPort(PORT); } }