Skip to content

Commit

Permalink
Clean up run.js with highland and stream-bifurcate dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
bterlson committed Nov 3, 2014
1 parent c2766c2 commit 19478c1
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 139 deletions.
199 changes: 82 additions & 117 deletions bin/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,6 @@
// Copyright (C) 2014, Microsoft Corporation. All rights reserved.
// This code is governed by the BSD License found in the LICENSE file.

var parser = require('test262-parser');
var tapify = require('../lib/tapify');
var simpleReporter = require('../lib/simpleReporter.js');
var glob = require('glob');
var through = require('through');
var fs = require('fs');
var jss = require('JSONStream').stringify();
var scenarios = require('../lib/scenarios');

var args = require('minimist')(process.argv.slice(2), {
default: {
runner: 'node',
Expand All @@ -28,68 +19,49 @@ var args = require('minimist')(process.argv.slice(2), {
}
});

var parser = require('test262-parser');
var tapify = require('../lib/tapify');
var simpleReporter = require('../lib/simpleReporter.js');
var _ = require('highland');
var glob = require('glob');
var fs = require('fs');
var path = require('path');
var jss = require('JSONStream').stringify();
var Tributary = require('stream-bifurcate')

var scenarios = require('../lib/scenarios');
var readFile = _.wrapCallback(fs.readFile);
var DEFAULT_BATCH_SIZE = 75;
var Runner = loadRunner();

// default to console runner if passing console command
if(args.consoleCommand && args.runner === 'node') {
args.runner = 'console';
}

// Try to create our runner
var Runner;
try {
Runner = require('../lib/runners/' + args.runner);
} catch(e) {
if(e.code === 'MODULE_NOT_FOUND') throw new Error('Runner ' + args.runner + ' not found.');
throw e;
}

var runner = new Runner(args);

// Run tests
var results = parser
.pipe(through(flatMap(scenarios(args))));

if(args.batch) {
results = results
.pipe(batch(args.batch))
.pipe(throughThreaded(runBatch, args.threads));
} else {
results = results
.pipe(throughThreaded(runTest, args.threads));
}

function batch(size) {
var currentBatch = [];

return through(function(data) {
currentBatch.push(data);
// apply default batch size
if(args.batch === true) args.batch = DEFAULT_BATCH_SIZE;

if(currentBatch.length === size) {
this.queue(currentBatch);
currentBatch = [];
}
}, function(done) {
this.queue(currentBatch);
this.queue(null);
});
}

function runTest(test, done) {
var stream = this;
runner.run(test, function() {
stream.queue(test);
done();
});
}
var start = Date.now();

function runBatch(batch, done) {
var stream = this;
runner.runBatch(batch, function() {
batch.forEach(stream.queue);
done();
});
}
var files = _(args._.map(globStream)).merge();
var contents = files.fork().map(readFile).sequence();
var tests = contents.zip(files.fork()).map(function(d) {
return parser.parseFile({ contents: d[0].toString('utf8'), file: d[1]});
});
var getScenarios = scenarios(args);
var scenarios = tests.flatMap(scenarioStream);
if(args.batch) scenarios = _(scenarios).batch(args.batch);

var trb = scenarios.pipe(new Tributary());
var results = _(function(push) {
for(var i = 0; i < args.threads; i++) push(null, run(trb.fork()));
push(null, _.nil);
}).merge();

results.on('end', function() {
console.log("Took " + ((Date.now() - start) / 1000) + " seconds");
})

if(args.reporter === 'json') {
results.pipe(jss).pipe(process.stdout);
Expand All @@ -99,67 +71,60 @@ if(args.reporter === 'json') {
results.pipe(simpleReporter);
}

// Make sure unnamed args are processed as glob patterns, even though unix-based
// system will auto-expand glob pattern args.
var files = args._.reduce(function (files, pattern) {
return files.concat(glob.sync(pattern));
}, []);

processFiles(files);

function processFiles(files) {
var index = -1;

function nextFile() {
index++;
if(index < files.length) {
processFile(files[index], nextFile);
} else {
parser.end();
}
}

nextFile();

function processFile(file, cb) {
fs.readFile(file, 'utf8', function(err, contents) {
parser.write({file: file, contents: contents});
cb();
// takes a test collateral stream.
// Returns test results stream.
function run(tests) {
var runner = new Runner(args);

return _(tests).map(function(test) {
return _(function(push) {
if(args.batch) {
runner.runBatch(test, function() {
test.forEach(function(t) {
push(null, t);
})
push(null, _.nil);
});
} else {
runner.run(test, function() {
push(null, test);
push(null, _.nil);
});
}
});
}
}).sequence();
}

function flatMap(iterFn) {
return function (test) {
var iter = iterFn(test);
var val = iter.next();
// takes a file path and returns a stream of filenames
// that match it
function globStream(p) {
var mg = glob(p);
var source = _('match', mg);
mg.on('end', function() { source.end() })

while(!val.done) {
this.queue(val.value);
val = iter.next();
}
}
return source;
}

function throughThreaded(cb, threads) {
var pending = 0;
var done = false;

return through(function(data) {
var that = this;
pending++;

if(pending >= threads) that.pause();

cb.call(this, data, function() {
pending--;
if(done && pending === 0) that.queue(null);
if(pending < threads && that.paused) that.resume();
});
}, function() {
done = true;
if(pending === 0) {
this.queue(null);
// takes a test and returns a stream of all the scenarios
function scenarioStream(test) {
var iter = getScenarios(test);
return _(function(push) {
var rec = iter.next();
while(!rec.done) {
push(null, rec.value);
rec = iter.next();
}

push(null, _.nil);
})
}

// Load the runner
function loadRunner() {
try {
return require('../lib/runners/' + args.runner);
} catch(e) {
if(e.code === 'MODULE_NOT_FOUND') throw new Error('Runner ' + args.runner + ' not found.');
throw e;
}
}
4 changes: 3 additions & 1 deletion lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,5 +150,7 @@ Runner.prototype.runBatch = function(batch, done) {

Runner.prototype.run = function(test, done) {
this.compile(test);
this.execute(test, done);
this.execute(test, function() {
done(null, test);
});
}
20 changes: 0 additions & 20 deletions lib/runners/jsshell.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,14 @@ module.exports = JSShellRunner;

var fs = require('fs');
var cp = require('child_process');
var through = require('through');
var ConsoleRunner = require('./console');
var DEFAULT_BATCH_SIZE = 75;
var counter = 0;

function lineSplitter() {
var splitLines = through(function(data) {
this.buffer += data;
var lines = this.buffer.split(/\r?\n/);
this.buffer = lines.pop();

lines.forEach(function(line) { this.queue(line)}, this);
}, function() {
this.queue(this.buffer);
})

splitLines.buffer = "";

return splitLines;
}

function JSShellRunner(args) {
args.consolePrintCommand = args.consolePrintCommand || "print";

ConsoleRunner.apply(this, arguments);

if(args.batch === true) args.batch = DEFAULT_BATCH_SIZE;

if(args.batch) {
this.batchTestStart =
'var env = newGlobal();\n' +
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"minimist": "^0.2.0",
"tap": "~0.4.11",
"test262-parser": "^1.0.2",
"through": "~2.3.4"
"through": "~2.3.4",
"stream-bifurcate": "^1.0.0"
},
"author": "Brian Terlson",
"license": "BSD"
Expand Down

0 comments on commit 19478c1

Please sign in to comment.