From c9247d6695fb310e325ef2b8585709f0274a40b0 Mon Sep 17 00:00:00 2001 From: Wen Date: Sun, 31 May 2026 04:38:21 -0700 Subject: [PATCH] test(evm): cap child_process.exec in lib.js to surface stalled commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Autobahn EVM integration matrix has hit multiple 30-minute job timeouts where hardhat went silent between test files with no error. The orphan-process listing at cleanup consistently shows a docker exec (running `seid tx evm send` or similar) still alive — `child_process.exec` has no timeout by default, so a stalled CLI invocation eats the entire job budget instead of surfacing as a clear error. Add a default 60s timeout to execCommand with a SIGKILL kill signal. On expiry, throw an error containing the offending command so the next occurrence is a 60s actionable error instead of a 30-minute mystery. Override via EXEC_TIMEOUT_MS for tests that legitimately need longer. Co-Authored-By: Claude Opus 4.7 (1M context) --- contracts/test/lib.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/contracts/test/lib.js b/contracts/test/lib.js index 5fc378cd7e..0d8c769708 100644 --- a/contracts/test/lib.js +++ b/contracts/test/lib.js @@ -1032,9 +1032,22 @@ async function execute(command, interaction=`printf "12345678\\n"`){ } function execCommand(command) { + // Cap shelled-out child processes (typically `docker exec ... seid ...`) + // with a timeout so an indefinite stall surfaces as an error with the + // command text, instead of consuming the entire job's wall-clock budget. + // The Autobahn EVM matrix has hit multiple 30-minute job timeouts where + // hardhat went silent between test files; suspect path is a stalled + // child here. Override via EXEC_TIMEOUT_MS for tests that legitimately + // need longer. + const timeoutMs = Number(process.env.EXEC_TIMEOUT_MS || 60000) return new Promise((resolve, reject) => { - exec(command, (error, stdout, stderr) => { + exec(command, { timeout: timeoutMs, killSignal: "SIGKILL" }, (error, stdout, stderr) => { if (error) { + if (error.killed || error.signal) { + const summary = command.length > 200 ? command.slice(0, 197) + "..." : command + reject(new Error(`execCommand timed out after ${timeoutMs}ms: ${summary}`)) + return + } reject(error); return; }