'use strict'; // Flags: --expose-gc const common = require('../common'); common.skipIfInspectorDisabled(); const assert = require('assert'); const vm = require('vm'); const { Session } = require('inspector'); const session = new Session(); session.connect(); function notificationPromise(method) { return new Promise((resolve) => session.once(method, resolve)); } async function testContextCreatedAndDestroyed() { console.log('Testing context created/destroyed notifications'); { const mainContextPromise = notificationPromise('Runtime.executionContextCreated'); session.post('Runtime.enable', assert.ifError); const contextCreated = await mainContextPromise; const { name, origin, auxData } = contextCreated.params.context; if (common.isSunOS || common.isWindows) { // uv_get_process_title() is unimplemented on Solaris-likes, it returns // an empty string. On the Windows CI buildbots it returns // "Administrator: Windows PowerShell[42]" because of a GetConsoleTitle() // quirk. Not much we can do about either, just verify that it contains // the PID. assert.strictEqual(name.includes(`[${process.pid}]`), true); } else { let expects = `${process.argv0}[${process.pid}]`; if (!common.isMainThread) { expects = `Worker[${require('worker_threads').threadId}]`; } assert.strictEqual(expects, name); } assert.strictEqual(origin, '', JSON.stringify(contextCreated)); assert.strictEqual(auxData.isDefault, true, JSON.stringify(contextCreated)); } { const vmContextCreatedPromise = notificationPromise('Runtime.executionContextCreated'); let contextDestroyed = null; session.once('Runtime.executionContextDestroyed', (notification) => contextDestroyed = notification); vm.runInNewContext('1 + 1'); const contextCreated = await vmContextCreatedPromise; const { id, name, origin, auxData } = contextCreated.params.context; assert.strictEqual(name, 'VM Context 1', JSON.stringify(contextCreated)); assert.strictEqual(origin, '', JSON.stringify(contextCreated)); assert.strictEqual(auxData.isDefault, false, JSON.stringify(contextCreated)); // GC is unpredictable... console.log('Checking/waiting for GC.'); while (!contextDestroyed) global.gc(); console.log('Context destroyed.'); assert.strictEqual(contextDestroyed.params.executionContextId, id, JSON.stringify(contextDestroyed)); } { const vmContextCreatedPromise = notificationPromise('Runtime.executionContextCreated'); let contextDestroyed = null; session.once('Runtime.executionContextDestroyed', (notification) => contextDestroyed = notification); vm.runInNewContext('1 + 1', {}, { contextName: 'Custom context', contextOrigin: 'https://origin.example' }); const contextCreated = await vmContextCreatedPromise; const { name, origin, auxData } = contextCreated.params.context; assert.strictEqual(name, 'Custom context', JSON.stringify(contextCreated)); assert.strictEqual(origin, 'https://origin.example', JSON.stringify(contextCreated)); assert.strictEqual(auxData.isDefault, false, JSON.stringify(contextCreated)); // GC is unpredictable... console.log('Checking/waiting for GC again.'); while (!contextDestroyed) global.gc(); console.log('Other context destroyed.'); } { const vmContextCreatedPromise = notificationPromise('Runtime.executionContextCreated'); let contextDestroyed = null; session.once('Runtime.executionContextDestroyed', (notification) => contextDestroyed = notification); vm.createContext({}, { origin: 'https://nodejs.org' }); const contextCreated = await vmContextCreatedPromise; const { name, origin, auxData } = contextCreated.params.context; assert.strictEqual(name, 'VM Context 2', JSON.stringify(contextCreated)); assert.strictEqual(origin, 'https://nodejs.org', JSON.stringify(contextCreated)); assert.strictEqual(auxData.isDefault, false, JSON.stringify(contextCreated)); // GC is unpredictable... console.log('Checking/waiting for GC a third time.'); while (!contextDestroyed) global.gc(); console.log('Context destroyed once again.'); } { const vmContextCreatedPromise = notificationPromise('Runtime.executionContextCreated'); let contextDestroyed = null; session.once('Runtime.executionContextDestroyed', (notification) => contextDestroyed = notification); vm.createContext({}, { name: 'Custom context 2' }); const contextCreated = await vmContextCreatedPromise; const { name, auxData } = contextCreated.params.context; assert.strictEqual(name, 'Custom context 2', JSON.stringify(contextCreated)); assert.strictEqual(auxData.isDefault, false, JSON.stringify(contextCreated)); // GC is unpredictable... console.log('Checking/waiting for GC a fourth time.'); while (!contextDestroyed) global.gc(); console.log('Context destroyed a fourth time.'); } } async function testBreakpointHit() { console.log('Testing breakpoint is hit in a new context'); session.post('Debugger.enable', assert.ifError); const pausedPromise = notificationPromise('Debugger.paused'); vm.runInNewContext('debugger', {}); await pausedPromise; } testContextCreatedAndDestroyed().then(common.mustCall(testBreakpointHit));