Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add test debugging support #109

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ var root = __dirname + '/..',
args = argsparser.parse(),
testrunner = require(root),
o = testrunner.options,
code, tests,
code, tests, debug,
help;

help = ''
Expand All @@ -17,6 +17,7 @@ help = ''
+ '\nOptions:'
+ '\n -c, --code path to code you want to test'
+ '\n -t, --tests path to tests (space separated)'
+ '\n --debug debugging port'
+ '\n -d, --deps dependency paths - files required before code (space separated)'
+ '\n -l, --log logging options, json have to be used'
+ '\n --cov create tests coverage report'
Expand Down Expand Up @@ -65,6 +66,9 @@ for (var key in args) {
// of QUnit in browsers.
tests = args[key];
break;
case '--debug':
debug = args[key];
break;
case '-d':
case '--deps':
o.deps = args[key];
Expand Down Expand Up @@ -105,7 +109,11 @@ if(!code || !tests) {
return;
}

testrunner.run({ code: code, tests: tests, deps: o.deps, log: o.log }, function(err, stats) {
debug = debug || process.execArgv.reduce(function (prevArg, curArg) {
return prevArg || curArg.indexOf('--debug') === 0;
}, false);

testrunner.run({ code: code, tests: tests, deps: o.deps, log: o.log, debug: debug }, function(err, stats) {
if (err) {
console.error(err);
process.exit(1);
Expand Down
14 changes: 8 additions & 6 deletions lib/child.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ var options = JSON.parse(process.argv.pop()),
currentModule = path.basename(options.code.path, '.js'),
currentTest;

// send ping messages to when child is blocked.
// after I sent the first ping, testrunner will start to except the next ping
// within maxBlockDuration, otherwise this process will be killed
process.send({event: 'ping'});
setInterval(function() {
if(!options.debug) {
// send ping messages to when child is blocked.
// after I sent the first ping, testrunner will start to except the next ping
// within maxBlockDuration, otherwise this process will be killed
process.send({event: 'ping'});
}, Math.floor(options.maxBlockDuration / 2));
setInterval(function () {
process.send({event: 'ping'});
}, Math.floor(options.maxBlockDuration / 2));
}

process.on('uncaughtException', function(err) {
if (QUnit.config.current) {
Expand Down
93 changes: 57 additions & 36 deletions lib/testrunner.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var fs = require('fs'),
coverage = require('./coverage'),
cp = require('child_process'),
_ = require('underscore'),
freeport = require('freeport'),
log = exports.log = require('./log');

var options,
Expand Down Expand Up @@ -48,7 +49,10 @@ options = exports.options = {
namespace: null,

// max amount of ms child can be blocked, after that we assume running an infinite loop
maxBlockDuration: 2000
maxBlockDuration: 2000,

// port that should be used for debugging
debug: null
};

/**
Expand All @@ -60,9 +64,23 @@ function runOne(opts, callback) {
var child;
var pingCheckTimeoutId;
var argv = process.argv.slice();
var debug = opts.debug;

argv.push(JSON.stringify(opts));
child = cp.fork(__dirname + '/child.js', argv, {env: process.env});

if (debug) {
if (typeof debug === 'boolean') {
freeport(function (er, port) {
process.execArgv.push('--debug-brk=' + port);
fork();
});
} else {
process.execArgv.push('--debug-brk=' + debug);
fork();
}
} else {
fork();
}

function kill() {
process.removeListener('exit', kill);
Expand All @@ -75,40 +93,43 @@ function runOne(opts, callback) {
callback(err, data)
}

child.on('message', function(msg) {
switch (msg.event) {
case 'ping':
clearTimeout(pingCheckTimeoutId);
pingCheckTimeoutId = setTimeout(function() {
complete(new Error('Process blocked for too long'));
}, opts.maxBlockDuration);
break;
case 'assertionDone':
log.add('assertions', msg.data);
break;
case 'testDone':
log.add('tests', msg.data);
break;
case 'done':
clearTimeout(pingCheckTimeoutId);
msg.data.code = opts.code.path;
log.add('summaries', msg.data);
if (opts.coverage) {
coverage.add(msg.data.coverage);
msg.data.coverage = coverage.get();
msg.data.coverage.code = msg.data.code;
log.add('coverages', msg.data.coverage);
}
if (opts.log.testing) {
console.log('done');
}
complete(null, msg.data);
break;
case 'uncaughtException':
complete(_.extend(new Error(), msg.data));
break;
}
});
function fork() {
child = cp.fork(__dirname + '/child.js', argv, {env: process.env});
child.on('message', function (msg) {
switch (msg.event) {
case 'ping':
clearTimeout(pingCheckTimeoutId);
pingCheckTimeoutId = setTimeout(function () {
complete(new Error('Process blocked for too long'));
}, opts.maxBlockDuration);
break;
case 'assertionDone':
log.add('assertions', msg.data);
break;
case 'testDone':
log.add('tests', msg.data);
break;
case 'done':
clearTimeout(pingCheckTimeoutId);
msg.data.code = opts.code.path;
log.add('summaries', msg.data);
if (opts.coverage) {
coverage.add(msg.data.coverage);
msg.data.coverage = coverage.get();
msg.data.coverage.code = msg.data.code;
log.add('coverages', msg.data.coverage);
}
if (opts.log.testing) {
console.log('done');
}
complete(null, msg.data);
break;
case 'uncaughtException':
complete(_.extend(new Error(), msg.data));
break;
}
});
}

process.on('exit', kill);

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "qunit",
"description": "QUnit testing framework for nodejs",
"version": "0.7.5",
"version": "0.7.6",
"author": "Oleg Slobodskoi <[email protected]>",
"contributors": [
{
Expand Down Expand Up @@ -39,6 +39,7 @@
"argsparser": "^0.0.6",
"cli-table": "^0.3.0",
"co": "^3.0.6",
"freeport": "^1.0.3",
"qunitjs": "1.10.0",
"tracejs": "^0.1.8",
"underscore": "^1.6.0"
Expand Down