From f7a885790dec63483d92d843e4e6197781f8ea31 Mon Sep 17 00:00:00 2001 From: Christian Aurich Date: Thu, 27 Aug 2026 08:12:10 -0300 Subject: [PATCH] test: deflake test-inspect-async-hook-setup-at-inspect The test sends Debugger.setAsyncCallStackDepth in the same batch as Runtime.enable and Debugger.enable, and treats the command response as proof that async stack recording is on. It is not. While the target runs JS the command is dispatched from a V8 interrupt, where Agent::SyncAsyncHookState() cannot call into JS and defers enabling the async hook to an immediate, answering the command anyway. The `debugger` in the polling interval then pauses the target before that immediate runs, and the nested message loop does not process immediates, so setupTimeoutWithBreak() schedules the timer with the hook still disabled and Debugger.paused arrives without asyncStackTrace. Send the command after the first pause instead. Messages dispatched while the target is paused come from the nested message loop rather than an interrupt, so the hook is enabled inline and the response is the barrier the test assumed it to be. Deferring is deliberate: calling into JS from a V8 interrupt is not safe. This corrects an assumption of the test, not the runtime. Signed-off-by: Christian Aurich --- .../test-inspect-async-hook-setup-at-inspect.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/parallel/test-inspect-async-hook-setup-at-inspect.js b/test/parallel/test-inspect-async-hook-setup-at-inspect.js index 4b43fea96ab3..5d1f276ca5e1 100644 --- a/test/parallel/test-inspect-async-hook-setup-at-inspect.js +++ b/test/parallel/test-inspect-async-hook-setup-at-inspect.js @@ -25,6 +25,17 @@ async function waitForInitialSetup(session) { await session.waitForBreakOnLine(2, '[eval]'); } +// Sent only once the target is paused. While the target runs JS the command +// is dispatched from a V8 interrupt, where Agent::SyncAsyncHookState() cannot +// call into JS and defers enabling the async hook to an immediate that the +// pause then blocks, answering the command anyway. Dispatching from the paused +// message loop enables the hook inline, so the response is a real barrier. +async function enableAsyncStackTraces(session) { + console.error('[test]', 'Enabling async stack traces'); + await session.send({ 'method': 'Debugger.setAsyncCallStackDepth', + 'params': { 'maxDepth': 10 } }); +} + async function setupTimeoutForStackTrace(session) { console.error('[test]', 'Setting up timeout for async stack trace'); await session.send([ @@ -50,13 +61,12 @@ async function runTests() { await session.send([ { 'method': 'Runtime.enable' }, { 'method': 'Debugger.enable' }, - { 'method': 'Debugger.setAsyncCallStackDepth', - 'params': { 'maxDepth': 10 } }, { 'method': 'Debugger.setBlackboxPatterns', 'params': { 'patterns': [] } }, ]); await waitForInitialSetup(session); + await enableAsyncStackTraces(session); await setupTimeoutForStackTrace(session); await checkAsyncStackTrace(session);