1// Flags: --expose-internals 2'use strict'; 3const common = require('../common'); 4common.skipIfInspectorDisabled(); 5common.skipIf32Bits(); 6const { NodeInstance } = require('../common/inspector-helper.js'); 7const assert = require('assert'); 8 9common.skipIfWorker(); // Signal starts a server for a main thread inspector 10 11const script = ` 12process._rawDebug('Waiting until a signal enables the inspector...'); 13let waiting = setInterval(waitUntilDebugged, 50); 14 15function waitUntilDebugged() { 16 const { internalBinding } = require('internal/test/binding'); 17 if (!internalBinding('inspector').isEnabled()) return; 18 clearInterval(waiting); 19 // At this point, even though the Inspector is enabled, the default async 20 // call stack depth is 0. We need a chance to call 21 // Debugger.setAsyncCallStackDepth *before* activating the actual timer for 22 // async stack traces to work. Directly using a debugger statement would be 23 // too brittle, and using a longer timeout would unnecessarily slow down the 24 // test on most machines. Triggering a debugger break through an interval is 25 // a faster and more reliable way. 26 process._rawDebug('Signal received, waiting for debugger setup'); 27 waiting = setInterval(() => { debugger; }, 50); 28} 29 30// This function is called by the inspector client (session) 31function setupTimeoutWithBreak() { 32 clearInterval(waiting); 33 process._rawDebug('Debugger ready, setting up timeout with a break'); 34 setTimeout(() => { debugger; }, 50); 35} 36`; 37 38async function waitForInitialSetup(session) { 39 console.error('[test]', 'Waiting for initial setup'); 40 await session.waitForBreakOnLine(16, '[eval]'); 41} 42 43async function setupTimeoutForStackTrace(session) { 44 console.error('[test]', 'Setting up timeout for async stack trace'); 45 await session.send([ 46 { 'method': 'Runtime.evaluate', 47 'params': { expression: 'setupTimeoutWithBreak()' } }, 48 { 'method': 'Debugger.resume' }, 49 ]); 50} 51 52async function checkAsyncStackTrace(session) { 53 console.error('[test]', 'Verify basic properties of asyncStackTrace'); 54 const paused = await session.waitForBreakOnLine(23, '[eval]'); 55 assert(paused.params.asyncStackTrace, 56 `${Object.keys(paused.params)} contains "asyncStackTrace" property`); 57 assert(paused.params.asyncStackTrace.description, 'Timeout'); 58 assert(paused.params.asyncStackTrace.callFrames 59 .some((frame) => frame.functionName === 'setupTimeoutWithBreak')); 60} 61 62async function runTests() { 63 const instance = await NodeInstance.startViaSignal(script); 64 const session = await instance.connectInspectorSession(); 65 await session.send([ 66 { 'method': 'Runtime.enable' }, 67 { 'method': 'Debugger.enable' }, 68 { 'method': 'Debugger.setAsyncCallStackDepth', 69 'params': { 'maxDepth': 10 } }, 70 { 'method': 'Debugger.setBlackboxPatterns', 71 'params': { 'patterns': [] } }, 72 { 'method': 'Runtime.runIfWaitingForDebugger' }, 73 ]); 74 75 await waitForInitialSetup(session); 76 await setupTimeoutForStackTrace(session); 77 await checkAsyncStackTrace(session); 78 79 console.error('[test]', 'Stopping child instance'); 80 session.disconnect(); 81 instance.kill(); 82} 83 84runTests().then(common.mustCall()); 85