Skip to content

Commit

Permalink
Merge branch 'pr-2680' into devel
Browse files Browse the repository at this point in the history
  • Loading branch information
n1mmy committed Sep 30, 2014
2 parents 381b2fa + 5a4d351 commit 46e7834
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 3 deletions.
13 changes: 13 additions & 0 deletions tools/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ main.registerCommand({
'raw-logs': { type: Boolean },
settings: { type: String },
program: { type: String },
test: {type: Boolean, default: false},
verbose: { type: Boolean, short: "v" },
// With --once, meteor does not re-run the project if it crashes
// and does not monitor for file changes. Intentionally
Expand Down Expand Up @@ -303,6 +304,18 @@ main.registerCommand({
if (options['raw-logs'])
runLog.setRawLogs(true);

// Velocity testing. Sets up a DDP connection to the app process and
// runs phantomjs.
//
// NOTE: this calls process.exit() when testing is done.
if (options['test']){
var serverUrl = "http://" + (parsedHostPort.host || "localhost") +
":" + parsedHostPort.port;
var velocity = require('./run-velocity.js');
velocity.runVelocity(serverUrl);
}


var runAll = require('./run-all.js');
return runAll.run(options.appDir, {
proxyPort: parsedHostPort.port,
Expand Down
7 changes: 4 additions & 3 deletions tools/help.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ Options:
to the host and port that the Meteor server binds to.
--production Simulate production mode. Minify and bundle CSS and JS files.
--raw-logs Run without parsing logs from stdout and stderr.
--settings Set optional data for Meteor.settings on the server
--release Specify the release of Meteor to use
--program The program in the app to run (Advanced)
--settings Set optional data for Meteor.settings on the server.
--release Specify the release of Meteor to use.
--program The program in the app to run (Advanced).
--verbose Print all output from builds logs.
--test [Experimental] Run Velocity tests using phantomjs and exit.


>>> create
Expand Down
134 changes: 134 additions & 0 deletions tools/run-velocity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
var Console = require('./console.js').Console;
var uniload = require('./uniload.js');

var phantomjs = require('phantomjs');
var child_process = require('child_process');
var _ = require('underscore');

// XXX this could really use a self-test!

// XXX would be nice be nice if this didn't have to be in core. Perhaps
// at some point we'll have an API for packages to register commands in
// the tool.

// 1. Establish a DDP connection to Meteor
// 2. Subscribe to the Velocity subscriptions that tell us
// which tests pass/fail and when all tests have completed.
// 3. Open the app server with PhantomJS to run client side tests.
// 4. Print the results and exit with the appropriate exit code.
var runVelocity = function (url) {
var unipackages = uniload.load({
packages: [ 'ddp']
});
var DDP = unipackages.ddp.DDP;

// XXX maybe a startup message so users know the tests are running.

var ddpConnection = DDP.connect(url);

var interval = setInterval(function () {
if (ddpConnection.status().status === "connected") {
clearInterval(interval);

ddpConnection.subscribe("VelocityTestReports", {
onError: function () {
Console.stderr.write("failed to subscribe to VelocityTestReports "
+ "subscription");
// XXX tell user to add velocity:core
// XXX these also fire if the user turns on autopublish
}, onReady: function () {
this.connection.registerStore("velocityTestReports", {
update: function (msg) {
if (msg.msg === "added") {
var testDesc = msg.fields.framework + " : " +
msg.fields.ancestors.join(":") + " => " + msg.fields.name;
if (msg.fields.result === "passed") {
console.log("PASSED", testDesc);
} else if (msg.fields.result === "failed") {
console.error("FAILED", testDesc);
console.log(msg.fields.failureStackTrace);
}
}
}
});
}
});

var reports = {};
function updateReport(msg) {
var report = reports[msg.id];
if (! report) {
reports[msg.id] = msg.fields;
} else {
_.extend(report, msg.fields);
}
}
var aggregateResult = null;
var isFinished = false;
ddpConnection.subscribe("VelocityAggregateReports", {
onError: function () {
Console.stderr.write("failed to subscribe to " +
"VelocityAggregateReports subscription");
}, onReady: function () {
this.connection.registerStore("velocityAggregateReports", {
update: function (msg) {
if (msg.msg === "added" || msg.msg === "changed") {
updateReport(msg);
var report = reports[msg.id];

if (report.name === "aggregateResult") {
aggregateResult = report.result;
}

if (report.name === "aggregateComplete" &&
report.result === "completed") {
setTimeout(function () {
if (aggregateResult === "passed") {
console.log("TESTS RAN SUCCESSFULLY");
// XXX XXX this is not great. We shouldn't be
// exiting from deep within code like this. Better
// would be to integrate with run --once, and
// signal the inner process to exit cleanly on
// test completion.
process.exit(0);
}
if (aggregateResult === "failed") {
console.log("FAILURE");
process.exit(1);
}
}, 2000);
}
}
}
});
}
});

function visitWithPhantom (url) {
var phantomScript = "require('webpage').create().open('" + url + "');";
child_process.execFile(
'/bin/bash',
['-c',
("exec " + phantomjs.path + " /dev/stdin <<'END'\n" +
phantomScript + "END\n")]);
}

ddpConnection.subscribe("VelocityMirrors", {
onError: function (err) {
Console.stderr.write("failed to subscribe to VelocityMirrors " +
"subscription", err);
}, onReady: function () {
this.connection.registerStore("velocityMirrors", {
update: function (msg) {
if (msg.msg === "added") {
visitWithPhantom(msg.fields.rootUrl);
}
}
});
}
});
}
}, 2000);
};

exports.runVelocity = runVelocity;

0 comments on commit 46e7834

Please sign in to comment.