Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
inspector: rewrite inspector test helper
Browse files Browse the repository at this point in the history
Helper was rewritten to rely on promises instead of manually written
queue and callbacks. This simplifies the code and makes it easier to
maintain and extend.

PR-URL: #14797
Reviewed-By: Timothy Gu <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Eugene Ostroukhov authored and MylesBorins committed Sep 10, 2017

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent 3f44989 commit cf195cc
Showing 22 changed files with 868 additions and 1,119 deletions.
9 changes: 9 additions & 0 deletions test/common/README.md
Original file line number Diff line number Diff line change
@@ -99,6 +99,15 @@ Tests whether `name` and `expected` are part of a raised warning.

Checks if `pathname` exists

### fires(promise, [error], [timeoutMs])
* promise [&lt;Promise]
* error [&lt;String] default = 'timeout'
* timeoutMs [&lt;Number] default = 100

Returns a new promise that will propagate `promise` resolution or rejection if
that happens within the `timeoutMs` timespan, or rejects with `error` as
a reason otherwise.

### fixturesDir
* return [&lt;String>]

42 changes: 42 additions & 0 deletions test/common/index.js
Original file line number Diff line number Diff line change
@@ -819,6 +819,32 @@ function restoreWritable(name) {
delete process[name].writeTimes;
}

function onResolvedOrRejected(promise, callback) {
return promise.then((result) => {
callback();
return result;
}, (error) => {
callback();
throw error;
});
}

function timeoutPromise(error, timeoutMs) {
let clearCallback = null;
let done = false;
const promise = onResolvedOrRejected(new Promise((resolve, reject) => {
const timeout = setTimeout(() => reject(error), timeoutMs);
clearCallback = () => {
if (done)
return;
clearTimeout(timeout);
resolve();
};
}), () => done = true);
promise.clear = clearCallback;
return promise;
}

exports.hijackStdout = hijackStdWritable.bind(null, 'stdout');
exports.hijackStderr = hijackStdWritable.bind(null, 'stderr');
exports.restoreStdout = restoreWritable.bind(null, 'stdout');
@@ -832,3 +858,19 @@ exports.firstInvalidFD = function firstInvalidFD() {
} catch (e) {}
return fd;
};

exports.fires = function fires(promise, error, timeoutMs) {
if (!timeoutMs && util.isNumber(error)) {
timeoutMs = error;
error = null;
}
if (!error)
error = 'timeout';
if (!timeoutMs)
timeoutMs = 100;
const timeout = timeoutPromise(error, timeoutMs);
return Promise.race([
onResolvedOrRejected(promise, () => timeout.clear()),
timeout
]);
};
771 changes: 313 additions & 458 deletions test/inspector/inspector-helper.js

Large diffs are not rendered by default.

68 changes: 68 additions & 0 deletions test/inspector/test-break-when-eval.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const assert = require('assert');
const { NodeInstance } = require('./inspector-helper.js');
const path = require('path');

const script = path.join(path.dirname(module.filename), 'global-function.js');

async 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.send(commands);
await session.waitForNotification('Runtime.consoleAPICalled');
}

async 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
}
}
];
session.send(commands);
await session.waitForBreakOnLine(9, script);
}

async function stepOverConsoleStatement(session) {
console.log('[test]', 'Step over console statement and test output');
session.send({ 'method': 'Debugger.stepOver' });
await session.waitForConsoleOutput('log', [0, 3]);
await session.waitForNotification('Debugger.paused');
}

async function runTests() {
const child = new NodeInstance(['--inspect=0'], undefined, script);
const session = await child.connectInspectorSession();
await setupDebugger(session);
await breakOnLine(session);
await stepOverConsoleStatement(session);
await session.runToCompletion();
assert.strictEqual(0, (await child.expectShutdown()).exitCode);
}

common.crashOnUnhandledRejection();
runTests();
41 changes: 41 additions & 0 deletions test/inspector/test-debug-brk-flag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
'use strict';
const common = require('../common');

common.skipIfInspectorDisabled();

const assert = require('assert');
const { mainScriptPath,
NodeInstance } = require('./inspector-helper.js');

async function testBreakpointOnStart(session) {
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' }
];

session.send(commands);
await session.waitForBreakOnLine(0, mainScriptPath);
}

async function runTests() {
const child = new NodeInstance(['--inspect', '--debug-brk']);
const session = await child.connectInspectorSession();

await testBreakpointOnStart(session);
await session.runToCompletion();

assert.strictEqual(55, (await child.expectShutdown()).exitCode);
}

common.crashOnUnhandledRejection();
runTests();
46 changes: 46 additions & 0 deletions test/inspector/test-debug-end.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const { strictEqual } = require('assert');
const { NodeInstance } = require('./inspector-helper.js');

async function testNoServerNoCrash() {
console.log('Test there\'s no crash stopping server that was not started');
const instance = new NodeInstance([],
`process._debugEnd();
process.exit(42);`);
strictEqual(42, (await instance.expectShutdown()).exitCode);
}

async function testNoSessionNoCrash() {
console.log('Test there\'s no crash stopping server without connecting');
const instance = new NodeInstance('--inspect=0',
'process._debugEnd();process.exit(42);');
strictEqual(42, (await instance.expectShutdown()).exitCode);
}

async function testSessionNoCrash() {
console.log('Test there\'s no crash stopping server after connecting');
const script = `process._debugEnd();
process._debugProcess(process.pid);
setTimeout(() => {
console.log("Done");
process.exit(42);
});`;

const instance = new NodeInstance('--inspect-brk=0', script);
const session = await instance.connectInspectorSession();
await session.send({ 'method': 'Runtime.runIfWaitingForDebugger' });
await session.waitForServerDisconnect();
strictEqual(42, (await instance.expectShutdown()).exitCode);
}

async function runTest() {
await testNoServerNoCrash();
await testNoSessionNoCrash();
await testSessionNoCrash();
}

common.crashOnUnhandledRejection();

runTest();
45 changes: 45 additions & 0 deletions test/inspector/test-exception.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';
const common = require('../common');

common.skipIfInspectorDisabled();

const assert = require('assert');
const { NodeInstance } = require('./inspector-helper.js');
const path = require('path');

const script = path.join(common.fixturesDir, 'throws_error.js');

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, script);
}


async function runTest() {
const child = new NodeInstance(undefined, undefined, script);
const session = await child.connectInspectorSession();
await testBreakpointOnStart(session);
await session.runToCompletion();
assert.strictEqual(1, (await child.expectShutdown()).exitCode);
}

common.crashOnUnhandledRejection();

runTest();
128 changes: 0 additions & 128 deletions test/inspector/test-inspector-break-when-eval.js

This file was deleted.

59 changes: 0 additions & 59 deletions test/inspector/test-inspector-debug-brk.js

This file was deleted.

64 changes: 0 additions & 64 deletions test/inspector/test-inspector-exception.js

This file was deleted.

51 changes: 0 additions & 51 deletions test/inspector/test-inspector-ip-detection.js

This file was deleted.

21 changes: 0 additions & 21 deletions test/inspector/test-inspector-stop-profile-after-done.js

This file was deleted.

501 changes: 212 additions & 289 deletions test/inspector/test-inspector.js

Large diffs are not rendered by default.

48 changes: 48 additions & 0 deletions test/inspector/test-ip-detection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
'use strict';
const common = require('../common');

common.skipIfInspectorDisabled();

const assert = require('assert');
const { NodeInstance } = require('./inspector-helper.js');
const os = require('os');

const ip = pickIPv4Address();

if (!ip)
common.skip('No IP address found');

function checkIpAddress(ip, response) {
const res = response[0];
const wsUrl = res['webSocketDebuggerUrl'];
assert.ok(wsUrl);
const match = wsUrl.match(/^ws:\/\/(.*):\d+\/(.*)/);
assert.strictEqual(ip, match[1]);
assert.strictEqual(res['id'], match[2]);
assert.strictEqual(ip, res['devtoolsFrontendUrl'].match(/.*ws=(.*):\d+/)[1]);
}

function pickIPv4Address() {
for (const i of [].concat(...Object.values(os.networkInterfaces()))) {
if (i.family === 'IPv4' && i.address !== '127.0.0.1')
return i.address;
}
}

async function test() {
const instance = new NodeInstance('--inspect-brk=0.0.0.0:0');
try {
checkIpAddress(ip, await instance.httpGet(ip, '/json/list'));
} catch (error) {
if (error.code === 'EHOSTUNREACH') {
common.printSkipMessage('Unable to connect to self');
} else {
throw error;
}
}
instance.kill();
}

common.crashOnUnhandledRejection();

test();
28 changes: 14 additions & 14 deletions test/inspector/test-not-blocked-on-idle.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const helper = require('./inspector-helper.js');
const { NodeInstance } = require('./inspector-helper.js');

function shouldShutDown(session) {
session
.sendInspectorCommands([
{ 'method': 'Debugger.enable' },
{ 'method': 'Debugger.pause' },
])
.disconnect(true);
}

function runTests(harness) {
async function runTests() {
const script = 'setInterval(() => {debugger;}, 60000);';
const node = new NodeInstance('--inspect=0', script);
// 1 second wait to make sure the inferior began running the script
setTimeout(() => harness.runFrontendSession([shouldShutDown]).kill(), 1000);
await new Promise((resolve) => setTimeout(() => resolve(), 1000));
const session = await node.connectInspectorSession();
await session.send([
{ 'method': 'Debugger.enable' },
{ 'method': 'Debugger.pause' }
]);
session.disconnect();
node.kill();
}

const script = 'setInterval(() => {debugger;}, 60000);';
helper.startNodeForInspectorTest(runTests, '--inspect', script);
common.crashOnUnhandledRejection();
runTests();
11 changes: 0 additions & 11 deletions test/inspector/test-off-no-session.js

This file was deleted.

24 changes: 0 additions & 24 deletions test/inspector/test-off-with-session-then-on.js

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
30 changes: 30 additions & 0 deletions test/inspector/test-stop-profile-after-done.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const assert = require('assert');
const { NodeInstance } = require('./inspector-helper.js');

async function runTests() {
const child = new NodeInstance(['--inspect=0'],
`let c = 0;
const interval = setInterval(() => {
console.log(new Object());
if (c++ === 10)
clearInterval(interval);
}, 10);`);
const session = await child.connectInspectorSession();

session.send([
{ 'method': 'Profiler.setSamplingInterval', 'params': { 'interval': 100 } },
{ 'method': 'Profiler.enable' },
{ 'method': 'Runtime.runIfWaitingForDebugger' },
{ 'method': 'Profiler.start' }]);
while (await child.nextStderrString() !==
'Waiting for the debugger to disconnect...');
await session.send({ 'method': 'Profiler.stop' });
session.disconnect();
assert.strictEqual(0, (await child.expectShutdown()).exitCode);
}

common.crashOnUnhandledRejection();
runTests();
File renamed without changes.

0 comments on commit cf195cc

Please sign in to comment.