From 0f4f77f8a20f34a035cfd2bce57041bfe170877f Mon Sep 17 00:00:00 2001 From: David Greenspan Date: Mon, 29 Sep 2014 12:10:11 -0700 Subject: [PATCH 01/15] Fix #2627 (source maps with a PATH_PREFIX) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When you set ROOT_URL_PATH_PREFIX, source maps are not found because the server serves them at a different path from where the client looks for them. I don’t understand this code super well, but based on what’s reported in issue #2627, the new code seems strictly more correct than the old code. --- packages/webapp/webapp_server.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/webapp/webapp_server.js b/packages/webapp/webapp_server.js index 41f1128fb7..d80665c872 100644 --- a/packages/webapp/webapp_server.js +++ b/packages/webapp/webapp_server.js @@ -424,8 +424,11 @@ WebAppInternals.staticFilesMiddleware = function (staticFiles, req, res, next) { // // You may also need to enable source maps in Chrome: open dev tools, click // the gear in the bottom right corner, and select "enable source maps". - if (info.sourceMapUrl) - res.setHeader('X-SourceMap', info.sourceMapUrl); + if (info.sourceMapUrl) { + res.setHeader('X-SourceMap', + __meteor_runtime_config__.ROOT_URL_PATH_PREFIX + + info.sourceMapUrl); + } if (info.type === "js") { res.setHeader("Content-Type", "application/javascript; charset=UTF-8"); From 3a08be805548b43d69a8675c3f1d1859649ee40a Mon Sep 17 00:00:00 2001 From: Adam Monsen Date: Tue, 23 Sep 2014 15:43:33 -0700 Subject: [PATCH 02/15] api doc: add a working showdown (Markdown) example I couldn't figure out an easy way to include a Spacebars operator like {{#markdown}} in a Markdown code block, hence the {{#... trickery. I think I can clean this up a little with the {{dstache}} template helper, though. See next commit. --- docs/client/packages/showdown.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/client/packages/showdown.html b/docs/client/packages/showdown.html index 26aa44a2b8..876e799049 100644 --- a/docs/client/packages/showdown.html +++ b/docs/client/packages/showdown.html @@ -11,7 +11,13 @@ tags. You can still use all of the usual Meteor template features inside a Markdown block, such as `{{dstache}}#each}}`, and you still get reactivity. - +Example: + +{{#markdown}}`I am using __markdown__.`{{/markdown}} + +outputs + +

I am using markdown.

{{/markdown}} From 4f13b2b89b7fdae8b0e37fb86fb909f89bb42c02 Mon Sep 17 00:00:00 2001 From: Adam Monsen Date: Tue, 23 Sep 2014 15:51:06 -0700 Subject: [PATCH 03/15] api doc: use {{dstache}} template helper Less/cleaner source code. --- docs/client/packages/showdown.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/client/packages/showdown.html b/docs/client/packages/showdown.html index 876e799049..34e2b45e4e 100644 --- a/docs/client/packages/showdown.html +++ b/docs/client/packages/showdown.html @@ -5,15 +5,14 @@ This package lets you use Markdown in your templates. It's easy: just -put your markdown inside -{{#markdown}} ... {{/markdown}} +put your markdown inside `{{dstache}}#markdown}} ... {{dstache}}/markdown}}` tags. You can still use all of the usual Meteor template features inside a Markdown block, such as `{{dstache}}#each}}`, and you still get reactivity. Example: -{{#markdown}}`I am using __markdown__.`{{/markdown}} +`{{dstache}}#markdown}}I am using __markdown__.{{dstache}}/markdown}}` outputs From b7b9a530389afbf90295f3361d15c5393f305c73 Mon Sep 17 00:00:00 2001 From: Rick Golden Date: Wed, 24 Sep 2014 16:33:58 -0700 Subject: [PATCH 04/15] fix typo (use of & vs. &&) --- packages/tinytest/tinytest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tinytest/tinytest.js b/packages/tinytest/tinytest.js index b4992a4075..1423f4c2bf 100644 --- a/packages/tinytest/tinytest.js +++ b/packages/tinytest/tinytest.js @@ -522,7 +522,7 @@ _.extend(TestRun.prototype, { }, stop_at_offset); // Wait for the test to complete or time out. future.wait(); - onComplete & onComplete(); + onComplete && onComplete(); }); } else { // client From 5b2c7e6ddc8111b172f93c748c1e6427dc8f5101 Mon Sep 17 00:00:00 2001 From: Mitar Date: Wed, 24 Sep 2014 21:56:56 -0700 Subject: [PATCH 05/15] Template.created has now more use. --- docs/client/api.html | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/client/api.html b/docs/client/api.html index 9743eb8151..318a450bd7 100644 --- a/docs/client/api.html +++ b/docs/client/api.html @@ -2254,12 +2254,8 @@ This callback fires once and is the first callback to fire. Every `created` callback with a certain template instance object in `this`, you will eventually get a `destroyed` callback for the same object. -{{#note}} - The `created` callback is not currently very useful. In a later release, the - template instance object (or something like it) will be visible from helper - functions, and `created` will be a useful way to set up values that are read - from helpers. For now, you probably just want to use `rendered`. -{{/note}} +`created` is a useful way to set up values on template instance that are +read from template helpers using `Template.instance()`. {{> autoApiBox "Template#destroyed"}} From a272d3c6e9c5579764adb36c6b0d85f626977ce7 Mon Sep 17 00:00:00 2001 From: Richard Guan Date: Sat, 27 Sep 2014 23:33:11 -0700 Subject: [PATCH 06/15] Missing a period(.) in this one sentence Entire document has sentences ending in periods except for this one (including the ones ending in quotes). --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df1861c3e8..3f6bb3216b 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ the app: ../meteor You'll then be able to read the docs locally in your browser at -`http://localhost:3000/` +`http://localhost:3000/`. Note that if you run Meteor from a git checkout, you cannot pin apps to specific Meteor releases or run using different Meteor releases using `--release`. From 22d48ee0db4911ce60b98dbf0d0ba552b09599e8 Mon Sep 17 00:00:00 2001 From: rissem Date: Wed, 24 Sep 2014 18:24:33 -0700 Subject: [PATCH 07/15] add --test flag to Meteor CLI for velociy CI support - establish a DDP connection to Meteor - subscribe to test results - hit running web server - exit with appropriate status code after tests have completed --- tools/commands.js | 120 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/tools/commands.js b/tools/commands.js index d1895df568..894c013d54 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -25,6 +25,9 @@ var cordova = require('./commands-cordova.js'); var commandsPackages = require('./commands-packages.js'); var execFileSync = require('./utils.js').execFileSync; var Console = require('./console.js').Console; +var uniload = require('./uniload.js'); +var phantomjs = require('phantomjs'); +var child_process = require('child_process'); // The architecture used by Galaxy servers; it's the architecture used // by 'meteor deploy'. @@ -164,6 +167,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 @@ -303,6 +307,122 @@ main.registerCommand({ if (options['raw-logs']) runLog.setRawLogs(true); + // If `--test` is specified we need to start the app server, poke + // it with PhantomJS, and listen for test results. + // + // More specifically: + // 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. Poke an app server with PhantomJS to run client side tests. + // 4. Print the results and exit with the appropriate exit code. + if (options['test']){ + var unipackages = uniload.load({ + packages: [ 'ddp'] + }); + var DDP = unipackages.ddp.DDP; + + var ddpConnection = DDP.connect("http://localhost:3000"); + + 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"); + }, 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 :-)") + //better way to exit here? + 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); + } + var runAll = require('./run-all.js'); return runAll.run(options.appDir, { proxyPort: parsedHostPort.port, From 251763f2eb3bad06a55fc774525d25d59242c2a9 Mon Sep 17 00:00:00 2001 From: rissem Date: Fri, 26 Sep 2014 11:01:47 -0700 Subject: [PATCH 08/15] clean up velocity --test pull request - remove hardcoded localhost:3000 - add documentation to command - remove emoji --- tools/commands.js | 13 ++++++++----- tools/help.txt | 1 + 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/commands.js b/tools/commands.js index 894c013d54..6b5dab658f 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -322,7 +322,10 @@ main.registerCommand({ }); var DDP = unipackages.ddp.DDP; - var ddpConnection = DDP.connect("http://localhost:3000"); + var hostPort = parseHostPort(options.port); + var serverUrl = "http://" + (hostPort.host || "localhost") + + ":" + hostPort.port; + var ddpConnection = DDP.connect(serverUrl); var interval = setInterval(function(){ if (ddpConnection.status().status === "connected"){ @@ -339,9 +342,9 @@ main.registerCommand({ var testDesc = msg.fields.framework + " : " + msg.fields.ancestors.join(":") + " => " + msg.fields.name; if(msg.fields.result == "passed"){ - console.log("PASSED ", testDesc); + console.log("PASSED", testDesc); } else if (msg.fields.result == "failed"){ - console.error("FAILED ", testDesc); + console.error("FAILED", testDesc); console.log(msg.fields.failureStackTrace) } } @@ -380,12 +383,12 @@ main.registerCommand({ report.result === "completed"){ setTimeout(function(){ if (aggregateResult === "passed"){ - console.log("TESTS RAN SUCCESSFULLY :-)") + console.log("TESTS RAN SUCCESSFULLY") //better way to exit here? process.exit(0); } if (aggregateResult === "failed"){ - console.log("FAILURE :-("); + console.log("FAILURE"); process.exit(1); } }, 2000); diff --git a/tools/help.txt b/tools/help.txt index ace2248c91..5de0546e61 100644 --- a/tools/help.txt +++ b/tools/help.txt @@ -50,6 +50,7 @@ Options: --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) + --test Run velocity tests (using phantomjs if necessary) and exit --verbose Print all output from builds logs. From 8e2b5612a9d1c4d745dbf7a3bded43a27cc6fd2e Mon Sep 17 00:00:00 2001 From: Paolo Scanferla Date: Mon, 22 Sep 2014 22:08:38 +0200 Subject: [PATCH 09/15] Export same-origin check and `end_of_redirect_response` template. Export some properties to allow developers to override them to support logging in using the OAuth redirect flow from cross origin domain. --- packages/oauth/oauth_server.js | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/oauth/oauth_server.js b/packages/oauth/oauth_server.js index ac3dff10ad..f5cc5d592e 100644 --- a/packages/oauth/oauth_server.js +++ b/packages/oauth/oauth_server.js @@ -122,6 +122,21 @@ OAuth._isCordovaFromQuery = function (query) { } }; +// Checks if the `redirectUrl` matches the app host. +// We export this function so that developers can override this +// behavior to allow apps from external domains to login using the +// redirect OAuth flow. +OAuth._checkRedirectUrlOrigin = function (redirectUrl) { + var appHost = Meteor.absoluteUrl(); + var appHostReplacedLocalhost = Meteor.absoluteUrl(undefined, { + replaceLocalhost: true + }); + return ( + redirectUrl.substr(0, appHost.length) !== appHost && + redirectUrl.substr(0, appHostReplacedLocalhost.length) !== appHostReplacedLocalhost + ); +}; + // Listen to incoming OAuth http requests WebApp.connectHandlers.use(function(req, res, next) { @@ -274,7 +289,7 @@ OAuth._renderOauthResults = function(res, query, credentialSecret) { OAuth._endOfPopupResponseTemplate = Assets.getText( "end_of_popup_response.html"); -var endOfRedirectResponseTemplate = Assets.getText( +OAuth._endOfRedirectResponseTemplate = Assets.getText( "end_of_redirect_response.html"); // Renders the end of login response template into some HTML and JavaScript @@ -322,7 +337,7 @@ var renderEndOfLoginResponse = function (options) { if (options.loginStyle === 'popup') { template = OAuth._endOfPopupResponseTemplate; } else if (options.loginStyle === 'redirect') { - template = endOfRedirectResponseTemplate; + template = OAuth._endOfRedirectResponseTemplate; } else { throw new Error('invalid loginStyle: ' + options.loginStyle); } @@ -370,12 +385,7 @@ OAuth._endOfLoginResponse = function (res, details) { if (details.loginStyle === 'redirect') { redirectUrl = OAuth._stateFromQuery(details.query).redirectUrl; var appHost = Meteor.absoluteUrl(); - var appHostReplacedLocalhost = Meteor.absoluteUrl(undefined, { - replaceLocalhost: true - }); - if (redirectUrl.substr(0, appHost.length) !== appHost && - redirectUrl.substr(0, appHostReplacedLocalhost.length) !== - appHostReplacedLocalhost) { + if (OAuth._checkRedirectUrlOrigin(redirectUrl)) { details.error = "redirectUrl (" + redirectUrl + ") is not on the same host as the app (" + appHost + ")"; redirectUrl = appHost; From 381b2fa0990acc5924c8bb9c9817a73b1d8b3dfe Mon Sep 17 00:00:00 2001 From: Emily Stark Date: Mon, 29 Sep 2014 18:27:49 -0700 Subject: [PATCH 10/15] Remove 'reload' timeout. This timeout was designed for a very specific case (hit stop during a hot code push, come back to the page later and you don't expect your session state to still be there), but it's not clear what length of time is right for that, nor whether it's even what users expect (and if there should be a timeout, it probably varies from package to package depending on what type of data the package is storing in sessionStorage -- e.g. for OAuth logins, 30 seconds is way too short of a timeout). Fixes #2696. --- packages/reload/reload.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/reload/reload.js b/packages/reload/reload.js index c20060cc70..2a400bdece 100644 --- a/packages/reload/reload.js +++ b/packages/reload/reload.js @@ -34,13 +34,6 @@ Reload = {}; var KEY_NAME = 'Meteor_Reload'; -// after how long should we consider this no longer an automatic -// reload, but a fresh restart. This only happens if a reload is -// interrupted and a user manually restarts things. The only time -// this is really weird is if a user navigates away mid-refresh, -// then manually navigates back to the page. -var TIMEOUT = 30000; - var old_data = {}; // read in old data at startup. @@ -98,8 +91,7 @@ try { Meteor._debug("Got invalid JSON on reload. Ignoring."); } -if (old_parsed.reload && typeof old_parsed.data === "object" && - old_parsed.time + TIMEOUT > (new Date()).getTime()) { +if (old_parsed.reload && typeof old_parsed.data === "object") { // Meteor._debug("Restoring reload data."); old_data = old_parsed.data; } @@ -178,7 +170,7 @@ Reload._migrate = function (tryReload, options) { try { // Persist the migration data var json = JSON.stringify({ - time: (new Date()).getTime(), data: migrationData, reload: true + data: migrationData, reload: true }); } catch (err) { Meteor._debug("Couldn't serialize data for migration", migrationData); From 4ba382eff3ff296e7550197464fe969b3047e1ec Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Mon, 29 Sep 2014 18:47:18 -0700 Subject: [PATCH 11/15] Move velocity code to a separate file for easier maintenance. --- tools/commands.js | 125 ++---------------------------------------- tools/run-velocity.js | 124 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 119 deletions(-) create mode 100644 tools/run-velocity.js diff --git a/tools/commands.js b/tools/commands.js index 6b5dab658f..be786f3b8b 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -25,9 +25,6 @@ var cordova = require('./commands-cordova.js'); var commandsPackages = require('./commands-packages.js'); var execFileSync = require('./utils.js').execFileSync; var Console = require('./console.js').Console; -var uniload = require('./uniload.js'); -var phantomjs = require('phantomjs'); -var child_process = require('child_process'); // The architecture used by Galaxy servers; it's the architecture used // by 'meteor deploy'. @@ -307,125 +304,15 @@ main.registerCommand({ if (options['raw-logs']) runLog.setRawLogs(true); - // If `--test` is specified we need to start the app server, poke - // it with PhantomJS, and listen for test results. - // - // More specifically: - // 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. Poke an app server with PhantomJS to run client side tests. - // 4. Print the results and exit with the appropriate exit code. + // Use `--test` to activate velocity testing. if (options['test']){ - var unipackages = uniload.load({ - packages: [ 'ddp'] - }); - var DDP = unipackages.ddp.DDP; - - var hostPort = parseHostPort(options.port); - var serverUrl = "http://" + (hostPort.host || "localhost") + - ":" + hostPort.port; - var ddpConnection = DDP.connect(serverUrl); - - 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"); - }, 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") - //better way to exit here? - 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); + 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, diff --git a/tools/run-velocity.js b/tools/run-velocity.js new file mode 100644 index 0000000000..e74df0637d --- /dev/null +++ b/tools/run-velocity.js @@ -0,0 +1,124 @@ +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 comment +// +// More specifically: +// 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. Poke an 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; + + 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"); + }, 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"); + //better way to exit here? + 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; From a72629c6ce35a45f081b26cb06397f8bede96dd9 Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Mon, 29 Sep 2014 19:06:25 -0700 Subject: [PATCH 12/15] Mark run --test as experimental. --- tools/help.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/help.txt b/tools/help.txt index 5de0546e61..5c1d1d398d 100644 --- a/tools/help.txt +++ b/tools/help.txt @@ -50,8 +50,8 @@ Options: --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) - --test Run velocity tests (using phantomjs if necessary) and exit --verbose Print all output from builds logs. + --test [Experimental] Run Velocity tests using phantomjs and exit >>> create From 99f7c4cd66a63bbcb1d21135907bb1392f9eab8f Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Mon, 29 Sep 2014 19:14:46 -0700 Subject: [PATCH 13/15] comments --- tools/commands.js | 5 ++++- tools/run-velocity.js | 20 +++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/tools/commands.js b/tools/commands.js index be786f3b8b..770982857a 100644 --- a/tools/commands.js +++ b/tools/commands.js @@ -304,7 +304,10 @@ main.registerCommand({ if (options['raw-logs']) runLog.setRawLogs(true); - // Use `--test` to activate velocity testing. + // 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; diff --git a/tools/run-velocity.js b/tools/run-velocity.js index e74df0637d..3025bf64a9 100644 --- a/tools/run-velocity.js +++ b/tools/run-velocity.js @@ -5,10 +5,12 @@ 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. -// XXX comment -// -// More specifically: // 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. @@ -20,6 +22,8 @@ var runVelocity = function (url) { }); 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(){ @@ -30,6 +34,8 @@ var runVelocity = function (url) { 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){ @@ -40,7 +46,7 @@ var runVelocity = function (url) { console.log("PASSED", testDesc); } else if (msg.fields.result == "failed"){ console.error("FAILED", testDesc); - console.log(msg.fields.failureStackTrace) + console.log(msg.fields.failureStackTrace); } } } @@ -79,7 +85,11 @@ var runVelocity = function (url) { setTimeout(function(){ if (aggregateResult === "passed"){ console.log("TESTS RAN SUCCESSFULLY"); - //better way to exit here? + // 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"){ From 5a4d35184cc84713b3c18d110f3d835401fbedea Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Mon, 29 Sep 2014 19:50:24 -0700 Subject: [PATCH 14/15] code style cleanups to match style guide. help text nitpicking. --- tools/help.txt | 8 +++---- tools/run-velocity.js | 52 +++++++++++++++++++++---------------------- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tools/help.txt b/tools/help.txt index 5c1d1d398d..33775373f8 100644 --- a/tools/help.txt +++ b/tools/help.txt @@ -47,11 +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 + --test [Experimental] Run Velocity tests using phantomjs and exit. >>> create diff --git a/tools/run-velocity.js b/tools/run-velocity.js index 3025bf64a9..1c73d82861 100644 --- a/tools/run-velocity.js +++ b/tools/run-velocity.js @@ -14,7 +14,7 @@ var _ = require('underscore'); // 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. Poke an app server with PhantomJS to run client side tests. +// 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({ @@ -26,25 +26,25 @@ var runVelocity = function (url) { var ddpConnection = DDP.connect(url); - var interval = setInterval(function(){ - if (ddpConnection.status().status === "connected"){ + var interval = setInterval(function () { + if (ddpConnection.status().status === "connected") { clearInterval(interval); ddpConnection.subscribe("VelocityTestReports", { - onError: function(){ + 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(){ + }, onReady: function () { this.connection.registerStore("velocityTestReports", { - update: function(msg){ - if (msg.msg == "added"){ + update: function (msg) { + if (msg.msg === "added") { var testDesc = msg.fields.framework + " : " + msg.fields.ancestors.join(":") + " => " + msg.fields.name; - if(msg.fields.result == "passed"){ + if (msg.fields.result === "passed") { console.log("PASSED", testDesc); - } else if (msg.fields.result == "failed"){ + } else if (msg.fields.result === "failed") { console.error("FAILED", testDesc); console.log(msg.fields.failureStackTrace); } @@ -55,9 +55,9 @@ var runVelocity = function (url) { }); var reports = {}; - function updateReport(msg){ + function updateReport(msg) { var report = reports[msg.id]; - if (! report){ + if (! report) { reports[msg.id] = msg.fields; } else { _.extend(report, msg.fields); @@ -66,24 +66,24 @@ var runVelocity = function (url) { var aggregateResult = null; var isFinished = false; ddpConnection.subscribe("VelocityAggregateReports", { - onError: function(){ + onError: function () { Console.stderr.write("failed to subscribe to " + "VelocityAggregateReports subscription"); - }, onReady: function(){ + }, onReady: function () { this.connection.registerStore("velocityAggregateReports", { - update: function(msg){ - if (msg.msg === "added" || msg.msg == "changed"){ + update: function (msg) { + if (msg.msg === "added" || msg.msg === "changed") { updateReport(msg); var report = reports[msg.id]; - if (report.name === "aggregateResult"){ + if (report.name === "aggregateResult") { aggregateResult = report.result; } - if(report.name === "aggregateComplete" && - report.result === "completed"){ - setTimeout(function(){ - if (aggregateResult === "passed"){ + 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 @@ -92,7 +92,7 @@ var runVelocity = function (url) { // test completion. process.exit(0); } - if (aggregateResult === "failed"){ + if (aggregateResult === "failed") { console.log("FAILURE"); process.exit(1); } @@ -104,7 +104,7 @@ var runVelocity = function (url) { } }); - function visitWithPhantom(url){ + function visitWithPhantom (url) { var phantomScript = "require('webpage').create().open('" + url + "');"; child_process.execFile( '/bin/bash', @@ -114,13 +114,13 @@ var runVelocity = function (url) { } ddpConnection.subscribe("VelocityMirrors", { - onError: function(err){ + onError: function (err) { Console.stderr.write("failed to subscribe to VelocityMirrors " + "subscription", err); - }, onReady: function(){ + }, onReady: function () { this.connection.registerStore("velocityMirrors", { - update: function(msg){ - if (msg.msg === "added"){ + update: function (msg) { + if (msg.msg === "added") { visitWithPhantom(msg.fields.rootUrl); } } From 43c996cd13e4e57b8c82ce26c801c7c2a279d83e Mon Sep 17 00:00:00 2001 From: Nick Martin Date: Mon, 29 Sep 2014 21:41:05 -0700 Subject: [PATCH 15/15] Fix whitespace --- tools/help.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/help.txt b/tools/help.txt index 48538457f5..84add6c744 100644 --- a/tools/help.txt +++ b/tools/help.txt @@ -55,7 +55,7 @@ Options: --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. + --test [Experimental] Run Velocity tests using phantomjs and exit. >>> debug Run the project, but suspend the server process for debugging.