summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorEugene Ostroukhov <eostroukhov@chromium.org>2017-05-31 15:14:52 -0700
committerEugene Ostroukhov <eostroukhov@chromium.org>2017-06-05 08:47:43 -0700
commite6dcc3dfa9dbbf59cf6f67425e47c47bea70fe2c (patch)
tree1b34b15cf54eba71bf5e3f21aa16d6e5c4ada01a /test
parent5d9dc94509253845642e617f9d6d47ce0d09d7da (diff)
downloadnode-new-e6dcc3dfa9dbbf59cf6f67425e47c47bea70fe2c.tar.gz
inspector: Allows reentry when paused
This change allows reentering the message dispatch loop when the Node is paused. This is necessary when the pause happened as a result of the message sent by a debug frontend, such as evaluating a function with a breakpoint inside. Fixes: https://github.com/nodejs/node/issues/13320 PR-URL: https://github.com/nodejs/node/pull/13350 Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'test')
-rw-r--r--test/inspector/global-function.js13
-rw-r--r--test/inspector/inspector-helper.js28
-rw-r--r--test/inspector/test-inspector-break-when-eval.js128
3 files changed, 160 insertions, 9 deletions
diff --git a/test/inspector/global-function.js b/test/inspector/global-function.js
new file mode 100644
index 0000000000..d72bacd7ca
--- /dev/null
+++ b/test/inspector/global-function.js
@@ -0,0 +1,13 @@
+'use strict'; // eslint-disable-line required-modules
+let invocations = 0;
+const interval = setInterval(() => {}, 1000);
+
+global.sum = function() {
+ const a = 1;
+ const b = 2;
+ const c = a + b;
+ clearInterval(interval);
+ console.log(invocations++, c);
+};
+
+console.log('Ready!');
diff --git a/test/inspector/inspector-helper.js b/test/inspector/inspector-helper.js
index 755c357077..faf932f495 100644
--- a/test/inspector/inspector-helper.js
+++ b/test/inspector/inspector-helper.js
@@ -10,6 +10,7 @@ const url = require('url');
const DEBUG = false;
const TIMEOUT = 15 * 1000;
const EXPECT_ALIVE_SYMBOL = Symbol('isAlive');
+const DONT_EXPECT_RESPONSE_SYMBOL = Symbol('dontExpectResponse');
const mainScript = path.join(common.fixturesDir, 'loop.js');
function send(socket, message, id, callback) {
@@ -183,7 +184,6 @@ TestSession.prototype.processMessage_ = function(message) {
this.messagefilter_ && this.messagefilter_(message);
const id = message['id'];
if (id) {
- assert.strictEqual(id, this.expectedId_);
this.expectedId_++;
if (this.responseCheckers_[id]) {
const messageJSON = JSON.stringify(message);
@@ -207,16 +207,21 @@ TestSession.prototype.sendAll_ = function(commands, callback) {
if (!commands.length) {
callback();
} else {
- this.lastId_++;
+ let id = ++this.lastId_;
let command = commands[0];
if (command instanceof Array) {
- this.responseCheckers_[this.lastId_] = command[1];
+ this.responseCheckers_[id] = command[1];
command = command[0];
}
if (command instanceof Function)
command = command();
- this.messages_[this.lastId_] = command;
- send(this.socket_, command, this.lastId_,
+ if (!command[DONT_EXPECT_RESPONSE_SYMBOL]) {
+ this.messages_[id] = command;
+ } else {
+ id += 100000;
+ this.lastId_--;
+ }
+ send(this.socket_, command, id,
() => this.sendAll_(commands.slice(1), callback));
}
};
@@ -497,12 +502,13 @@ Harness.prototype.kill = function() {
exports.startNodeForInspectorTest = function(callback,
inspectorFlags = ['--inspect-brk'],
- opt_script_contents) {
+ scriptContents = '',
+ scriptFile = mainScript) {
const args = [].concat(inspectorFlags);
- if (opt_script_contents) {
- args.push('-e', opt_script_contents);
+ if (scriptContents) {
+ args.push('-e', scriptContents);
} else {
- args.push(mainScript);
+ args.push(scriptFile);
}
const child = spawn(process.execPath, args);
@@ -534,3 +540,7 @@ exports.startNodeForInspectorTest = function(callback,
exports.mainScriptSource = function() {
return fs.readFileSync(mainScript, 'utf8');
};
+
+exports.markMessageNoResponse = function(message) {
+ message[DONT_EXPECT_RESPONSE_SYMBOL] = true;
+};
diff --git a/test/inspector/test-inspector-break-when-eval.js b/test/inspector/test-inspector-break-when-eval.js
new file mode 100644
index 0000000000..388edf6f5c
--- /dev/null
+++ b/test/inspector/test-inspector-break-when-eval.js
@@ -0,0 +1,128 @@
+'use strict';
+const common = require('../common');
+common.skipIfInspectorDisabled();
+const assert = require('assert');
+const helper = require('./inspector-helper.js');
+const path = require('path');
+
+const script = path.join(path.dirname(module.filename), 'global-function.js');
+
+
+function setupExpectBreakOnLine(line, url, session) {
+ return function(message) {
+ if ('Debugger.paused' === message['method']) {
+ const callFrame = message['params']['callFrames'][0];
+ const location = callFrame['location'];
+ assert.strictEqual(url, session.scriptUrlForId(location['scriptId']));
+ assert.strictEqual(line, location['lineNumber']);
+ return true;
+ }
+ };
+}
+
+function setupExpectConsoleOutputAndBreak(type, values) {
+ if (!(values instanceof Array))
+ values = [ values ];
+ let consoleLog = false;
+ function matchConsoleLog(message) {
+ if ('Runtime.consoleAPICalled' === message['method']) {
+ const params = message['params'];
+ if (params['type'] === type) {
+ let i = 0;
+ for (const value of params['args']) {
+ if (value['value'] !== values[i++])
+ return false;
+ }
+ return i === values.length;
+ }
+ }
+ }
+
+ return function(message) {
+ if (consoleLog)
+ return message['method'] === 'Debugger.paused';
+ consoleLog = matchConsoleLog(message);
+ return false;
+ };
+}
+
+function setupExpectContextDestroyed(id) {
+ return function(message) {
+ if ('Runtime.executionContextDestroyed' === message['method'])
+ return message['params']['executionContextId'] === id;
+ };
+}
+
+function setupDebugger(session) {
+ console.log('[test]', 'Setting up a debugger');
+ const commands = [
+ { 'method': 'Runtime.enable' },
+ { 'method': 'Debugger.enable' },
+ { 'method': 'Debugger.setAsyncCallStackDepth',
+ 'params': {'maxDepth': 0} },
+ { 'method': 'Runtime.runIfWaitingForDebugger' },
+ ];
+
+ session
+ .sendInspectorCommands(commands)
+ .expectMessages((message) => 'Runtime.consoleAPICalled' === message.method);
+}
+
+function breakOnLine(session) {
+ console.log('[test]', 'Breaking in the code');
+ const commands = [
+ { 'method': 'Debugger.setBreakpointByUrl',
+ 'params': { 'lineNumber': 9,
+ 'url': script,
+ 'columnNumber': 0,
+ 'condition': ''
+ }
+ },
+ { 'method': 'Runtime.evaluate',
+ 'params': { 'expression': 'sum()',
+ 'objectGroup': 'console',
+ 'includeCommandLineAPI': true,
+ 'silent': false,
+ 'contextId': 1,
+ 'returnByValue': false,
+ 'generatePreview': true,
+ 'userGesture': true,
+ 'awaitPromise': false
+ }
+ }
+ ];
+ helper.markMessageNoResponse(commands[1]);
+ session
+ .sendInspectorCommands(commands)
+ .expectMessages(setupExpectBreakOnLine(9, script, session));
+}
+
+function stepOverConsoleStatement(session) {
+ console.log('[test]', 'Step over console statement and test output');
+ session
+ .sendInspectorCommands({ 'method': 'Debugger.stepOver' })
+ .expectMessages(setupExpectConsoleOutputAndBreak('log', [0, 3]));
+}
+
+function testWaitsForFrontendDisconnect(session, harness) {
+ console.log('[test]', 'Verify node waits for the frontend to disconnect');
+ session.sendInspectorCommands({ 'method': 'Debugger.resume'})
+ .expectMessages(setupExpectContextDestroyed(1))
+ .expectStderrOutput('Waiting for the debugger to disconnect...')
+ .disconnect(true);
+}
+
+function runTests(harness) {
+ harness
+ .runFrontendSession([
+ setupDebugger,
+ breakOnLine,
+ stepOverConsoleStatement,
+ testWaitsForFrontendDisconnect
+ ]).expectShutDown(0);
+}
+
+helper.startNodeForInspectorTest(runTests,
+ ['--inspect'],
+ undefined,
+ script);