1'use strict'; 2 3// Flags: --expose-gc 4 5const common = require('../common'); 6common.skipIfInspectorDisabled(); 7 8const assert = require('assert'); 9const vm = require('vm'); 10const { Session } = require('inspector'); 11 12const session = new Session(); 13session.connect(); 14 15function notificationPromise(method) { 16 return new Promise((resolve) => session.once(method, resolve)); 17} 18 19async function testContextCreatedAndDestroyed() { 20 console.log('Testing context created/destroyed notifications'); 21 { 22 const mainContextPromise = 23 notificationPromise('Runtime.executionContextCreated'); 24 25 session.post('Runtime.enable', assert.ifError); 26 const contextCreated = await mainContextPromise; 27 const { name, origin, auxData } = contextCreated.params.context; 28 if (common.isSunOS || common.isWindows || common.isIBMi) { 29 // uv_get_process_title() is unimplemented on Solaris-likes and IBMi, 30 // it returns an empty string. On the Windows CI buildbots it returns 31 // "Administrator: Windows PowerShell[42]" because of a GetConsoleTitle() 32 // quirk. Not much we can do about either, just verify that it contains 33 // the PID. 34 assert.strictEqual(name.includes(`[${process.pid}]`), true); 35 } else { 36 let expects = `${process.argv0}[${process.pid}]`; 37 if (!common.isMainThread) { 38 expects = `Worker[${require('worker_threads').threadId}]`; 39 } 40 assert.strictEqual(expects, name); 41 } 42 assert.strictEqual(origin, '', 43 JSON.stringify(contextCreated)); 44 assert.strictEqual(auxData.isDefault, true, 45 JSON.stringify(contextCreated)); 46 } 47 48 { 49 const vmContextCreatedPromise = 50 notificationPromise('Runtime.executionContextCreated'); 51 52 let contextDestroyed = null; 53 session.once('Runtime.executionContextDestroyed', 54 (notification) => contextDestroyed = notification); 55 56 vm.runInNewContext('1 + 1'); 57 58 const contextCreated = await vmContextCreatedPromise; 59 const { id, name, origin, auxData } = contextCreated.params.context; 60 assert.strictEqual(name, 'VM Context 1', 61 JSON.stringify(contextCreated)); 62 assert.strictEqual(origin, '', 63 JSON.stringify(contextCreated)); 64 assert.strictEqual(auxData.isDefault, false, 65 JSON.stringify(contextCreated)); 66 67 // GC is unpredictable... 68 console.log('Checking/waiting for GC.'); 69 while (!contextDestroyed) 70 global.gc(); 71 console.log('Context destroyed.'); 72 73 assert.strictEqual(contextDestroyed.params.executionContextId, id, 74 JSON.stringify(contextDestroyed)); 75 } 76 77 { 78 const vmContextCreatedPromise = 79 notificationPromise('Runtime.executionContextCreated'); 80 81 let contextDestroyed = null; 82 session.once('Runtime.executionContextDestroyed', 83 (notification) => contextDestroyed = notification); 84 85 vm.runInNewContext('1 + 1', {}, { 86 contextName: 'Custom context', 87 contextOrigin: 'https://origin.example' 88 }); 89 90 const contextCreated = await vmContextCreatedPromise; 91 const { name, origin, auxData } = contextCreated.params.context; 92 assert.strictEqual(name, 'Custom context', 93 JSON.stringify(contextCreated)); 94 assert.strictEqual(origin, 'https://origin.example', 95 JSON.stringify(contextCreated)); 96 assert.strictEqual(auxData.isDefault, false, 97 JSON.stringify(contextCreated)); 98 99 // GC is unpredictable... 100 console.log('Checking/waiting for GC again.'); 101 while (!contextDestroyed) 102 global.gc(); 103 console.log('Other context destroyed.'); 104 } 105 106 { 107 const vmContextCreatedPromise = 108 notificationPromise('Runtime.executionContextCreated'); 109 110 let contextDestroyed = null; 111 session.once('Runtime.executionContextDestroyed', 112 (notification) => contextDestroyed = notification); 113 114 vm.createContext({}, { origin: 'https://nodejs.org' }); 115 116 const contextCreated = await vmContextCreatedPromise; 117 const { name, origin, auxData } = contextCreated.params.context; 118 assert.strictEqual(name, 'VM Context 2', 119 JSON.stringify(contextCreated)); 120 assert.strictEqual(origin, 'https://nodejs.org', 121 JSON.stringify(contextCreated)); 122 assert.strictEqual(auxData.isDefault, false, 123 JSON.stringify(contextCreated)); 124 125 // GC is unpredictable... 126 console.log('Checking/waiting for GC a third time.'); 127 while (!contextDestroyed) 128 global.gc(); 129 console.log('Context destroyed once again.'); 130 } 131 132 { 133 const vmContextCreatedPromise = 134 notificationPromise('Runtime.executionContextCreated'); 135 136 let contextDestroyed = null; 137 session.once('Runtime.executionContextDestroyed', 138 (notification) => contextDestroyed = notification); 139 140 vm.createContext({}, { name: 'Custom context 2' }); 141 142 const contextCreated = await vmContextCreatedPromise; 143 const { name, auxData } = contextCreated.params.context; 144 assert.strictEqual(name, 'Custom context 2', 145 JSON.stringify(contextCreated)); 146 assert.strictEqual(auxData.isDefault, false, 147 JSON.stringify(contextCreated)); 148 149 // GC is unpredictable... 150 console.log('Checking/waiting for GC a fourth time.'); 151 while (!contextDestroyed) 152 global.gc(); 153 console.log('Context destroyed a fourth time.'); 154 } 155} 156 157async function testBreakpointHit() { 158 console.log('Testing breakpoint is hit in a new context'); 159 session.post('Debugger.enable', assert.ifError); 160 161 const pausedPromise = notificationPromise('Debugger.paused'); 162 vm.runInNewContext('debugger', {}); 163 await pausedPromise; 164} 165 166(async function() { 167 await testContextCreatedAndDestroyed(); 168 await testBreakpointHit(); 169})().then(common.mustCall()); 170