// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. InspectorTest.log('Tests external stack traces'); let contextGroup1 = new InspectorTest.ContextGroup(); let session1 = contextGroup1.connect(); let Protocol1 = session1.Protocol; let contextGroup2 = new InspectorTest.ContextGroup(); let session2 = contextGroup2.connect(); let Protocol2 = session2.Protocol; session1.setupScriptMap(); session2.setupScriptMap(); let utilsScript = ` function store(description) { let buffer = inspector.storeCurrentStackTrace(description); return '[' + new Int32Array(buffer).join(',') + ']'; } function started(id) { inspector.externalAsyncTaskStarted(Int32Array.from(JSON.parse(id)).buffer); } function finished(id) { inspector.externalAsyncTaskFinished(Int32Array.from(JSON.parse(id)).buffer); }`; contextGroup1.addScript(utilsScript, 0, 0, 'utils.js'); contextGroup2.addScript(utilsScript, 0, 0, 'utils.js'); InspectorTest.runAsyncTestSuite([ async function testDebuggerId() { InspectorTest.log('Enabling debugger first time..'); let {result: {debuggerId}} = await Protocol1.Debugger.enable(); let firstDebuggerId = debuggerId; InspectorTest.log('Enabling debugger again..'); ({result: {debuggerId}} = await Protocol1.Debugger.enable()); if (firstDebuggerId !== debuggerId) { InspectorTest.log( 'FAIL: second Debugger.enable returns different debugger id'); } else { InspectorTest.log( '> second Debugger.enable returns the same debugger id'); } InspectorTest.log('Enabling debugger in another context group..'); ({result: {debuggerId}} = await Protocol2.Debugger.enable()); if (firstDebuggerId === debuggerId) { InspectorTest.log( 'FAIL: Debugger.enable in another context group returns the same debugger id'); } else { InspectorTest.log( '> Debugger.enable in another context group returns own debugger id'); } await Protocol2.Debugger.disable(); }, async function testInstrumentation() { Protocol1.Debugger.enable(); Protocol1.Debugger.setAsyncCallStackDepth({maxDepth: 32}); let result = await Protocol1.Runtime.evaluate( {expression: 'id = inspector.storeCurrentStackTrace(\'stack\')'}); let stackTraceId = result.result.result.objectId; Protocol1.Runtime.evaluate({ expression: `inspector.externalAsyncTaskStarted(id); debugger; inspector.externalAsyncTaskFinished(id);` }); let {params: {callFrames, asyncStackTraceId}} = await Protocol1.Debugger.oncePaused(); result = await Protocol1.Debugger.getStackTrace( {stackTraceId: asyncStackTraceId}); InspectorTest.logMessage(result); await Protocol1.Debugger.disable(); }, async function testDisableStacksAfterStored() { Protocol1.Debugger.enable(); Protocol1.Debugger.setAsyncCallStackDepth({maxDepth: 32}); let result = await Protocol1.Runtime.evaluate( {expression: 'id = inspector.storeCurrentStackTrace(\'stack\')'}); let stackTraceId = result.result.result.objectId; Protocol1.Debugger.setAsyncCallStackDepth({maxDepth: 0}); Protocol1.Runtime.evaluate({ expression: `inspector.externalAsyncTaskStarted(id); debugger; inspector.externalAsyncTaskFinished(id);` }); let {params: {callFrames, asyncStackTraceId}} = await Protocol1.Debugger.oncePaused(); if (!asyncStackTraceId) { InspectorTest.log('> external async stack trace is empty'); } else { InspectorTest.log('FAIL: external async stack trace is reported'); } await Protocol1.Debugger.disable(); }, async function testDisableStacksAfterStarted() { Protocol1.Debugger.enable(); Protocol1.Debugger.setAsyncCallStackDepth({maxDepth: 32}); let result = await Protocol1.Runtime.evaluate( {expression: 'id = inspector.storeCurrentStackTrace(\'stack\')'}); let stackTraceId = result.result.result.objectId; Protocol1.Runtime.evaluate( {expression: 'inspector.externalAsyncTaskStarted(id);'}); Protocol1.Debugger.setAsyncCallStackDepth({maxDepth: 0}); Protocol1.Runtime.evaluate({ expression: `debugger; inspector.externalAsyncTaskFinished(id);` }); let {params: {callFrames, asyncStackTraceId}} = await Protocol1.Debugger.oncePaused(); if (!asyncStackTraceId) { InspectorTest.log('> external async stack trace is empty'); } else { InspectorTest.log('FAIL: external async stack trace is reported'); } await Protocol1.Debugger.disable(); }, async function testExternalStacks() { let debuggerId1 = (await Protocol1.Debugger.enable()).result.debuggerId; let debuggerId2 = (await Protocol2.Debugger.enable()).result.debuggerId; Protocol1.Debugger.setAsyncCallStackDepth({maxDepth: 32}); Protocol2.Debugger.setAsyncCallStackDepth({maxDepth: 32}); let stackTraceId1 = (await Protocol1.Runtime.evaluate({ expression: 'store(\'stack\')//# sourceURL=expr1-1.js' })).result.result.value; let stackTraceId2 = (await Protocol2.Runtime.evaluate({ expression: `started('${stackTraceId1}'); id = store('stack2'); finished('${stackTraceId1}'); id //# sourceURL=expr2.js` })).result.result.value; Protocol1.Runtime.evaluate({ expression: `started('${stackTraceId2}'); debugger; finished('${stackTraceId2}'); id //# sourceURL=expr1-2.js` }); let {params: {callFrames, asyncStackTraceId}} = await Protocol1.Debugger.oncePaused(); let debuggers = new Map( [[debuggerId1, Protocol1.Debugger], [debuggerId2, Protocol2.Debugger]]); let sessions = new Map([[debuggerId1, session1], [debuggerId2, session2]]); let currentDebuggerId = debuggerId1; while (true) { sessions.get(currentDebuggerId).logCallFrames(callFrames); if (asyncStackTraceId) { currentDebuggerId = asyncStackTraceId.debuggerId; let {result: {stackTrace}} = await debuggers.get(currentDebuggerId).getStackTrace({ stackTraceId: asyncStackTraceId }); InspectorTest.log(`-- ${stackTrace.description} --`); callFrames = stackTrace.callFrames; asyncStackTraceId = stackTrace.parentId; } else { break; } } Protocol1.Debugger.disable(); await Protocol2.Debugger.disable(); } ]);