|
|
|
'use strict';
|
|
|
|
const common = require('../common');
|
|
|
|
const assert = require('assert');
|
|
|
|
const debug = require('_debugger');
|
|
|
|
|
|
|
|
process.env.NODE_DEBUGGER_TIMEOUT = 2000;
|
|
|
|
const debugPort = common.PORT;
|
|
|
|
debug.port = debugPort;
|
|
|
|
const spawn = require('child_process').spawn;
|
|
|
|
|
|
|
|
setTimeout(function() {
|
|
|
|
if (nodeProcess) nodeProcess.kill('SIGTERM');
|
|
|
|
throw new Error('timeout');
|
|
|
|
}, 10000).unref();
|
|
|
|
|
|
|
|
|
|
|
|
let resCount = 0;
|
|
|
|
const p = new debug.Protocol();
|
|
|
|
p.onResponse = function() {
|
|
|
|
resCount++;
|
|
|
|
};
|
|
|
|
|
|
|
|
p.execute('Type: connect\r\n' +
|
|
|
|
'V8-Version: 3.0.4.1\r\n' +
|
|
|
|
'Protocol-Version: 1\r\n' +
|
|
|
|
'Embedding-Host: node v0.3.3-pre\r\n' +
|
|
|
|
'Content-Length: 0\r\n\r\n');
|
|
|
|
assert.strictEqual(resCount, 1);
|
|
|
|
|
|
|
|
// Make sure split messages go in.
|
|
|
|
|
|
|
|
const parts = [];
|
|
|
|
parts.push('Content-Length: 336\r\n');
|
|
|
|
assert.strictEqual(parts[0].length, 21);
|
|
|
|
parts.push('\r\n');
|
|
|
|
assert.strictEqual(parts[1].length, 2);
|
|
|
|
let bodyLength = 0;
|
|
|
|
|
|
|
|
parts.push('{"seq":12,"type":"event","event":"break","body":' +
|
|
|
|
'{"invocationText":"#<a Server>');
|
|
|
|
assert.strictEqual(parts[2].length, 78);
|
|
|
|
bodyLength += parts[2].length;
|
|
|
|
|
|
|
|
parts.push('.[anonymous](req=#<an IncomingMessage>, ' +
|
|
|
|
'res=#<a ServerResponse>)","sourceLine"');
|
|
|
|
assert.strictEqual(parts[3].length, 78);
|
|
|
|
bodyLength += parts[3].length;
|
|
|
|
|
|
|
|
parts.push(':45,"sourceColumn":4,"sourceLineText":" debugger;",' +
|
|
|
|
'"script":{"id":24,"name":"/home/ryan/projects/node/' +
|
|
|
|
'benchmark/http_simple.js","lineOffset":0,"columnOffset":0,' +
|
|
|
|
'"lineCount":98}}}');
|
|
|
|
assert.strictEqual(parts[4].length, 180);
|
|
|
|
bodyLength += parts[4].length;
|
|
|
|
|
|
|
|
assert.strictEqual(bodyLength, 336);
|
|
|
|
|
|
|
|
for (let i = 0; i < parts.length; i++) {
|
|
|
|
p.execute(parts[i]);
|
|
|
|
}
|
|
|
|
assert.strictEqual(resCount, 2);
|
|
|
|
|
|
|
|
|
|
|
|
// Make sure that if we get backed up, we still manage to get all the
|
|
|
|
// messages
|
|
|
|
const d = 'Content-Length: 466\r\n\r\n' +
|
|
|
|
'{"seq":10,"type":"event","event":"afterCompile","success":true,' +
|
|
|
|
'"body":{"script":{"handle":1,"type":"script","name":"dns.js",' +
|
|
|
|
'"id":34,"lineOffset":0,"columnOffset":0,"lineCount":241,' +
|
|
|
|
'"sourceStart":"(function(module, exports, require) {' +
|
|
|
|
'var dns = process.binding(\'cares\')' +
|
|
|
|
';\\nvar ne","sourceLength":6137,"scriptType":2,"compilationType"' +
|
|
|
|
':0,"context":{"ref":0},"text":"dns.js (lines: 241)"}},"refs":' +
|
|
|
|
'[{"handle":0' +
|
|
|
|
',"type":"context","text":"#<a ContextMirror>"}],"running":true}' +
|
|
|
|
'\r\n\r\nContent-Length: 119\r\n\r\n' +
|
|
|
|
'{"seq":11,"type":"event","event":"scriptCollected","success":true' +
|
|
|
|
',"body":{"script":{"id":26}},"refs":[],"running":true}';
|
|
|
|
p.execute(d);
|
|
|
|
assert.strictEqual(resCount, 4);
|
|
|
|
|
|
|
|
let expectedConnections = 0;
|
|
|
|
const tests = [];
|
|
|
|
function addTest(cb) {
|
|
|
|
expectedConnections++;
|
|
|
|
tests.push(cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
addTest(function(client, done) {
|
|
|
|
console.error('requesting version');
|
|
|
|
client.reqVersion(function(err, v) {
|
|
|
|
assert.ifError(err);
|
|
|
|
console.log('version: %s', v);
|
|
|
|
assert.strictEqual(process.versions.v8, v);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
addTest(function(client, done) {
|
|
|
|
console.error('requesting scripts');
|
|
|
|
client.reqScripts(function(err) {
|
|
|
|
assert.ifError(err);
|
|
|
|
console.error('got %d scripts', Object.keys(client.scripts).length);
|
|
|
|
|
|
|
|
let foundMainScript = false;
|
|
|
|
for (const k in client.scripts) {
|
|
|
|
const script = client.scripts[k];
|
|
|
|
if (script && script.name === 'bootstrap_node.js') {
|
|
|
|
foundMainScript = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert.ok(foundMainScript);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
addTest(function(client, done) {
|
|
|
|
console.error('eval 2+2');
|
|
|
|
client.reqEval('2+2', function(err, res) {
|
|
|
|
console.error(res);
|
|
|
|
assert.ifError(err);
|
|
|
|
assert.strictEqual(res.text, '4');
|
|
|
|
assert.strictEqual(res.value, 4);
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
let connectCount = 0;
|
|
|
|
const script = 'setTimeout(function() { console.log("blah"); });' +
|
|
|
|
'setInterval(function() {}, 1000000);';
|
|
|
|
|
|
|
|
let nodeProcess;
|
|
|
|
|
|
|
|
function doTest(cb, done) {
|
|
|
|
const args = ['--debug=' + debugPort, '-e', script];
|
|
|
|
nodeProcess = spawn(process.execPath, args);
|
|
|
|
|
|
|
|
nodeProcess.stdout.once('data', function() {
|
|
|
|
console.log('>>> new node process: %d', nodeProcess.pid);
|
|
|
|
let failed = true;
|
|
|
|
try {
|
|
|
|
process._debugProcess(nodeProcess.pid);
|
|
|
|
failed = false;
|
|
|
|
} finally {
|
|
|
|
// At least TRY not to leave zombie procs if this fails.
|
|
|
|
if (failed)
|
|
|
|
nodeProcess.kill('SIGTERM');
|
|
|
|
}
|
|
|
|
console.log('>>> starting debugger session');
|
|
|
|
});
|
|
|
|
|
|
|
|
let didTryConnect = false;
|
|
|
|
nodeProcess.stderr.setEncoding('utf8');
|
|
|
|
let b = '';
|
|
|
|
nodeProcess.stderr.on('data', function(data) {
|
|
|
|
console.error('got stderr data %j', data);
|
|
|
|
nodeProcess.stderr.resume();
|
|
|
|
b += data;
|
|
|
|
if (didTryConnect === false && b.match(/Debugger listening on /)) {
|
|
|
|
didTryConnect = true;
|
|
|
|
|
|
|
|
// The timeout is here to expose a race in the bootstrap process.
|
|
|
|
// Without the early SIGUSR1 debug handler, it effectively results
|
|
|
|
// in an infinite ECONNREFUSED loop.
|
|
|
|
setTimeout(tryConnect, 100);
|
|
|
|
|
|
|
|
function tryConnect() {
|
|
|
|
// Wait for some data before trying to connect
|
|
|
|
const c = new debug.Client();
|
|
|
|
console.error('>>> connecting...');
|
|
|
|
c.connect(debug.port);
|
|
|
|
c.on('break', function() {
|
|
|
|
c.reqContinue(function() {});
|
|
|
|
});
|
|
|
|
c.on('ready', function() {
|
|
|
|
connectCount++;
|
|
|
|
console.log('ready!');
|
|
|
|
cb(c, function() {
|
|
|
|
c.end();
|
|
|
|
c.on('end', function() {
|
|
|
|
console.error(
|
|
|
|
'>>> killing node process %d\n\n',
|
|
|
|
nodeProcess.pid);
|
|
|
|
nodeProcess.kill();
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
c.on('error', function(err) {
|
|
|
|
if (err.code !== 'ECONNREFUSED') throw err;
|
|
|
|
setTimeout(tryConnect, 10);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function run() {
|
|
|
|
const t = tests[0];
|
|
|
|
if (!t) return;
|
|
|
|
|
|
|
|
doTest(t, function() {
|
|
|
|
tests.shift();
|
|
|
|
run();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
run();
|
|
|
|
|
|
|
|
process.on('exit', function(code) {
|
|
|
|
if (!code)
|
|
|
|
assert.strictEqual(connectCount, expectedConnections);
|
|
|
|
});
|