From f8ba1226b18ff07b8b497732585403c82ceaf21f Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 28 Sep 2016 12:21:18 -0400 Subject: [PATCH 1/5] Rename test entry point module so that it isn't ignored. --- tools/tests/old/app-with-private/{test.js => main.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/tests/old/app-with-private/{test.js => main.js} (100%) diff --git a/tools/tests/old/app-with-private/test.js b/tools/tests/old/app-with-private/main.js similarity index 100% rename from tools/tests/old/app-with-private/test.js rename to tools/tests/old/app-with-private/main.js From 20a66041264f7dba1a2634710f12a7199b60934e Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 28 Sep 2016 12:27:00 -0400 Subject: [PATCH 2/5] Remove pointless and exception-swallowing assert.doesNotThrow wrappers. --- tools/tests/old/test-bundler-assets.js | 161 ++++++++++++------------- 1 file changed, 80 insertions(+), 81 deletions(-) diff --git a/tools/tests/old/test-bundler-assets.js b/tools/tests/old/test-bundler-assets.js index df3a543dbb..3a2ebdccc1 100644 --- a/tools/tests/old/test-bundler-assets.js +++ b/tools/tests/old/test-bundler-assets.js @@ -50,96 +50,95 @@ var runTest = function () { catalog.official.initialize(); console.log("Bundle app with public/ directory"); - assert.doesNotThrow(function () { - var projectContext = makeProjectContext("app-with-public"); - var tmpOutputDir = tmpDir(); - var result = bundler.bundle({ - projectContext: projectContext, - outputPath: tmpOutputDir - }); - var clientManifest = JSON.parse( - files.readFile( - files.pathJoin(tmpOutputDir, "programs", "web.browser", "program.json") - ) - ); + var projectContext = makeProjectContext("app-with-public"); + var tmpOutputDir = tmpDir(); - var testCases = [["/test.txt", "Test\n"], - ["/nested/nested.txt", "Nested\n"]]; - _.each(testCases, function (file) { - var manifestItem = _.find(clientManifest.manifest, function (m) { - return m.url === file[0]; - }); - assert(manifestItem); - var diskPath = files.pathJoin(tmpOutputDir, "programs", "web.browser", - manifestItem.path); - assert(files.exists(diskPath)); - assert.strictEqual(files.readFile(diskPath, "utf8"), file[1]); + var result = bundler.bundle({ + projectContext: projectContext, + outputPath: tmpOutputDir + }); + + var clientManifest = JSON.parse( + files.readFile( + files.pathJoin(tmpOutputDir, "programs", "web.browser", "program.json") + ) + ); + + var testCases = [["/test.txt", "Test\n"], + ["/nested/nested.txt", "Nested\n"]]; + _.each(testCases, function (file) { + var manifestItem = _.find(clientManifest.manifest, function (m) { + return m.url === file[0]; }); + assert(manifestItem); + var diskPath = files.pathJoin(tmpOutputDir, "programs", "web.browser", + manifestItem.path); + assert(files.exists(diskPath)); + assert.strictEqual(files.readFile(diskPath, "utf8"), file[1]); }); console.log("Bundle app with private/ directory and package asset"); - assert.doesNotThrow(function () { - var projectContext = makeProjectContext("app-with-private"); - var tmpOutputDir = tmpDir(); + var projectContext = makeProjectContext("app-with-private"); + var tmpOutputDir = tmpDir(); - var result = bundler.bundle({ - projectContext: projectContext, - outputPath: tmpOutputDir - }); - - var serverManifest = JSON.parse( - files.readFile( - files.pathJoin(tmpOutputDir, "programs", "server", - "program.json") - ) - ); - var testTxtPath; - var nestedTxtPath; - var packageTxtPath; - var unregisteredExtensionPath; - _.each(serverManifest.load, function (item) { - if (item.path === "packages/test-package.js") { - packageTxtPath = files.pathJoin( - tmpOutputDir, "programs", "server", item.assets['test-package.txt']); - unregisteredExtensionPath = files.pathJoin( - tmpOutputDir, "programs", "server", item.assets["test.notregistered"]); - } - if (item.path === "app/test.js") { - testTxtPath = files.pathJoin( - tmpOutputDir, "programs", "server", item.assets['test.txt']); - nestedTxtPath = files.pathJoin( - tmpOutputDir, "programs", "server", item.assets["nested/test.txt"]); - } - }); - // check that the files are where the manifest says they are - assert.strictEqual(result.errors, false, result.errors && result.errors[0]); - assert(files.exists(testTxtPath)); - assert(files.exists(nestedTxtPath)); - assert(files.exists(packageTxtPath)); - assert(files.exists(unregisteredExtensionPath)); - assert.strictEqual(files.readFile(testTxtPath, "utf8"), "Test\n"); - assert.strictEqual(files.readFile(nestedTxtPath, "utf8"), "Nested\n"); - assert.strictEqual(files.readFile(packageTxtPath, "utf8"), "Package\n"); - assert.strictEqual(files.readFile(unregisteredExtensionPath, "utf8"), - "No extension handler\n"); - - // Run the app to check that Assets.getText/Binary do the right things. - var meteorToolPath = files.convertToOSPath(process.env.METEOR_TOOL_PATH); - var fut = new Future(); - require('child_process').execFile( - meteorToolPath, - // use a non-default port so we don't fail if someone is running an app - // now - ["--once", "--port", "4123"], { - cwd: files.convertToOSPath(projectContext.projectDir), - stdio: 'inherit' - }, - fut.resolver() - ); - fut.wait(); // would throw if command failed + var result = bundler.bundle({ + projectContext: projectContext, + outputPath: tmpOutputDir }); + + var serverManifest = JSON.parse( + files.readFile( + files.pathJoin(tmpOutputDir, "programs", "server", + "program.json") + ) + ); + + var testTxtPath; + var nestedTxtPath; + var packageTxtPath; + var unregisteredExtensionPath; + _.each(serverManifest.load, function (item) { + if (item.path === "packages/test-package.js") { + packageTxtPath = files.pathJoin( + tmpOutputDir, "programs", "server", item.assets['test-package.txt']); + unregisteredExtensionPath = files.pathJoin( + tmpOutputDir, "programs", "server", item.assets["test.notregistered"]); + } + if (item.path === "app/main.js") { + testTxtPath = files.pathJoin( + tmpOutputDir, "programs", "server", item.assets['test.txt']); + nestedTxtPath = files.pathJoin( + tmpOutputDir, "programs", "server", item.assets["nested/test.txt"]); + } + }); + // check that the files are where the manifest says they are + assert.strictEqual(result.errors, false, result.errors && result.errors[0]); + assert(files.exists(testTxtPath)); + assert(files.exists(nestedTxtPath)); + assert(files.exists(packageTxtPath)); + assert(files.exists(unregisteredExtensionPath)); + assert.strictEqual(files.readFile(testTxtPath, "utf8"), "Test\n"); + assert.strictEqual(files.readFile(nestedTxtPath, "utf8"), "Nested\n"); + assert.strictEqual(files.readFile(packageTxtPath, "utf8"), "Package\n"); + assert.strictEqual(files.readFile(unregisteredExtensionPath, "utf8"), + "No extension handler\n"); + + // Run the app to check that Assets.getText/Binary do the right things. + var meteorToolPath = files.convertToOSPath(process.env.METEOR_TOOL_PATH); + var fut = new Future(); + require('child_process').execFile( + meteorToolPath, + // use a non-default port so we don't fail if someone is running an app + // now + ["--once", "--port", "4123"], { + cwd: files.convertToOSPath(projectContext.projectDir), + stdio: 'inherit' + }, + fut.resolver() + ); + fut.wait(); // would throw if command failed }; var Fiber = require('fibers'); From 5b2e08a80cfe15616d222cd86a0e1a9ea317addc Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Wed, 28 Sep 2016 16:57:52 -0400 Subject: [PATCH 3/5] Automatically reconfigure Mongo replication set when --port differs. Fixes #7563. --- tools/runners/run-mongo.js | 30 +++++++++-- .../mongo-sanity/.meteor/.finished-upgraders | 15 ++++++ .../apps/mongo-sanity/.meteor/.gitignore | 1 + tools/tests/apps/mongo-sanity/.meteor/.id | 7 +++ .../tests/apps/mongo-sanity/.meteor/packages | 12 +++++ .../tests/apps/mongo-sanity/.meteor/platforms | 2 + tools/tests/apps/mongo-sanity/.meteor/release | 1 + .../tests/apps/mongo-sanity/.meteor/versions | 54 +++++++++++++++++++ tools/tests/apps/mongo-sanity/server/main.js | 18 +++++++ tools/tests/mongo.js | 29 ++++++++++ 10 files changed, 165 insertions(+), 4 deletions(-) create mode 100644 tools/tests/apps/mongo-sanity/.meteor/.finished-upgraders create mode 100644 tools/tests/apps/mongo-sanity/.meteor/.gitignore create mode 100644 tools/tests/apps/mongo-sanity/.meteor/.id create mode 100644 tools/tests/apps/mongo-sanity/.meteor/packages create mode 100644 tools/tests/apps/mongo-sanity/.meteor/platforms create mode 100644 tools/tests/apps/mongo-sanity/.meteor/release create mode 100644 tools/tests/apps/mongo-sanity/.meteor/versions create mode 100644 tools/tests/apps/mongo-sanity/server/main.js diff --git a/tools/runners/run-mongo.js b/tools/runners/run-mongo.js index 9f9b692a20..d308a8066c 100644 --- a/tools/runners/run-mongo.js +++ b/tools/runners/run-mongo.js @@ -532,7 +532,8 @@ var launchMongo = function (options) { var stdoutOnData = fiberHelpers.bindEnvironment(function (data) { // note: don't use "else ifs" in this, because 'data' can have multiple // lines - if (/\[initandlisten\] Did not find local replica set configuration document at startup/.test(data)) { + if (/\[initandlisten\] Did not find local replica set configuration document at startup/.test(data) || + /\[ReplicationExecutor\] Locally stored replica set configuration does not have a valid entry for the current node/.test(data)) { replSetReadyToBeInitiated = true; maybeReadyToTalk(); } @@ -596,10 +597,25 @@ var launchMongo = function (options) { if (stopped) { return; } + var configuration = { _id: replSetName, + version: 1, members: [{_id: 0, host: '127.0.0.1:' + options.port, priority: 100}] }; + + try { + const config = yieldingMethod(db.admin(), "command", { + replSetGetConfig: 1, + }).config; + + // If a replication set configuration already exists, it's + // important that the new version number is greater than the old. + if (config && _.has(config, "version")) { + configuration.version = config.version + 1; + } + } catch (e) {} + if (options.multiple) { // Add two more members: one of which should start as secondary but // could in theory become primary, and one of which can never be @@ -613,10 +629,16 @@ var launchMongo = function (options) { } try { - var initiateResult = yieldingMethod( - db.admin(), 'command', {replSetInitiate: configuration}); + yieldingMethod(db.admin(), 'command', { + replSetInitiate: configuration, + }); } catch (e) { - if (e.message !== 'already initialized') { + if (e.message === 'already initialized') { + yieldingMethod(db.admin(), 'command', { + replSetReconfig: configuration, + force: true, + }); + } else { throw Error("rs.initiate error: " + e.message); } } diff --git a/tools/tests/apps/mongo-sanity/.meteor/.finished-upgraders b/tools/tests/apps/mongo-sanity/.meteor/.finished-upgraders new file mode 100644 index 0000000000..aa607041da --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/.finished-upgraders @@ -0,0 +1,15 @@ +# This file contains information which helps Meteor properly upgrade your +# app when you run 'meteor update'. You should check it into version control +# with your project. + +notices-for-0.9.0 +notices-for-0.9.1 +0.9.4-platform-file +notices-for-facebook-graph-api-2 +1.2.0-standard-minifiers-package +1.2.0-meteor-platform-split +1.2.0-cordova-changes +1.2.0-breaking-changes +1.3.0-split-minifiers-package +1.4.0-remove-old-dev-bundle-link +1.4.1-add-shell-server-package diff --git a/tools/tests/apps/mongo-sanity/.meteor/.gitignore b/tools/tests/apps/mongo-sanity/.meteor/.gitignore new file mode 100644 index 0000000000..4083037423 --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/.gitignore @@ -0,0 +1 @@ +local diff --git a/tools/tests/apps/mongo-sanity/.meteor/.id b/tools/tests/apps/mongo-sanity/.meteor/.id new file mode 100644 index 0000000000..789b92d073 --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/.id @@ -0,0 +1,7 @@ +# This file contains a token that is unique to your project. +# Check it into your repository along with the rest of this directory. +# It can be used for purposes such as: +# - ensuring you don't accidentally deploy one app on top of another +# - providing package authors with aggregated statistics + +fgbyyt1b3uxw5u734ug diff --git a/tools/tests/apps/mongo-sanity/.meteor/packages b/tools/tests/apps/mongo-sanity/.meteor/packages new file mode 100644 index 0000000000..6205c4c08c --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/packages @@ -0,0 +1,12 @@ +# Meteor packages used by this project, one per line. +# Check this file (and the other files in this directory) into your repository. +# +# 'meteor add' and 'meteor remove' will edit this file for you, +# but you can also edit it by hand. + +meteor-base # Packages every Meteor app needs to have +mongo # The database Meteor supports right now + +ecmascript # Enable ECMAScript2015+ syntax in app code +shell-server # Server-side component of the `meteor shell` command + diff --git a/tools/tests/apps/mongo-sanity/.meteor/platforms b/tools/tests/apps/mongo-sanity/.meteor/platforms new file mode 100644 index 0000000000..efeba1b50c --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/tools/tests/apps/mongo-sanity/.meteor/release b/tools/tests/apps/mongo-sanity/.meteor/release new file mode 100644 index 0000000000..621e94f0ec --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/release @@ -0,0 +1 @@ +none diff --git a/tools/tests/apps/mongo-sanity/.meteor/versions b/tools/tests/apps/mongo-sanity/.meteor/versions new file mode 100644 index 0000000000..e675491585 --- /dev/null +++ b/tools/tests/apps/mongo-sanity/.meteor/versions @@ -0,0 +1,54 @@ +allow-deny@1.0.5 +autoupdate@1.3.11 +babel-compiler@6.9.2-beta.5 +babel-runtime@0.1.12-beta.5 +base64@1.0.9 +binary-heap@1.0.9 +blaze@2.1.8 +blaze-tools@1.0.9 +boilerplate-generator@1.0.10 +callback-hook@1.0.9 +check@1.2.3 +ddp@1.2.5 +ddp-client@1.3.2-beta.5 +ddp-common@1.2.6 +ddp-server@1.3.11-beta.5 +deps@1.0.12 +diff-sequence@1.0.6 +ecmascript@0.5.9-beta.5 +ecmascript-runtime@0.3.15-beta.5 +ejson@1.0.12 +geojson-utils@1.0.9 +hot-code-push@1.0.4 +html-tools@1.0.10 +htmljs@1.0.10 +http@1.2.10-beta.5 +id-map@1.0.8 +jquery@1.11.9 +livedata@1.0.18 +logging@1.1.16-beta.5 +meteor@1.2.18-beta.5 +meteor-base@1.0.4 +minimongo@1.0.17 +modules@0.7.7-beta.5 +modules-runtime@0.7.7-beta.5 +mongo@1.1.13-beta.5 +mongo-id@1.0.5 +npm-mongo@1.5.51-beta.5 +observe-sequence@1.0.12 +ordered-dict@1.0.8 +promise@0.8.8-beta.5 +random@1.0.10 +reactive-var@1.0.10 +reload@1.1.10 +retry@1.0.8 +routepolicy@1.0.11 +shell-server@0.2.1 +spacebars@1.0.12 +spacebars-compiler@1.0.12 +tracker@1.1.0 +ui@1.0.11 +underscore@1.0.9 +url@1.0.10 +webapp@1.3.12-beta.5 +webapp-hashing@1.0.9 diff --git a/tools/tests/apps/mongo-sanity/server/main.js b/tools/tests/apps/mongo-sanity/server/main.js new file mode 100644 index 0000000000..45aa6e530a --- /dev/null +++ b/tools/tests/apps/mongo-sanity/server/main.js @@ -0,0 +1,18 @@ +import { Mongo } from 'meteor/mongo'; + +const collection = new Mongo.Collection("sanity"); + +Meteor.startup(() => { + let doc = collection.findOne(); + + if (! doc) { + collection.insert({ count: 0 }); + doc = collection.findOne(); + } + + collection.update(doc._id, { + $inc: { count: 1 } + }); + + console.log("count: " + collection.findOne().count); +}); diff --git a/tools/tests/mongo.js b/tools/tests/mongo.js index eafc5fecd3..eb9794a446 100644 --- a/tools/tests/mongo.js +++ b/tools/tests/mongo.js @@ -56,3 +56,32 @@ selftest.define("meteor mongo", function () { selftest.define("meteor mongo in unicode dir", function () { testMeteorMongo('asdf\u0442asdf'); }); + +selftest.define("mongo with multiple --port numbers (#7563)", function () { + var s = new Sandbox(); + s.createApp("mongo-multiple-ports", "mongo-sanity"); + s.cd("mongo-multiple-ports"); + + function check(args, matches) { + const run = s.run(...args); + run.waitSecs(30); + matches.forEach(m => { + run.waitSecs(10); + run.match(m); + }); + run.stop(); + } + + // Make absolutely sure we're creating the database for the first time. + check(["reset"], ["Project reset."]); + + let count = 0; + function next() { + return ["Started MongoDB", "count: " + (++count)]; + } + + check(["run"], next()); + check(["--port", "4321"], next()); + check(["--port", "4123"], next()); + check([], next()); +}); From 295d3d5678228f06ee0ab6c0d60139849a0ea192 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 29 Sep 2016 09:42:54 -0400 Subject: [PATCH 4/5] Kill mongo when server process exits. We try to kill any mongod processes before starting new ones, but this change kills it when the development server shuts down, too. Killing mongo on shutdown is particularly important for tests that run meteor multiple times in a row, and for whatever reason fail to find and kill running mongod processes on startup, e.g. because the --port has changed (#7563). This comment by @glasser seems to suggest this is a reasonable idea: https://github.com/meteor/meteor/issues/2182#issuecomment-45685614 Fixes #2182 and possibly other related bugs. --- tools/runners/run-mongo.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/runners/run-mongo.js b/tools/runners/run-mongo.js index d308a8066c..551d36d63b 100644 --- a/tools/runners/run-mongo.js +++ b/tools/runners/run-mongo.js @@ -482,15 +482,15 @@ var launchMongo = function (options) { proc = spawnMongod(mongod_path, port, dbPath, replSetName); - subHandles.push({ - stop: function () { - if (proc) { - proc.removeListener('exit', procExitHandler); - proc.kill('SIGINT'); - proc = null; - } + function stop() { + if (proc) { + proc.removeListener('exit', procExitHandler); + proc.kill('SIGINT'); + proc = null; } - }); + } + require("../tool-env/cleanup.js").onExit(stop); + subHandles.push({ stop }); var procExitHandler = fiberHelpers.bindEnvironment(function (code, signal) { // Defang subHandle.stop(). From dd3fe9a264a00f085b9fa7654d18b3fd67dbae30 Mon Sep 17 00:00:00 2001 From: Ben Newman Date: Thu, 29 Sep 2016 16:03:02 -0400 Subject: [PATCH 5/5] Add additional delay to "run: run" test. --- tools/tests/run.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/tests/run.js b/tools/tests/run.js index 908cdc8593..3be4636150 100644 --- a/tools/tests/run.js +++ b/tools/tests/run.js @@ -106,6 +106,7 @@ try { run.match('s.json: parse error reading settings file'); run.match('Waiting for file change'); s.write('s.json', '{}'); + run.waitSecs(15); run.match('App running at'); run.stop();