Skip to content
Prev Previous commit
Next Next commit
tests
  • Loading branch information
TimothyGu committed Jul 17, 2017
commit fe7c4a5a34a5b664521d36feaf1c6c597ba1e74b
121 changes: 121 additions & 0 deletions test/inspector/test-inspector-contexts-js.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
'use strict';
const common = require('../common');
const { fires, neverFires } = common;
common.skipIfInspectorDisabled();
const assert = require('assert');
const { Session, attachContext, detachContext } = require('inspector');
const { promisify } = require('util');
const { createContext } = require('vm');

common.crashOnUnhandledRejection();

const session = new Session();
const once = common.cancellableOnce.bind(session);
const post = promisify(session.post).bind(session);

async function main() {
session.connect();

// Basic tests.
{
const VM_CONTEXT_NAME = 'New VM Context';
const VM_CONTEXT_ORIGIN = 'https://nodejs.org/api/vm.html';

const sandbox = {
propInSandbox: 42
};
createContext(sandbox);

// Enable context tracking; receive info about default context.
{
const eventPromise = fires(once('Runtime.executionContextCreated'));
post('Runtime.enable');
const topContext = (await eventPromise).params.context;
assert.strictEqual(topContext.name, 'Node.js Main Context');
assert.strictEqual(topContext.origin, '');
assert.strictEqual(topContext.auxData.isDefault, true);
}

let vmContext;

// Attaching contextified sandbox.
{
const eventPromise = fires(once('Runtime.executionContextCreated'));
attachContext(sandbox, {
name: VM_CONTEXT_NAME,
origin: VM_CONTEXT_ORIGIN
});
vmContext = (await eventPromise).params.context;
assert.strictEqual(vmContext.name, VM_CONTEXT_NAME);
assert.strictEqual(vmContext.origin, VM_CONTEXT_ORIGIN);
assert.strictEqual(vmContext.auxData.isDefault, false);
}

// Evaluating expressions in the specified context.
{
const { result } = await post('Runtime.evaluate', {
expression: 'propInSandbox++',
contextId: vmContext.id
});
assert.strictEqual(result.type, 'number');
assert.strictEqual(result.value, 42);
assert.strictEqual(sandbox.propInSandbox, 43);
}

// Trying to attach the same context twice.
{
const eventPromise =
neverFires(once('Runtime.executionContextCreated'));
attachContext(sandbox, {
name: VM_CONTEXT_NAME,
origin: VM_CONTEXT_ORIGIN
});
await eventPromise;
}

// Detach context.
{
const eventPromise = fires(once('Runtime.executionContextDestroyed'));
detachContext(sandbox);
const destroyedId = (await eventPromise).params.executionContextId;
assert.strictEqual(destroyedId, vmContext.id);
}

// Trying to detach multiple times.
{
const eventPromise =
neverFires(once('Runtime.executionContextDestroyed'));
detachContext(sandbox);
await eventPromise;
}
}

// Default context names.
{
const contexts = [
createContext(),
createContext(),
createContext()
];
const ids = new Map();
for (const [i, context] of contexts.entries()) {
const eventPromise = fires(once('Runtime.executionContextCreated'));
attachContext(context);
const info = (await eventPromise).params.context;
assert.strictEqual(info.name, `vm Module Context ${i + 1}`);
assert.strictEqual(info.origin, '');
assert.strictEqual(info.auxData.isDefault, false);
ids.set(context, info.id);
}
for (const context of contexts) {
const eventPromise = fires(once('Runtime.executionContextDestroyed'));
detachContext(context);
const destroyedId = (await eventPromise).params.executionContextId;
assert.strictEqual(destroyedId, ids.get(context));
}
}

session.disconnect();
}

main();
159 changes: 159 additions & 0 deletions test/inspector/test-inspector-contexts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
'use strict';
const common = require('../common');
common.skipIfInspectorDisabled();
const assert = require('assert');
const helper = require('./inspector-helper.js');

const ROOT_CONTEXT_NAME = 'Node.js Main Context';
const ROOT_CONTEXT_ORIGIN = '';
const VM_CONTEXT_NAME = 'New VM Context';
const VM_CONTEXT_ORIGIN = 'https://nodejs.org/api/vm.html';

let topContextId;
let vmContextId;

function setupExpectContextCreation(idx) {
return (message) => {
if (message.method === 'Runtime.executionContextCreated') {
const { context } = message.params;
assert.strictEqual(typeof context.id, 'number');
if (idx === 0) {
topContextId = context.id;
assert.strictEqual(context.name, ROOT_CONTEXT_NAME);
assert.strictEqual(context.origin, ROOT_CONTEXT_ORIGIN);
assert.strictEqual(context.auxData.isDefault, true);
} else {
vmContextId = context.id;
assert.strictEqual(context.name, VM_CONTEXT_NAME);
assert.strictEqual(context.origin, VM_CONTEXT_ORIGIN);
assert.strictEqual(context.auxData.isDefault, false);
}
return true;
}
};
}

function setupExpectBreakInContext(functionName) {
return (message) => {
if (message.method === 'Debugger.paused') {
if (functionName) {
const callFrame = message.params.callFrames[0];
assert.strictEqual(callFrame.functionName, functionName);
}
return true;
}
};
}

function setupExpectContextDestroyed(idx) {
return (message) => {
if (message.method === 'Runtime.executionContextDestroyed') {
const { executionContextId } = message.params;
assert.strictEqual(executionContextId,
idx === 0 ? topContextId : vmContextId);
return true;
}
};
}

function testBreakpointInContext(session) {
console.log('[test]',
'Verifying debugger stops on start (--inspect-brk option)');
const commands = [
{ 'method': 'Runtime.enable' },
{ 'method': 'Debugger.enable' },
{ 'method': 'Runtime.runIfWaitingForDebugger' },
];
const messages = [
setupExpectContextCreation(0),
setupExpectContextCreation(1),
setupExpectBreakInContext('testfn'),
];
session
.sendInspectorCommands(commands)
.expectMessages(messages);
}

function resume(session) {
console.log('[test]', 'Resuming and waiting for pause');
session
.sendInspectorCommands({ 'method': 'Debugger.resume' })
.expectMessages(setupExpectBreakInContext());
}

function testEvaluateInContext(session) {
console.log('[test]', 'Evaluate in VM context');
session.sendInspectorCommands([
[
{ method: 'Runtime.evaluate',
params: { expression: 'propInSandbox++',
contextId: vmContextId } },
({ result }) => {
assert.strictEqual(result.type, 'number');
assert.strictEqual(result.value, 42);
}
],
[
{ method: 'Runtime.evaluate',
params: { expression: 'sandbox.propInSandbox' } },
({ result }) => {
assert.strictEqual(result.type, 'number');
assert.strictEqual(result.value, 43);
}
]
]);
}

function testDetachContext(session) {
console.log('[test]', 'Verify V8 acknowledges context detachment');
session
.sendInspectorCommands({ 'method': 'Debugger.resume' })
.expectMessages([
setupExpectContextDestroyed(1),
setupExpectBreakInContext()
]);
}

function resumeAndTerminate(session) {
session
.sendInspectorCommands({ 'method': 'Debugger.resume'})
.disconnect(true);
}

function runTests(harness) {
harness
.runFrontendSession([
testBreakpointInContext,
resume,
testEvaluateInContext,
testDetachContext,
resumeAndTerminate
]).expectShutDown(0);
}

const script = `
'use strict';
const { attachContext, detachContext } = require('inspector');
const { createContext, runInContext } = require('vm');

const sandbox = {
propInSandbox: 42
};
createContext(sandbox);

attachContext(sandbox, {
name: ${JSON.stringify(VM_CONTEXT_NAME)},
origin: ${JSON.stringify(VM_CONTEXT_ORIGIN)}
});
runInContext(\`
function testfn() {
debugger;
}
testfn();
\`, sandbox);
debugger;
detachContext(sandbox);
debugger;
`;

helper.startNodeForInspectorTest(runTests, '--inspect-brk', script);