summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Bedford <guybedford@gmail.com>2018-01-17 00:35:54 +0200
committerGuy Bedford <guybedford@gmail.com>2018-01-22 18:39:21 +0200
commite7ff00d0c52ad7deefe8be4a6a293d15fd3fca7b (patch)
tree85ba33781747ad30295f491e07232e087b8f2662
parenta65b0b90c96546a33b0c9d52c9c7024df201d6b1 (diff)
downloadandroid-node-v8-e7ff00d0c52ad7deefe8be4a6a293d15fd3fca7b.tar.gz
android-node-v8-e7ff00d0c52ad7deefe8be4a6a293d15fd3fca7b.tar.bz2
android-node-v8-e7ff00d0c52ad7deefe8be4a6a293d15fd3fca7b.zip
inspector: --inspect-brk for es modules
Reworked rebase of PR #17360 with feedback PR-URL: https://github.com/nodejs/node/pull/18194 Fixes: https://github.com/nodejs/node/issues/17340 Reviewed-By: Eugene Ostroukhov <eostroukhov@google.com> Reviewed-By: James M Snell <jasnell@gmail.com>
-rw-r--r--lib/internal/loader/Loader.js11
-rw-r--r--lib/internal/loader/ModuleJob.js6
-rw-r--r--lib/module.js1
-rw-r--r--test/common/inspector-helper.js43
-rw-r--r--test/fixtures/es-modules/loop.mjs10
-rw-r--r--test/parallel/test-inspect-async-hook-setup-at-inspect.js1
-rw-r--r--test/parallel/test-inspector-esm.js120
-rw-r--r--test/parallel/test-inspector-no-crash-ws-after-bindings.js1
-rw-r--r--test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js1
-rw-r--r--test/sequential/test-inspector-async-hook-setup-at-signal.js1
-rw-r--r--test/sequential/test-inspector-async-stack-traces-promise-then.js1
-rw-r--r--test/sequential/test-inspector-async-stack-traces-set-interval.js1
-rw-r--r--test/sequential/test-inspector-break-e.js1
-rw-r--r--test/sequential/test-inspector-break-when-eval.js1
-rw-r--r--test/sequential/test-inspector-debug-brk-flag.js6
-rw-r--r--test/sequential/test-inspector-debug-end.js1
-rw-r--r--test/sequential/test-inspector-exception.js1
-rw-r--r--test/sequential/test-inspector-ip-detection.js1
-rw-r--r--test/sequential/test-inspector-not-blocked-on-idle.js1
-rw-r--r--test/sequential/test-inspector-scriptparsed-context.js1
-rw-r--r--test/sequential/test-inspector-stop-profile-after-done.js1
-rw-r--r--test/sequential/test-inspector.js13
22 files changed, 202 insertions, 22 deletions
diff --git a/lib/internal/loader/Loader.js b/lib/internal/loader/Loader.js
index 2e6a69af31..eda42645f1 100644
--- a/lib/internal/loader/Loader.js
+++ b/lib/internal/loader/Loader.js
@@ -44,6 +44,7 @@ class Loader {
throw new errors.TypeError('ERR_INVALID_ARG_TYPE', 'base', 'string');
this.base = base;
+ this.isMain = true;
// methods which translate input code or other information
// into es modules
@@ -132,7 +133,15 @@ class Loader {
loaderInstance = translators.get(format);
}
- job = new ModuleJob(this, url, loaderInstance);
+ let inspectBrk = false;
+ if (this.isMain) {
+ if (process._breakFirstLine) {
+ delete process._breakFirstLine;
+ inspectBrk = true;
+ }
+ this.isMain = false;
+ }
+ job = new ModuleJob(this, url, loaderInstance, inspectBrk);
this.moduleMap.set(url, job);
return job;
}
diff --git a/lib/internal/loader/ModuleJob.js b/lib/internal/loader/ModuleJob.js
index 8aa1b4b051..2d6325b85c 100644
--- a/lib/internal/loader/ModuleJob.js
+++ b/lib/internal/loader/ModuleJob.js
@@ -14,7 +14,7 @@ const enableDebug = (process.env.NODE_DEBUG || '').match(/\besm\b/) ||
class ModuleJob {
// `loader` is the Loader instance used for loading dependencies.
// `moduleProvider` is a function
- constructor(loader, url, moduleProvider) {
+ constructor(loader, url, moduleProvider, inspectBrk) {
this.loader = loader;
this.error = null;
this.hadError = false;
@@ -30,6 +30,10 @@ class ModuleJob {
const dependencyJobs = [];
({ module: this.module,
reflect: this.reflect } = await this.modulePromise);
+ if (inspectBrk) {
+ const initWrapper = process.binding('inspector').callAndPauseOnStart;
+ initWrapper(this.module.instantiate, this.module);
+ }
assert(this.module instanceof ModuleWrap);
this.module.link(async (dependencySpecifier) => {
const dependencyJobPromise =
diff --git a/lib/module.js b/lib/module.js
index 0ee109bc32..4a8480ed1b 100644
--- a/lib/module.js
+++ b/lib/module.js
@@ -467,6 +467,7 @@ Module._load = function(request, parent, isMain) {
ESMLoader = new Loader();
const userLoader = process.binding('config').userLoader;
if (userLoader) {
+ ESMLoader.isMain = false;
const hooks = await ESMLoader.import(userLoader);
ESMLoader = new Loader();
ESMLoader.hook(hooks);
diff --git a/test/common/inspector-helper.js b/test/common/inspector-helper.js
index 1f1738e31b..5e927f2150 100644
--- a/test/common/inspector-helper.js
+++ b/test/common/inspector-helper.js
@@ -5,7 +5,9 @@ const fs = require('fs');
const http = require('http');
const fixtures = require('../common/fixtures');
const { spawn } = require('child_process');
-const url = require('url');
+const { URL, parse: parseURL } = require('url');
+const { getURLFromFilePath } = require('internal/url');
+const path = require('path');
const _MAINSCRIPT = fixtures.path('loop.js');
const DEBUG = false;
@@ -171,8 +173,9 @@ class InspectorSession {
const scriptId = script['scriptId'];
const url = script['url'];
this._scriptsIdsByUrl.set(scriptId, url);
- if (url === _MAINSCRIPT)
+ if (getURLFromFilePath(url).toString() === this.scriptURL().toString()) {
this.mainScriptId = scriptId;
+ }
}
if (this._notificationCallback) {
@@ -238,11 +241,13 @@ class InspectorSession {
return notification;
}
- _isBreakOnLineNotification(message, line, url) {
+ _isBreakOnLineNotification(message, line, expectedScriptPath) {
if ('Debugger.paused' === message['method']) {
const callFrame = message['params']['callFrames'][0];
const location = callFrame['location'];
- assert.strictEqual(url, this._scriptsIdsByUrl.get(location['scriptId']));
+ const scriptPath = this._scriptsIdsByUrl.get(location['scriptId']);
+ assert(scriptPath.toString() === expectedScriptPath.toString(),
+ `${scriptPath} !== ${expectedScriptPath}`);
assert.strictEqual(line, location['lineNumber']);
return true;
}
@@ -291,12 +296,26 @@ class InspectorSession {
'Waiting for the debugger to disconnect...');
await this.disconnect();
}
+
+ scriptPath() {
+ return this._instance.scriptPath();
+ }
+
+ script() {
+ return this._instance.script();
+ }
+
+ scriptURL() {
+ return getURLFromFilePath(this.scriptPath());
+ }
}
class NodeInstance {
constructor(inspectorFlags = ['--inspect-brk=0'],
scriptContents = '',
scriptFile = _MAINSCRIPT) {
+ this._scriptPath = scriptFile;
+ this._script = scriptFile ? null : scriptContents;
this._portCallback = null;
this.portPromise = new Promise((resolve) => this._portCallback = resolve);
this._process = spawnChildProcess(inspectorFlags, scriptContents,
@@ -375,7 +394,7 @@ class NodeInstance {
const port = await this.portPromise;
return http.get({
port,
- path: url.parse(devtoolsUrl).path,
+ path: parseURL(devtoolsUrl).path,
headers: {
'Connection': 'Upgrade',
'Upgrade': 'websocket',
@@ -425,10 +444,16 @@ class NodeInstance {
kill() {
this._process.kill();
}
-}
-function readMainScriptSource() {
- return fs.readFileSync(_MAINSCRIPT, 'utf8');
+ scriptPath() {
+ return this._scriptPath;
+ }
+
+ script() {
+ if (this._script === null)
+ this._script = fs.readFileSync(this.scriptPath(), 'utf8');
+ return this._script;
+ }
}
function onResolvedOrRejected(promise, callback) {
@@ -469,7 +494,5 @@ function fires(promise, error, timeoutMs) {
}
module.exports = {
- mainScriptPath: _MAINSCRIPT,
- readMainScriptSource,
NodeInstance
};
diff --git a/test/fixtures/es-modules/loop.mjs b/test/fixtures/es-modules/loop.mjs
new file mode 100644
index 0000000000..33a382bdde
--- /dev/null
+++ b/test/fixtures/es-modules/loop.mjs
@@ -0,0 +1,10 @@
+var t = 1;
+var k = 1;
+console.log('A message', 5);
+while (t > 0) {
+ if (t++ === 1000) {
+ t = 0;
+ console.log(`Outputed message #${k++}`);
+ }
+}
+process.exit(55); \ No newline at end of file
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 869ec21ca9..6b1c875138 100644
--- a/test/parallel/test-inspect-async-hook-setup-at-inspect.js
+++ b/test/parallel/test-inspect-async-hook-setup-at-inspect.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/parallel/test-inspector-esm.js b/test/parallel/test-inspector-esm.js
new file mode 100644
index 0000000000..b5a1365212
--- /dev/null
+++ b/test/parallel/test-inspector-esm.js
@@ -0,0 +1,120 @@
+// Flags: --expose-internals
+'use strict';
+const common = require('../common');
+
+common.skipIfInspectorDisabled();
+
+const assert = require('assert');
+const fixtures = require('../common/fixtures');
+const { NodeInstance } = require('../common/inspector-helper.js');
+
+function assertNoUrlsWhileConnected(response) {
+ assert.strictEqual(response.length, 1);
+ assert.ok(!response[0].hasOwnProperty('devtoolsFrontendUrl'));
+ assert.ok(!response[0].hasOwnProperty('webSocketDebuggerUrl'));
+}
+
+function assertScopeValues({ result }, expected) {
+ const unmatched = new Set(Object.keys(expected));
+ for (const actual of result) {
+ const value = expected[actual['name']];
+ assert.strictEqual(actual['value']['value'], value);
+ unmatched.delete(actual['name']);
+ }
+ assert.deepStrictEqual(Array.from(unmatched.values()), []);
+}
+
+async function testBreakpointOnStart(session) {
+ console.log('[test]',
+ 'Verifying debugger stops on start (--inspect-brk option)');
+ const commands = [
+ { 'method': 'Runtime.enable' },
+ { 'method': 'Debugger.enable' },
+ { 'method': 'Debugger.setPauseOnExceptions',
+ 'params': { 'state': 'none' } },
+ { 'method': 'Debugger.setAsyncCallStackDepth',
+ 'params': { 'maxDepth': 0 } },
+ { 'method': 'Profiler.enable' },
+ { 'method': 'Profiler.setSamplingInterval',
+ 'params': { 'interval': 100 } },
+ { 'method': 'Debugger.setBlackboxPatterns',
+ 'params': { 'patterns': [] } },
+ { 'method': 'Runtime.runIfWaitingForDebugger' }
+ ];
+
+ await session.send(commands);
+ await session.waitForBreakOnLine(0, session.scriptURL());
+}
+
+async function testBreakpoint(session) {
+ console.log('[test]', 'Setting a breakpoint and verifying it is hit');
+ const commands = [
+ { 'method': 'Debugger.setBreakpointByUrl',
+ 'params': { 'lineNumber': 5,
+ 'url': session.scriptURL(),
+ 'columnNumber': 0,
+ 'condition': ''
+ }
+ },
+ { 'method': 'Debugger.resume' },
+ ];
+ await session.send(commands);
+ const { scriptSource } = await session.send({
+ 'method': 'Debugger.getScriptSource',
+ 'params': { 'scriptId': session.mainScriptId } });
+ assert(scriptSource && (scriptSource.includes(session.script())),
+ `Script source is wrong: ${scriptSource}`);
+
+ await session.waitForConsoleOutput('log', ['A message', 5]);
+ const paused = await session.waitForBreakOnLine(5, session.scriptURL());
+ const scopeId = paused.params.callFrames[0].scopeChain[0].object.objectId;
+
+ console.log('[test]', 'Verify we can read current application state');
+ const response = await session.send({
+ 'method': 'Runtime.getProperties',
+ 'params': {
+ 'objectId': scopeId,
+ 'ownProperties': false,
+ 'accessorPropertiesOnly': false,
+ 'generatePreview': true
+ }
+ });
+ assertScopeValues(response, { t: 1001, k: 1 });
+
+ let { result } = await session.send({
+ 'method': 'Debugger.evaluateOnCallFrame', 'params': {
+ 'callFrameId': '{"ordinal":0,"injectedScriptId":1}',
+ 'expression': 'k + t',
+ 'objectGroup': 'console',
+ 'includeCommandLineAPI': true,
+ 'silent': false,
+ 'returnByValue': false,
+ 'generatePreview': true
+ }
+ });
+
+ assert.strictEqual(result['value'], 1002);
+
+ result = (await session.send({
+ 'method': 'Runtime.evaluate', 'params': {
+ 'expression': '5 * 5'
+ }
+ })).result;
+ assert.strictEqual(result['value'], 25);
+}
+
+async function runTest() {
+ const child = new NodeInstance(['--inspect-brk=0', '--experimental-modules'],
+ '', fixtures.path('es-modules/loop.mjs'));
+
+ const session = await child.connectInspectorSession();
+ assertNoUrlsWhileConnected(await child.httpGet(null, '/json/list'));
+ await testBreakpointOnStart(session);
+ await testBreakpoint(session);
+ await session.runToCompletion();
+ assert.strictEqual((await child.expectShutdown()).exitCode, 55);
+}
+
+common.crashOnUnhandledRejection();
+
+runTest();
diff --git a/test/parallel/test-inspector-no-crash-ws-after-bindings.js b/test/parallel/test-inspector-no-crash-ws-after-bindings.js
index 286373068e..15fa96952e 100644
--- a/test/parallel/test-inspector-no-crash-ws-after-bindings.js
+++ b/test/parallel/test-inspector-no-crash-ws-after-bindings.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js b/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js
index 980e9e4d46..e0c3b4dcb8 100644
--- a/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js
+++ b/test/sequential/test-inspector-async-hook-setup-at-inspect-brk.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-async-hook-setup-at-signal.js b/test/sequential/test-inspector-async-hook-setup-at-signal.js
index 5ff7dec947..e0b87b0ebb 100644
--- a/test/sequential/test-inspector-async-hook-setup-at-signal.js
+++ b/test/sequential/test-inspector-async-hook-setup-at-signal.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-async-stack-traces-promise-then.js b/test/sequential/test-inspector-async-stack-traces-promise-then.js
index 9ed61d5ae1..b5cb651ff4 100644
--- a/test/sequential/test-inspector-async-stack-traces-promise-then.js
+++ b/test/sequential/test-inspector-async-stack-traces-promise-then.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-async-stack-traces-set-interval.js b/test/sequential/test-inspector-async-stack-traces-set-interval.js
index e778bfc802..326032d40b 100644
--- a/test/sequential/test-inspector-async-stack-traces-set-interval.js
+++ b/test/sequential/test-inspector-async-stack-traces-set-interval.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-break-e.js b/test/sequential/test-inspector-break-e.js
index 9ae47253f4..8db403ad2c 100644
--- a/test/sequential/test-inspector-break-e.js
+++ b/test/sequential/test-inspector-break-e.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
diff --git a/test/sequential/test-inspector-break-when-eval.js b/test/sequential/test-inspector-break-when-eval.js
index e5d01cb189..b14e01a301 100644
--- a/test/sequential/test-inspector-break-when-eval.js
+++ b/test/sequential/test-inspector-break-when-eval.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-debug-brk-flag.js b/test/sequential/test-inspector-debug-brk-flag.js
index 235e7043d8..61eb4f97c6 100644
--- a/test/sequential/test-inspector-debug-brk-flag.js
+++ b/test/sequential/test-inspector-debug-brk-flag.js
@@ -1,11 +1,11 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const assert = require('assert');
-const { mainScriptPath,
- NodeInstance } = require('../common/inspector-helper.js');
+const { NodeInstance } = require('../common/inspector-helper.js');
async function testBreakpointOnStart(session) {
const commands = [
@@ -24,7 +24,7 @@ async function testBreakpointOnStart(session) {
];
session.send(commands);
- await session.waitForBreakOnLine(0, mainScriptPath);
+ await session.waitForBreakOnLine(0, session.scriptPath());
}
async function runTests() {
diff --git a/test/sequential/test-inspector-debug-end.js b/test/sequential/test-inspector-debug-end.js
index effef9f233..dadee26258 100644
--- a/test/sequential/test-inspector-debug-end.js
+++ b/test/sequential/test-inspector-debug-end.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-exception.js b/test/sequential/test-inspector-exception.js
index 743742f50f..3f83b37c72 100644
--- a/test/sequential/test-inspector-exception.js
+++ b/test/sequential/test-inspector-exception.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
const fixtures = require('../common/fixtures');
diff --git a/test/sequential/test-inspector-ip-detection.js b/test/sequential/test-inspector-ip-detection.js
index f7dee4494d..a69a57f55f 100644
--- a/test/sequential/test-inspector-ip-detection.js
+++ b/test/sequential/test-inspector-ip-detection.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
diff --git a/test/sequential/test-inspector-not-blocked-on-idle.js b/test/sequential/test-inspector-not-blocked-on-idle.js
index 68e4eaaa57..3b1befe35d 100644
--- a/test/sequential/test-inspector-not-blocked-on-idle.js
+++ b/test/sequential/test-inspector-not-blocked-on-idle.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-scriptparsed-context.js b/test/sequential/test-inspector-scriptparsed-context.js
index f295d737da..abffbfe5fc 100644
--- a/test/sequential/test-inspector-scriptparsed-context.js
+++ b/test/sequential/test-inspector-scriptparsed-context.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector-stop-profile-after-done.js b/test/sequential/test-inspector-stop-profile-after-done.js
index d0285df175..7069e49025 100644
--- a/test/sequential/test-inspector-stop-profile-after-done.js
+++ b/test/sequential/test-inspector-stop-profile-after-done.js
@@ -1,3 +1,4 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
diff --git a/test/sequential/test-inspector.js b/test/sequential/test-inspector.js
index 992a12e902..c34c953006 100644
--- a/test/sequential/test-inspector.js
+++ b/test/sequential/test-inspector.js
@@ -1,12 +1,11 @@
+// Flags: --expose-internals
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const assert = require('assert');
-const { mainScriptPath,
- readMainScriptSource,
- NodeInstance } = require('../common/inspector-helper.js');
+const { NodeInstance } = require('../common/inspector-helper.js');
function checkListResponse(response) {
assert.strictEqual(1, response.length);
@@ -75,7 +74,7 @@ async function testBreakpointOnStart(session) {
];
await session.send(commands);
- await session.waitForBreakOnLine(0, mainScriptPath);
+ await session.waitForBreakOnLine(0, session.scriptPath());
}
async function testBreakpoint(session) {
@@ -83,7 +82,7 @@ async function testBreakpoint(session) {
const commands = [
{ 'method': 'Debugger.setBreakpointByUrl',
'params': { 'lineNumber': 5,
- 'url': mainScriptPath,
+ 'url': session.scriptPath(),
'columnNumber': 0,
'condition': ''
}
@@ -94,11 +93,11 @@ async function testBreakpoint(session) {
const { scriptSource } = await session.send({
'method': 'Debugger.getScriptSource',
'params': { 'scriptId': session.mainScriptId } });
- assert(scriptSource && (scriptSource.includes(readMainScriptSource())),
+ assert(scriptSource && (scriptSource.includes(session.script())),
`Script source is wrong: ${scriptSource}`);
await session.waitForConsoleOutput('log', ['A message', 5]);
- const paused = await session.waitForBreakOnLine(5, mainScriptPath);
+ const paused = await session.waitForBreakOnLine(5, session.scriptPath());
const scopeId = paused.params.callFrames[0].scopeChain[0].object.objectId;
console.log('[test]', 'Verify we can read current application state');