diff options
Diffstat (limited to 'src/mongo/shell/servers.js')
-rw-r--r-- | src/mongo/shell/servers.js | 2343 |
1 files changed, 1160 insertions, 1183 deletions
diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js index 4ebf51ec693..e4633c42a7e 100644 --- a/src/mongo/shell/servers.js +++ b/src/mongo/shell/servers.js @@ -2,1112 +2,1192 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro myPort; (function() { - "use strict"; +"use strict"; - var shellVersion = version; +var shellVersion = version; - // Record the exit codes of mongod and mongos processes that crashed during startup keyed by - // port. This map is cleared when MongoRunner._startWithArgs and MongoRunner.stopMongod/s are - // called. - var serverExitCodeMap = {}; +// Record the exit codes of mongod and mongos processes that crashed during startup keyed by +// port. This map is cleared when MongoRunner._startWithArgs and MongoRunner.stopMongod/s are +// called. +var serverExitCodeMap = {}; - var _parsePath = function() { - var dbpath = ""; - for (var i = 0; i < arguments.length; ++i) - if (arguments[i] == "--dbpath") - dbpath = arguments[i + 1]; +var _parsePath = function() { + var dbpath = ""; + for (var i = 0; i < arguments.length; ++i) + if (arguments[i] == "--dbpath") + dbpath = arguments[i + 1]; - if (dbpath == "") - throw Error("No dbpath specified"); + if (dbpath == "") + throw Error("No dbpath specified"); - return dbpath; - }; + return dbpath; +}; - var _parsePort = function() { - var port = ""; - for (var i = 0; i < arguments.length; ++i) - if (arguments[i] == "--port") - port = arguments[i + 1]; +var _parsePort = function() { + var port = ""; + for (var i = 0; i < arguments.length; ++i) + if (arguments[i] == "--port") + port = arguments[i + 1]; - if (port == "") - throw Error("No port specified"); - return port; - }; + if (port == "") + throw Error("No port specified"); + return port; +}; - var createMongoArgs = function(binaryName, args) { - if (!Array.isArray(args)) { - throw new Error("The second argument to createMongoArgs must be an array"); - } +var createMongoArgs = function(binaryName, args) { + if (!Array.isArray(args)) { + throw new Error("The second argument to createMongoArgs must be an array"); + } - var fullArgs = [binaryName]; - - if (args.length == 1 && isObject(args[0])) { - var o = args[0]; - for (var k in o) { - if (o.hasOwnProperty(k)) { - if (k == "v" && isNumber(o[k])) { - var n = o[k]; - if (n > 0) { - if (n > 10) - n = 10; - var temp = "-"; - while (n-- > 0) - temp += "v"; - fullArgs.push(temp); - } - } else { - fullArgs.push("--" + k); - if (o[k] != "") - fullArgs.push("" + o[k]); + var fullArgs = [binaryName]; + + if (args.length == 1 && isObject(args[0])) { + var o = args[0]; + for (var k in o) { + if (o.hasOwnProperty(k)) { + if (k == "v" && isNumber(o[k])) { + var n = o[k]; + if (n > 0) { + if (n > 10) + n = 10; + var temp = "-"; + while (n-- > 0) + temp += "v"; + fullArgs.push(temp); } + } else { + fullArgs.push("--" + k); + if (o[k] != "") + fullArgs.push("" + o[k]); } } - } else { - for (var i = 0; i < args.length; i++) - fullArgs.push(args[i]); } + } else { + for (var i = 0; i < args.length; i++) + fullArgs.push(args[i]); + } - return fullArgs; - }; - - MongoRunner = function() {}; - - MongoRunner.dataDir = "/data/db"; - MongoRunner.dataPath = "/data/db/"; - - MongoRunner.mongodPath = "mongod"; - MongoRunner.mongosPath = "mongos"; - MongoRunner.mongoShellPath = "mongo"; - - MongoRunner.VersionSub = function(pattern, version) { - this.pattern = pattern; - this.version = version; - }; - - /** - * Returns an array of version elements from a version string. - * - * "3.3.4-fade3783" -> ["3", "3", "4-fade3783" ] - * "3.2" -> [ "3", "2" ] - * 3 -> exception: versions must have at least two components. - */ - var convertVersionStringToArray = function(versionString) { - assert("" !== versionString, "Version strings must not be empty"); - var versionArray = versionString.split('.'); - - assert.gt(versionArray.length, - 1, - "MongoDB versions must have at least two components to compare, but \"" + - versionString + "\" has " + versionArray.length); - return versionArray; - }; - - /** - * Returns the major version string from a version string. - * - * 3.3.4-fade3783 -> 3.3 - * 3.2 -> 3.2 - * 3 -> exception: versions must have at least two components. - */ - var extractMajorVersionFromVersionString = function(versionString) { - return convertVersionStringToArray(versionString).slice(0, 2).join('.'); - }; - - // These patterns allow substituting the binary versions used for each version string to support - // the - // dev/stable MongoDB release cycle. - // - // If you add a new version substitution to this list, you should add it to the lists of - // versions being checked in 'verify_versions_test.js' to verify it is susbstituted correctly. - MongoRunner.binVersionSubs = [ - new MongoRunner.VersionSub("latest", shellVersion()), - new MongoRunner.VersionSub(extractMajorVersionFromVersionString(shellVersion()), - shellVersion()), - // To-be-updated when we branch for the next release. - new MongoRunner.VersionSub("last-stable", "4.2") - ]; - - MongoRunner.getBinVersionFor = function(version) { - if (version instanceof MongoRunner.versionIterator.iterator) { - version = version.current(); - } - - if (version == null) - version = ""; - version = version.trim(); - if (version === "") - version = "latest"; - - // See if this version is affected by version substitutions - for (var i = 0; i < MongoRunner.binVersionSubs.length; i++) { - var sub = MongoRunner.binVersionSubs[i]; - if (sub.pattern == version) { - return sub.version; - } - } - - return version; - }; - - /** - * Returns true if two version strings could represent the same version. This is true - * if, after passing the versions through getBinVersionFor, the versions have the - * same value for each version component up through the length of the shorter version. - * - * That is, 3.2.4 compares equal to 3.2, but 3.2.4 does not compare equal to 3.2.3. - */ - MongoRunner.areBinVersionsTheSame = function(versionA, versionB) { + return fullArgs; +}; + +MongoRunner = function() {}; + +MongoRunner.dataDir = "/data/db"; +MongoRunner.dataPath = "/data/db/"; + +MongoRunner.mongodPath = "mongod"; +MongoRunner.mongosPath = "mongos"; +MongoRunner.mongoShellPath = "mongo"; + +MongoRunner.VersionSub = function(pattern, version) { + this.pattern = pattern; + this.version = version; +}; + +/** + * Returns an array of version elements from a version string. + * + * "3.3.4-fade3783" -> ["3", "3", "4-fade3783" ] + * "3.2" -> [ "3", "2" ] + * 3 -> exception: versions must have at least two components. + */ +var convertVersionStringToArray = function(versionString) { + assert("" !== versionString, "Version strings must not be empty"); + var versionArray = versionString.split('.'); + + assert.gt(versionArray.length, + 1, + "MongoDB versions must have at least two components to compare, but \"" + + versionString + "\" has " + versionArray.length); + return versionArray; +}; + +/** + * Returns the major version string from a version string. + * + * 3.3.4-fade3783 -> 3.3 + * 3.2 -> 3.2 + * 3 -> exception: versions must have at least two components. + */ +var extractMajorVersionFromVersionString = function(versionString) { + return convertVersionStringToArray(versionString).slice(0, 2).join('.'); +}; + +// These patterns allow substituting the binary versions used for each version string to support +// the +// dev/stable MongoDB release cycle. +// +// If you add a new version substitution to this list, you should add it to the lists of +// versions being checked in 'verify_versions_test.js' to verify it is susbstituted correctly. +MongoRunner.binVersionSubs = [ + new MongoRunner.VersionSub("latest", shellVersion()), + new MongoRunner.VersionSub(extractMajorVersionFromVersionString(shellVersion()), + shellVersion()), + // To-be-updated when we branch for the next release. + new MongoRunner.VersionSub("last-stable", "4.2") +]; + +MongoRunner.getBinVersionFor = function(version) { + if (version instanceof MongoRunner.versionIterator.iterator) { + version = version.current(); + } - // Check for invalid version strings first. - convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); - convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); + if (version == null) + version = ""; + version = version.trim(); + if (version === "") + version = "latest"; - try { - return (0 === MongoRunner.compareBinVersions(versionA, versionB)); - } catch (err) { - // compareBinVersions() throws an error if two versions differ only by the git hash. - return false; + // See if this version is affected by version substitutions + for (var i = 0; i < MongoRunner.binVersionSubs.length; i++) { + var sub = MongoRunner.binVersionSubs[i]; + if (sub.pattern == version) { + return sub.version; } - }; - - /** - * Compares two version strings and returns: - * 1, if the first is more recent - * 0, if they are equal - * -1, if the first is older - * - * Note that this function only compares up to the length of the shorter version. - * Because of this, minor versions will compare equal to the major versions they stem - * from, but major-major and minor-minor version pairs will undergo strict comparison. - */ - MongoRunner.compareBinVersions = function(versionA, versionB) { - - let stringA = versionA; - let stringB = versionB; - - versionA = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); - versionB = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); - - // Treat the githash as a separate element, if it's present. - versionA.push(...versionA.pop().split("-")); - versionB.push(...versionB.pop().split("-")); + } - var elementsToCompare = Math.min(versionA.length, versionB.length); + return version; +}; + +/** + * Returns true if two version strings could represent the same version. This is true + * if, after passing the versions through getBinVersionFor, the versions have the + * same value for each version component up through the length of the shorter version. + * + * That is, 3.2.4 compares equal to 3.2, but 3.2.4 does not compare equal to 3.2.3. + */ +MongoRunner.areBinVersionsTheSame = function(versionA, versionB) { + // Check for invalid version strings first. + convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); + convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); + + try { + return (0 === MongoRunner.compareBinVersions(versionA, versionB)); + } catch (err) { + // compareBinVersions() throws an error if two versions differ only by the git hash. + return false; + } +}; - for (var i = 0; i < elementsToCompare; ++i) { - var elementA = versionA[i]; - var elementB = versionB[i]; +/** + * Compares two version strings and returns: + * 1, if the first is more recent + * 0, if they are equal + * -1, if the first is older + * + * Note that this function only compares up to the length of the shorter version. + * Because of this, minor versions will compare equal to the major versions they stem + * from, but major-major and minor-minor version pairs will undergo strict comparison. + */ +MongoRunner.compareBinVersions = function(versionA, versionB) { + let stringA = versionA; + let stringB = versionB; - if (elementA === elementB) { - continue; - } + versionA = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionA)); + versionB = convertVersionStringToArray(MongoRunner.getBinVersionFor(versionB)); - var numA = parseInt(elementA); - var numB = parseInt(elementB); + // Treat the githash as a separate element, if it's present. + versionA.push(...versionA.pop().split("-")); + versionB.push(...versionB.pop().split("-")); - assert(!isNaN(numA) && !isNaN(numB), "Cannot compare non-equal non-numeric versions."); + var elementsToCompare = Math.min(versionA.length, versionB.length); - if (numA > numB) { - return 1; - } else if (numA < numB) { - return -1; - } + for (var i = 0; i < elementsToCompare; ++i) { + var elementA = versionA[i]; + var elementB = versionB[i]; - assert(false, `Unreachable case. Provided versions: {${stringA}, ${stringB}}`); + if (elementA === elementB) { + continue; } - return 0; - }; - - MongoRunner.logicalOptions = { - runId: true, - env: true, - pathOpts: true, - remember: true, - noRemember: true, - appendOptions: true, - restart: true, - noCleanData: true, - cleanData: true, - startClean: true, - forceLock: true, - useLogFiles: true, - logFile: true, - useHostName: true, - useHostname: true, - noReplSet: true, - forgetPort: true, - arbiter: true, - noJournal: true, - binVersion: true, - waitForConnect: true, - bridgeOptions: true, - skipValidation: true, - }; + var numA = parseInt(elementA); + var numB = parseInt(elementB); - MongoRunner.toRealPath = function(path, pathOpts) { + assert(!isNaN(numA) && !isNaN(numB), "Cannot compare non-equal non-numeric versions."); - // Replace all $pathOptions with actual values - pathOpts = pathOpts || {}; - path = path.replace(/\$dataPath/g, MongoRunner.dataPath); - path = path.replace(/\$dataDir/g, MongoRunner.dataDir); - for (var key in pathOpts) { - path = path.replace(RegExp("\\$" + RegExp.escape(key), "g"), pathOpts[key]); + if (numA > numB) { + return 1; + } else if (numA < numB) { + return -1; } - // Relative path - // Detect Unix and Windows absolute paths - // as well as Windows drive letters - // Also captures Windows UNC paths + assert(false, `Unreachable case. Provided versions: {${stringA}, ${stringB}}`); + } - if (!path.match(/^(\/|\\|[A-Za-z]:)/)) { - if (path != "" && !path.endsWith("/")) - path += "/"; + return 0; +}; + +MongoRunner.logicalOptions = { + runId: true, + env: true, + pathOpts: true, + remember: true, + noRemember: true, + appendOptions: true, + restart: true, + noCleanData: true, + cleanData: true, + startClean: true, + forceLock: true, + useLogFiles: true, + logFile: true, + useHostName: true, + useHostname: true, + noReplSet: true, + forgetPort: true, + arbiter: true, + noJournal: true, + binVersion: true, + waitForConnect: true, + bridgeOptions: true, + skipValidation: true, +}; + +MongoRunner.toRealPath = function(path, pathOpts) { + // Replace all $pathOptions with actual values + pathOpts = pathOpts || {}; + path = path.replace(/\$dataPath/g, MongoRunner.dataPath); + path = path.replace(/\$dataDir/g, MongoRunner.dataDir); + for (var key in pathOpts) { + path = path.replace(RegExp("\\$" + RegExp.escape(key), "g"), pathOpts[key]); + } - path = MongoRunner.dataPath + path; - } + // Relative path + // Detect Unix and Windows absolute paths + // as well as Windows drive letters + // Also captures Windows UNC paths - return path; + if (!path.match(/^(\/|\\|[A-Za-z]:)/)) { + if (path != "" && !path.endsWith("/")) + path += "/"; - }; + path = MongoRunner.dataPath + path; + } - MongoRunner.toRealDir = function(path, pathOpts) { + return path; +}; - path = MongoRunner.toRealPath(path, pathOpts); +MongoRunner.toRealDir = function(path, pathOpts) { + path = MongoRunner.toRealPath(path, pathOpts); - if (path.endsWith("/")) - path = path.substring(0, path.length - 1); + if (path.endsWith("/")) + path = path.substring(0, path.length - 1); - return path; - }; + return path; +}; - MongoRunner.toRealFile = MongoRunner.toRealDir; +MongoRunner.toRealFile = MongoRunner.toRealDir; - /** - * Returns an iterator object which yields successive versions on calls to advance(), starting - * from a random initial position, from an array of versions. - * - * If passed a single version string or an already-existing version iterator, just returns the - * object itself, since it will yield correctly on calls to advance(). - * - * @param {Array.<String>}|{String}|{versionIterator} - */ - MongoRunner.versionIterator = function(arr, isRandom) { +/** + * Returns an iterator object which yields successive versions on calls to advance(), starting + * from a random initial position, from an array of versions. + * + * If passed a single version string or an already-existing version iterator, just returns the + * object itself, since it will yield correctly on calls to advance(). + * + * @param {Array.<String>}|{String}|{versionIterator} + */ +MongoRunner.versionIterator = function(arr, isRandom) { + // If this isn't an array of versions, or is already an iterator, just use it + if (typeof arr == "string") + return arr; + if (arr.isVersionIterator) + return arr; - // If this isn't an array of versions, or is already an iterator, just use it - if (typeof arr == "string") - return arr; - if (arr.isVersionIterator) - return arr; + if (isRandom == undefined) + isRandom = false; - if (isRandom == undefined) - isRandom = false; + // Starting pos + var i = isRandom ? parseInt(Random.rand() * arr.length) : 0; - // Starting pos - var i = isRandom ? parseInt(Random.rand() * arr.length) : 0; + return new MongoRunner.versionIterator.iterator(i, arr); +}; - return new MongoRunner.versionIterator.iterator(i, arr); +MongoRunner.versionIterator.iterator = function(i, arr) { + if (!Array.isArray(arr)) { + throw new Error("Expected an array for the second argument, but got: " + tojson(arr)); + } + + this.current = function current() { + return arr[i]; }; - MongoRunner.versionIterator.iterator = function(i, arr) { - if (!Array.isArray(arr)) { - throw new Error("Expected an array for the second argument, but got: " + tojson(arr)); - } + // We define the toString() method as an alias for current() so that concatenating a version + // iterator with a string returns the next version in the list without introducing any + // side-effects. + this.toString = this.current; - this.current = function current() { - return arr[i]; - }; + this.advance = function advance() { + i = (i + 1) % arr.length; + }; - // We define the toString() method as an alias for current() so that concatenating a version - // iterator with a string returns the next version in the list without introducing any - // side-effects. - this.toString = this.current; + this.isVersionIterator = true; +}; + +/** + * Converts the args object by pairing all keys with their value and appending + * dash-dash (--) to the keys. The only exception to this rule are keys that + * are defined in MongoRunner.logicalOptions, of which they will be ignored. + * + * @param {string} binaryName + * @param {Object} args + * + * @return {Array.<String>} an array of parameter strings that can be passed + * to the binary. + */ +MongoRunner.arrOptions = function(binaryName, args) { + var fullArgs = [""]; + + // isObject returns true even if "args" is an array, so the else branch of this statement is + // dead code. See SERVER-14220. + if (isObject(args) || (args.length == 1 && isObject(args[0]))) { + var o = isObject(args) ? args : args[0]; + + // If we've specified a particular binary version, use that + if (o.binVersion && o.binVersion != "" && o.binVersion != shellVersion()) { + binaryName += "-" + o.binVersion; + } + + // Manage legacy options + var isValidOptionForBinary = function(option, value) { + if (!o.binVersion) + return true; - this.advance = function advance() { - i = (i + 1) % arr.length; + return true; }; - this.isVersionIterator = true; + var addOptionsToFullArgs = function(k, v) { + if (v === undefined || v === null) + return; - }; + fullArgs.push("--" + k); - /** - * Converts the args object by pairing all keys with their value and appending - * dash-dash (--) to the keys. The only exception to this rule are keys that - * are defined in MongoRunner.logicalOptions, of which they will be ignored. - * - * @param {string} binaryName - * @param {Object} args - * - * @return {Array.<String>} an array of parameter strings that can be passed - * to the binary. - */ - MongoRunner.arrOptions = function(binaryName, args) { - - var fullArgs = [""]; - - // isObject returns true even if "args" is an array, so the else branch of this statement is - // dead code. See SERVER-14220. - if (isObject(args) || (args.length == 1 && isObject(args[0]))) { - var o = isObject(args) ? args : args[0]; - - // If we've specified a particular binary version, use that - if (o.binVersion && o.binVersion != "" && o.binVersion != shellVersion()) { - binaryName += "-" + o.binVersion; + if (v != "") { + fullArgs.push("" + v); } + }; - // Manage legacy options - var isValidOptionForBinary = function(option, value) { - - if (!o.binVersion) - return true; - - return true; - }; - - var addOptionsToFullArgs = function(k, v) { - if (v === undefined || v === null) - return; - - fullArgs.push("--" + k); - - if (v != "") { - fullArgs.push("" + v); - } - }; - - for (var k in o) { - // Make sure our logical option should be added to the array of options - if (!o.hasOwnProperty(k) || k in MongoRunner.logicalOptions || - !isValidOptionForBinary(k, o[k])) - continue; + for (var k in o) { + // Make sure our logical option should be added to the array of options + if (!o.hasOwnProperty(k) || k in MongoRunner.logicalOptions || + !isValidOptionForBinary(k, o[k])) + continue; - if ((k == "v" || k == "verbose") && isNumber(o[k])) { - var n = o[k]; - if (n > 0) { - if (n > 10) - n = 10; - var temp = "-"; - while (n-- > 0) - temp += "v"; - fullArgs.push(temp); - } - } else if (k === "setParameter" && isObject(o[k])) { - // If the value associated with the setParameter option is an object, we want - // to add all key-value pairs in that object as separate --setParameters. - Object.keys(o[k]).forEach(function(paramKey) { - addOptionsToFullArgs(k, "" + paramKey + "=" + o[k][paramKey]); - }); - } else { - addOptionsToFullArgs(k, o[k]); + if ((k == "v" || k == "verbose") && isNumber(o[k])) { + var n = o[k]; + if (n > 0) { + if (n > 10) + n = 10; + var temp = "-"; + while (n-- > 0) + temp += "v"; + fullArgs.push(temp); } + } else if (k === "setParameter" && isObject(o[k])) { + // If the value associated with the setParameter option is an object, we want + // to add all key-value pairs in that object as separate --setParameters. + Object.keys(o[k]).forEach(function(paramKey) { + addOptionsToFullArgs(k, "" + paramKey + "=" + o[k][paramKey]); + }); + } else { + addOptionsToFullArgs(k, o[k]); } - } else { - for (var i = 0; i < args.length; i++) - fullArgs.push(args[i]); } + } else { + for (var i = 0; i < args.length; i++) + fullArgs.push(args[i]); + } - fullArgs[0] = binaryName; - return fullArgs; - }; - - MongoRunner.arrToOpts = function(arr) { + fullArgs[0] = binaryName; + return fullArgs; +}; - var opts = {}; - for (var i = 1; i < arr.length; i++) { - if (arr[i].startsWith("-")) { - var opt = arr[i].replace(/^-/, "").replace(/^-/, ""); +MongoRunner.arrToOpts = function(arr) { + var opts = {}; + for (var i = 1; i < arr.length; i++) { + if (arr[i].startsWith("-")) { + var opt = arr[i].replace(/^-/, "").replace(/^-/, ""); - if (arr.length > i + 1 && !arr[i + 1].startsWith("-")) { - opts[opt] = arr[i + 1]; - i++; - } else { - opts[opt] = ""; - } + if (arr.length > i + 1 && !arr[i + 1].startsWith("-")) { + opts[opt] = arr[i + 1]; + i++; + } else { + opts[opt] = ""; + } - if (opt.replace(/v/g, "") == "") { - opts["verbose"] = opt.length; - } + if (opt.replace(/v/g, "") == "") { + opts["verbose"] = opt.length; } } + } - return opts; - }; + return opts; +}; - MongoRunner.savedOptions = {}; +MongoRunner.savedOptions = {}; - MongoRunner.mongoOptions = function(opts) { - // Don't remember waitForConnect - var waitForConnect = opts.waitForConnect; - delete opts.waitForConnect; +MongoRunner.mongoOptions = function(opts) { + // Don't remember waitForConnect + var waitForConnect = opts.waitForConnect; + delete opts.waitForConnect; - // If we're a mongo object - if (opts.getDB) { - opts = {restart: opts.runId}; - } + // If we're a mongo object + if (opts.getDB) { + opts = {restart: opts.runId}; + } - // Initialize and create a copy of the opts - opts = Object.merge(opts || {}, {}); + // Initialize and create a copy of the opts + opts = Object.merge(opts || {}, {}); - if (!opts.restart) - opts.restart = false; + if (!opts.restart) + opts.restart = false; - // RunId can come from a number of places - // If restart is passed as an old connection - if (opts.restart && opts.restart.getDB) { - opts.runId = opts.restart.runId; - opts.restart = true; - } - // If it's the runId itself - else if (isObject(opts.restart)) { - opts.runId = opts.restart; - opts.restart = true; - } + // RunId can come from a number of places + // If restart is passed as an old connection + if (opts.restart && opts.restart.getDB) { + opts.runId = opts.restart.runId; + opts.restart = true; + } + // If it's the runId itself + else if (isObject(opts.restart)) { + opts.runId = opts.restart; + opts.restart = true; + } - if (isObject(opts.remember)) { - opts.runId = opts.remember; - opts.remember = true; - } else if (opts.remember == undefined) { - // Remember by default if we're restarting - opts.remember = opts.restart; - } + if (isObject(opts.remember)) { + opts.runId = opts.remember; + opts.remember = true; + } else if (opts.remember == undefined) { + // Remember by default if we're restarting + opts.remember = opts.restart; + } - // If we passed in restart : <conn> or runId : <conn> - if (isObject(opts.runId) && opts.runId.runId) - opts.runId = opts.runId.runId; + // If we passed in restart : <conn> or runId : <conn> + if (isObject(opts.runId) && opts.runId.runId) + opts.runId = opts.runId.runId; - if (opts.restart && opts.remember) { - opts = Object.merge(MongoRunner.savedOptions[opts.runId], opts); - } + if (opts.restart && opts.remember) { + opts = Object.merge(MongoRunner.savedOptions[opts.runId], opts); + } - // Create a new runId - opts.runId = opts.runId || ObjectId(); + // Create a new runId + opts.runId = opts.runId || ObjectId(); - if (opts.forgetPort) { - delete opts.port; - } + if (opts.forgetPort) { + delete opts.port; + } - // Normalize and get the binary version to use - if (opts.hasOwnProperty('binVersion')) { - if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { - // Advance the version iterator so that subsequent calls to - // MongoRunner.mongoOptions() use the next version in the list. - const iterator = opts.binVersion; - opts.binVersion = iterator.current(); - iterator.advance(); - } - opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); + // Normalize and get the binary version to use + if (opts.hasOwnProperty('binVersion')) { + if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { + // Advance the version iterator so that subsequent calls to + // MongoRunner.mongoOptions() use the next version in the list. + const iterator = opts.binVersion; + opts.binVersion = iterator.current(); + iterator.advance(); } + opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); + } - // Default for waitForConnect is true - opts.waitForConnect = - (waitForConnect == undefined || waitForConnect == null) ? true : waitForConnect; + // Default for waitForConnect is true + opts.waitForConnect = + (waitForConnect == undefined || waitForConnect == null) ? true : waitForConnect; - opts.port = opts.port || allocatePort(); + opts.port = opts.port || allocatePort(); - opts.pathOpts = - Object.merge(opts.pathOpts || {}, {port: "" + opts.port, runId: "" + opts.runId}); + opts.pathOpts = + Object.merge(opts.pathOpts || {}, {port: "" + opts.port, runId: "" + opts.runId}); - var shouldRemember = - (!opts.restart && !opts.noRemember) || (opts.restart && opts.appendOptions); - if (shouldRemember) { - MongoRunner.savedOptions[opts.runId] = Object.merge(opts, {}); - } + var shouldRemember = + (!opts.restart && !opts.noRemember) || (opts.restart && opts.appendOptions); + if (shouldRemember) { + MongoRunner.savedOptions[opts.runId] = Object.merge(opts, {}); + } - if (jsTestOptions().networkMessageCompressors) { - opts.networkMessageCompressors = jsTestOptions().networkMessageCompressors; - } + if (jsTestOptions().networkMessageCompressors) { + opts.networkMessageCompressors = jsTestOptions().networkMessageCompressors; + } - if (!opts.hasOwnProperty('bind_ip')) { - opts.bind_ip = "0.0.0.0"; - } + if (!opts.hasOwnProperty('bind_ip')) { + opts.bind_ip = "0.0.0.0"; + } - return opts; - }; + return opts; +}; - // Returns an array of integers representing the version provided. - // Ex: "3.3.12" => [3, 3, 12] - var _convertVersionToIntegerArray = function(version) { - var versionParts = - convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); - if (versionParts.length === 2) { - versionParts.push(Infinity); - } - return versionParts; - }; +// Returns an array of integers representing the version provided. +// Ex: "3.3.12" => [3, 3, 12] +var _convertVersionToIntegerArray = function(version) { + var versionParts = + convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); + if (versionParts.length === 2) { + versionParts.push(Infinity); + } + return versionParts; +}; - // Returns if version2 is equal to, or came after, version 1. - var _isMongodVersionEqualOrAfter = function(version1, version2) { - if (version2 === "latest") { - return true; - } +// Returns if version2 is equal to, or came after, version 1. +var _isMongodVersionEqualOrAfter = function(version1, version2) { + if (version2 === "latest") { + return true; + } - var versionParts1 = _convertVersionToIntegerArray(version1); - var versionParts2 = _convertVersionToIntegerArray(version2); - if (versionParts2[0] > versionParts1[0] || - (versionParts2[0] === versionParts1[0] && versionParts2[1] > versionParts1[1]) || - (versionParts2[0] === versionParts1[0] && versionParts2[1] === versionParts1[1] && - versionParts2[2] >= versionParts1[2])) { - return true; - } + var versionParts1 = _convertVersionToIntegerArray(version1); + var versionParts2 = _convertVersionToIntegerArray(version2); + if (versionParts2[0] > versionParts1[0] || + (versionParts2[0] === versionParts1[0] && versionParts2[1] > versionParts1[1]) || + (versionParts2[0] === versionParts1[0] && versionParts2[1] === versionParts1[1] && + versionParts2[2] >= versionParts1[2])) { + return true; + } - return false; - }; + return false; +}; + +// Removes a setParameter parameter from mongods running a version that won't recognize them. +var _removeSetParameterIfBeforeVersion = function(opts, parameterName, requiredVersion) { + var versionCompatible = (opts.binVersion === "" || opts.binVersion === undefined || + _isMongodVersionEqualOrAfter(requiredVersion, opts.binVersion)); + if (!versionCompatible && opts.setParameter && opts.setParameter[parameterName] != undefined) { + print("Removing '" + parameterName + "' setParameter with value " + + opts.setParameter[parameterName] + + " because it isn't compatibile with mongod running version " + opts.binVersion); + delete opts.setParameter[parameterName]; + } +}; + +/** + * @option {object} opts + * + * { + * dbpath {string} + * useLogFiles {boolean}: use with logFile option. + * logFile {string}: path to the log file. If not specified and useLogFiles + * is true, automatically creates a log file inside dbpath. + * noJournal {boolean} + * keyFile + * replSet + * oplogSize + * } + */ +MongoRunner.mongodOptions = function(opts) { + opts = MongoRunner.mongoOptions(opts); + + opts.dbpath = MongoRunner.toRealDir(opts.dbpath || "$dataDir/mongod-$port", opts.pathOpts); + + opts.pathOpts = Object.merge(opts.pathOpts, {dbpath: opts.dbpath}); + + _removeSetParameterIfBeforeVersion(opts, "writePeriodicNoops", "3.3.12"); + _removeSetParameterIfBeforeVersion(opts, "numInitialSyncAttempts", "3.3.12"); + _removeSetParameterIfBeforeVersion(opts, "numInitialSyncConnectAttempts", "3.3.12"); + _removeSetParameterIfBeforeVersion(opts, "migrationLockAcquisitionMaxWaitMS", "4.1.7"); + + if (!opts.logFile && opts.useLogFiles) { + opts.logFile = opts.dbpath + "/mongod.log"; + } else if (opts.logFile) { + opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); + } - // Removes a setParameter parameter from mongods running a version that won't recognize them. - var _removeSetParameterIfBeforeVersion = function(opts, parameterName, requiredVersion) { - var versionCompatible = (opts.binVersion === "" || opts.binVersion === undefined || - _isMongodVersionEqualOrAfter(requiredVersion, opts.binVersion)); - if (!versionCompatible && opts.setParameter && - opts.setParameter[parameterName] != undefined) { - print("Removing '" + parameterName + "' setParameter with value " + - opts.setParameter[parameterName] + - " because it isn't compatibile with mongod running version " + opts.binVersion); - delete opts.setParameter[parameterName]; - } - }; + if (opts.logFile !== undefined) { + opts.logpath = opts.logFile; + } - /** - * @option {object} opts - * - * { - * dbpath {string} - * useLogFiles {boolean}: use with logFile option. - * logFile {string}: path to the log file. If not specified and useLogFiles - * is true, automatically creates a log file inside dbpath. - * noJournal {boolean} - * keyFile - * replSet - * oplogSize - * } - */ - MongoRunner.mongodOptions = function(opts) { - - opts = MongoRunner.mongoOptions(opts); - - opts.dbpath = MongoRunner.toRealDir(opts.dbpath || "$dataDir/mongod-$port", opts.pathOpts); - - opts.pathOpts = Object.merge(opts.pathOpts, {dbpath: opts.dbpath}); - - _removeSetParameterIfBeforeVersion(opts, "writePeriodicNoops", "3.3.12"); - _removeSetParameterIfBeforeVersion(opts, "numInitialSyncAttempts", "3.3.12"); - _removeSetParameterIfBeforeVersion(opts, "numInitialSyncConnectAttempts", "3.3.12"); - _removeSetParameterIfBeforeVersion(opts, "migrationLockAcquisitionMaxWaitMS", "4.1.7"); - - if (!opts.logFile && opts.useLogFiles) { - opts.logFile = opts.dbpath + "/mongod.log"; - } else if (opts.logFile) { - opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); - } + if ((jsTestOptions().noJournal || opts.noJournal) && !('journal' in opts) && + !('configsvr' in opts)) { + opts.nojournal = ""; + } - if (opts.logFile !== undefined) { - opts.logpath = opts.logFile; - } + if (jsTestOptions().keyFile && !opts.keyFile) { + opts.keyFile = jsTestOptions().keyFile; + } - if ((jsTestOptions().noJournal || opts.noJournal) && !('journal' in opts) && - !('configsvr' in opts)) { - opts.nojournal = ""; + if (opts.hasOwnProperty("enableEncryption")) { + // opts.enableEncryption, if set, must be an empty string + if (opts.enableEncryption !== "") { + throw new Error("The enableEncryption option must be an empty string if it is " + + "specified"); } - - if (jsTestOptions().keyFile && !opts.keyFile) { - opts.keyFile = jsTestOptions().keyFile; + } else if (jsTestOptions().enableEncryption !== undefined) { + if (jsTestOptions().enableEncryption !== "") { + throw new Error("The enableEncryption option must be an empty string if it is " + + "specified"); } + opts.enableEncryption = ""; + } - if (opts.hasOwnProperty("enableEncryption")) { - // opts.enableEncryption, if set, must be an empty string - if (opts.enableEncryption !== "") { - throw new Error("The enableEncryption option must be an empty string if it is " + - "specified"); - } - } else if (jsTestOptions().enableEncryption !== undefined) { - if (jsTestOptions().enableEncryption !== "") { - throw new Error("The enableEncryption option must be an empty string if it is " + - "specified"); - } - opts.enableEncryption = ""; + if (opts.hasOwnProperty("encryptionKeyFile")) { + // opts.encryptionKeyFile, if set, must be a string + if (typeof opts.encryptionKeyFile !== "string") { + throw new Error("The encryptionKeyFile option must be a string if it is specified"); } - - if (opts.hasOwnProperty("encryptionKeyFile")) { - // opts.encryptionKeyFile, if set, must be a string - if (typeof opts.encryptionKeyFile !== "string") { - throw new Error("The encryptionKeyFile option must be a string if it is specified"); - } - } else if (jsTestOptions().encryptionKeyFile !== undefined) { - if (typeof(jsTestOptions().encryptionKeyFile) !== "string") { - throw new Error("The encryptionKeyFile option must be a string if it is specified"); - } - opts.encryptionKeyFile = jsTestOptions().encryptionKeyFile; + } else if (jsTestOptions().encryptionKeyFile !== undefined) { + if (typeof (jsTestOptions().encryptionKeyFile) !== "string") { + throw new Error("The encryptionKeyFile option must be a string if it is specified"); } + opts.encryptionKeyFile = jsTestOptions().encryptionKeyFile; + } - if (opts.hasOwnProperty("auditDestination")) { - // opts.auditDestination, if set, must be a string - if (typeof opts.auditDestination !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - } else if (jsTestOptions().auditDestination !== undefined) { - if (typeof(jsTestOptions().auditDestination) !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - opts.auditDestination = jsTestOptions().auditDestination; + if (opts.hasOwnProperty("auditDestination")) { + // opts.auditDestination, if set, must be a string + if (typeof opts.auditDestination !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } - - if (opts.noReplSet) - opts.replSet = null; - if (opts.arbiter) - opts.oplogSize = 1; - - return opts; - }; - - MongoRunner.mongosOptions = function(opts) { - opts = MongoRunner.mongoOptions(opts); - - // Normalize configdb option to be host string if currently a host - if (opts.configdb && opts.configdb.getDB) { - opts.configdb = opts.configdb.host; + } else if (jsTestOptions().auditDestination !== undefined) { + if (typeof (jsTestOptions().auditDestination) !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } + opts.auditDestination = jsTestOptions().auditDestination; + } - opts.pathOpts = - Object.merge(opts.pathOpts, {configdb: opts.configdb.replace(/:|\/|,/g, "-")}); + if (opts.noReplSet) + opts.replSet = null; + if (opts.arbiter) + opts.oplogSize = 1; - if (!opts.logFile && opts.useLogFiles) { - opts.logFile = - MongoRunner.toRealFile("$dataDir/mongos-$configdb-$port.log", opts.pathOpts); - } else if (opts.logFile) { - opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); - } + return opts; +}; - if (opts.logFile !== undefined) { - opts.logpath = opts.logFile; - } +MongoRunner.mongosOptions = function(opts) { + opts = MongoRunner.mongoOptions(opts); - var testOptions = jsTestOptions(); - if (testOptions.keyFile && !opts.keyFile) { - opts.keyFile = testOptions.keyFile; - } + // Normalize configdb option to be host string if currently a host + if (opts.configdb && opts.configdb.getDB) { + opts.configdb = opts.configdb.host; + } - if (opts.hasOwnProperty("auditDestination")) { - // opts.auditDestination, if set, must be a string - if (typeof opts.auditDestination !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - } else if (testOptions.auditDestination !== undefined) { - if (typeof(testOptions.auditDestination) !== "string") { - throw new Error("The auditDestination option must be a string if it is specified"); - } - opts.auditDestination = testOptions.auditDestination; - } + opts.pathOpts = Object.merge(opts.pathOpts, {configdb: opts.configdb.replace(/:|\/|,/g, "-")}); - if (!opts.hasOwnProperty('binVersion') && testOptions.mongosBinVersion) { - opts.binVersion = MongoRunner.getBinVersionFor(testOptions.mongosBinVersion); - } - - // If the mongos is being restarted with a newer version, make sure we remove any options - // that no longer exist in the newer version. - if (opts.restart && MongoRunner.areBinVersionsTheSame('latest', opts.binVersion)) { - delete opts.noAutoSplit; - } + if (!opts.logFile && opts.useLogFiles) { + opts.logFile = MongoRunner.toRealFile("$dataDir/mongos-$configdb-$port.log", opts.pathOpts); + } else if (opts.logFile) { + opts.logFile = MongoRunner.toRealFile(opts.logFile, opts.pathOpts); + } - return opts; - }; + if (opts.logFile !== undefined) { + opts.logpath = opts.logFile; + } - /** - * Starts a mongod instance. - * - * @param {Object} opts - * - * { - * useHostName {boolean}: Uses hostname of machine if true. - * forceLock {boolean}: Deletes the lock file if set to true. - * dbpath {string}: location of db files. - * cleanData {boolean}: Removes all files in dbpath if true. - * startClean {boolean}: same as cleanData. - * noCleanData {boolean}: Do not clean files (cleanData takes priority). - * binVersion {string}: version for binary (also see MongoRunner.binVersionSubs). - * - * @see MongoRunner.mongodOptions for other options - * } - * - * @return {Mongo} connection object to the started mongod instance. - * - * @see MongoRunner.arrOptions - */ - MongoRunner.runMongod = function(opts) { - - opts = opts || {}; - var env = undefined; - var useHostName = true; - var runId = null; - var waitForConnect = true; - var fullOptions = opts; - - if (isObject(opts)) { - opts = MongoRunner.mongodOptions(opts); - fullOptions = opts; - - if (opts.useHostName != undefined) { - useHostName = opts.useHostName; - } else if (opts.useHostname != undefined) { - useHostName = opts.useHostname; - } else { - useHostName = true; // Default to true - } - env = opts.env; - runId = opts.runId; - waitForConnect = opts.waitForConnect; - - if (opts.forceLock) - removeFile(opts.dbpath + "/mongod.lock"); - if ((opts.cleanData || opts.startClean) || (!opts.restart && !opts.noCleanData)) { - print("Resetting db path '" + opts.dbpath + "'"); - resetDbpath(opts.dbpath); - } + var testOptions = jsTestOptions(); + if (testOptions.keyFile && !opts.keyFile) { + opts.keyFile = testOptions.keyFile; + } - var mongodProgram = MongoRunner.mongodPath; - opts = MongoRunner.arrOptions(mongodProgram, opts); + if (opts.hasOwnProperty("auditDestination")) { + // opts.auditDestination, if set, must be a string + if (typeof opts.auditDestination !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } - - var mongod = MongoRunner._startWithArgs(opts, env, waitForConnect); - if (!mongod) { - return null; + } else if (testOptions.auditDestination !== undefined) { + if (typeof (testOptions.auditDestination) !== "string") { + throw new Error("The auditDestination option must be a string if it is specified"); } + opts.auditDestination = testOptions.auditDestination; + } - mongod.commandLine = MongoRunner.arrToOpts(opts); - mongod.name = (useHostName ? getHostName() : "localhost") + ":" + mongod.commandLine.port; - mongod.host = mongod.name; - mongod.port = parseInt(mongod.commandLine.port); - mongod.runId = runId || ObjectId(); - mongod.dbpath = fullOptions.dbpath; - mongod.savedOptions = MongoRunner.savedOptions[mongod.runId]; - mongod.fullOptions = fullOptions; + if (!opts.hasOwnProperty('binVersion') && testOptions.mongosBinVersion) { + opts.binVersion = MongoRunner.getBinVersionFor(testOptions.mongosBinVersion); + } - return mongod; - }; + // If the mongos is being restarted with a newer version, make sure we remove any options + // that no longer exist in the newer version. + if (opts.restart && MongoRunner.areBinVersionsTheSame('latest', opts.binVersion)) { + delete opts.noAutoSplit; + } - MongoRunner.runMongos = function(opts) { - opts = opts || {}; - - var env = undefined; - var useHostName = false; - var runId = null; - var waitForConnect = true; - var fullOptions = opts; - - if (isObject(opts)) { - opts = MongoRunner.mongosOptions(opts); - fullOptions = opts; - - useHostName = opts.useHostName || opts.useHostname; - runId = opts.runId; - waitForConnect = opts.waitForConnect; - env = opts.env; - var mongosProgram = MongoRunner.mongosPath; - opts = MongoRunner.arrOptions(mongosProgram, opts); + return opts; +}; + +/** + * Starts a mongod instance. + * + * @param {Object} opts + * + * { + * useHostName {boolean}: Uses hostname of machine if true. + * forceLock {boolean}: Deletes the lock file if set to true. + * dbpath {string}: location of db files. + * cleanData {boolean}: Removes all files in dbpath if true. + * startClean {boolean}: same as cleanData. + * noCleanData {boolean}: Do not clean files (cleanData takes priority). + * binVersion {string}: version for binary (also see MongoRunner.binVersionSubs). + * + * @see MongoRunner.mongodOptions for other options + * } + * + * @return {Mongo} connection object to the started mongod instance. + * + * @see MongoRunner.arrOptions + */ +MongoRunner.runMongod = function(opts) { + opts = opts || {}; + var env = undefined; + var useHostName = true; + var runId = null; + var waitForConnect = true; + var fullOptions = opts; + + if (isObject(opts)) { + opts = MongoRunner.mongodOptions(opts); + fullOptions = opts; + + if (opts.useHostName != undefined) { + useHostName = opts.useHostName; + } else if (opts.useHostname != undefined) { + useHostName = opts.useHostname; + } else { + useHostName = true; // Default to true } + env = opts.env; + runId = opts.runId; + waitForConnect = opts.waitForConnect; - var mongos = MongoRunner._startWithArgs(opts, env, waitForConnect); - if (!mongos) { - return null; + if (opts.forceLock) + removeFile(opts.dbpath + "/mongod.lock"); + if ((opts.cleanData || opts.startClean) || (!opts.restart && !opts.noCleanData)) { + print("Resetting db path '" + opts.dbpath + "'"); + resetDbpath(opts.dbpath); } - mongos.commandLine = MongoRunner.arrToOpts(opts); - mongos.name = (useHostName ? getHostName() : "localhost") + ":" + mongos.commandLine.port; - mongos.host = mongos.name; - mongos.port = parseInt(mongos.commandLine.port); - mongos.runId = runId || ObjectId(); - mongos.savedOptions = MongoRunner.savedOptions[mongos.runId]; - mongos.fullOptions = fullOptions; - - return mongos; - }; + var mongodProgram = MongoRunner.mongodPath; + opts = MongoRunner.arrOptions(mongodProgram, opts); + } - MongoRunner.StopError = function(returnCode) { - this.name = "StopError"; - this.returnCode = returnCode; - this.message = "MongoDB process stopped with exit code: " + this.returnCode; - this.stack = this.toString() + "\n" + (new Error()).stack; - }; + var mongod = MongoRunner._startWithArgs(opts, env, waitForConnect); + if (!mongod) { + return null; + } - MongoRunner.StopError.prototype = Object.create(Error.prototype); - MongoRunner.StopError.prototype.constructor = MongoRunner.StopError; - - // Constants for exit codes of MongoDB processes - MongoRunner.EXIT_ABORT = -6; - MongoRunner.EXIT_CLEAN = 0; - MongoRunner.EXIT_BADOPTIONS = 2; - MongoRunner.EXIT_REPLICATION_ERROR = 3; - MongoRunner.EXIT_NEED_UPGRADE = 4; - MongoRunner.EXIT_SHARDING_ERROR = 5; - // SIGKILL is translated to TerminateProcess() on Windows, which causes the program to - // terminate with exit code 1. - MongoRunner.EXIT_SIGKILL = _isWindows() ? 1 : -9; - MongoRunner.EXIT_KILL = 12; - MongoRunner.EXIT_ABRUPT = 14; - MongoRunner.EXIT_NTSERVICE_ERROR = 20; - MongoRunner.EXIT_JAVA = 21; - MongoRunner.EXIT_OOM_MALLOC = 42; - MongoRunner.EXIT_OOM_REALLOC = 43; - MongoRunner.EXIT_FS = 45; - MongoRunner.EXIT_CLOCK_SKEW = 47; // OpTime clock skew; deprecated - MongoRunner.EXIT_NET_ERROR = 48; - MongoRunner.EXIT_WINDOWS_SERVICE_STOP = 49; - MongoRunner.EXIT_POSSIBLE_CORRUPTION = 60; - MongoRunner.EXIT_NEED_DOWNGRADE = 62; - MongoRunner.EXIT_UNCAUGHT = 100; // top level exception that wasn't caught - MongoRunner.EXIT_TEST = 101; - - MongoRunner.validateCollectionsCallback = function(port) {}; - - /** - * Kills a mongod process. - * - * @param {Mongo} conn the connection object to the process to kill - * @param {number} signal The signal number to use for killing - * @param {Object} opts Additional options. Format: - * { - * auth: { - * user {string}: admin user name - * pwd {string}: admin password - * }, - * skipValidation: <bool>, - * allowedExitCode: <int> - * } - * - * Note: The auth option is required in a authenticated mongod running in Windows since - * it uses the shutdown command, which requires admin credentials. - */ - MongoRunner.stopMongod = function(conn, signal, opts) { - if (!conn.pid) { - throw new Error("first arg must have a `pid` property; " + - "it is usually the object returned from MongoRunner.runMongod/s"); - } + mongod.commandLine = MongoRunner.arrToOpts(opts); + mongod.name = (useHostName ? getHostName() : "localhost") + ":" + mongod.commandLine.port; + mongod.host = mongod.name; + mongod.port = parseInt(mongod.commandLine.port); + mongod.runId = runId || ObjectId(); + mongod.dbpath = fullOptions.dbpath; + mongod.savedOptions = MongoRunner.savedOptions[mongod.runId]; + mongod.fullOptions = fullOptions; + + return mongod; +}; + +MongoRunner.runMongos = function(opts) { + opts = opts || {}; + + var env = undefined; + var useHostName = false; + var runId = null; + var waitForConnect = true; + var fullOptions = opts; + + if (isObject(opts)) { + opts = MongoRunner.mongosOptions(opts); + fullOptions = opts; + + useHostName = opts.useHostName || opts.useHostname; + runId = opts.runId; + waitForConnect = opts.waitForConnect; + env = opts.env; + var mongosProgram = MongoRunner.mongosPath; + opts = MongoRunner.arrOptions(mongosProgram, opts); + } - if (!conn.port) { - throw new Error("first arg must have a `port` property; " + - "it is usually the object returned from MongoRunner.runMongod/s"); - } + var mongos = MongoRunner._startWithArgs(opts, env, waitForConnect); + if (!mongos) { + return null; + } - signal = parseInt(signal) || 15; - opts = opts || {}; + mongos.commandLine = MongoRunner.arrToOpts(opts); + mongos.name = (useHostName ? getHostName() : "localhost") + ":" + mongos.commandLine.port; + mongos.host = mongos.name; + mongos.port = parseInt(mongos.commandLine.port); + mongos.runId = runId || ObjectId(); + mongos.savedOptions = MongoRunner.savedOptions[mongos.runId]; + mongos.fullOptions = fullOptions; + + return mongos; +}; + +MongoRunner.StopError = function(returnCode) { + this.name = "StopError"; + this.returnCode = returnCode; + this.message = "MongoDB process stopped with exit code: " + this.returnCode; + this.stack = this.toString() + "\n" + (new Error()).stack; +}; + +MongoRunner.StopError.prototype = Object.create(Error.prototype); +MongoRunner.StopError.prototype.constructor = MongoRunner.StopError; + +// Constants for exit codes of MongoDB processes +MongoRunner.EXIT_ABORT = -6; +MongoRunner.EXIT_CLEAN = 0; +MongoRunner.EXIT_BADOPTIONS = 2; +MongoRunner.EXIT_REPLICATION_ERROR = 3; +MongoRunner.EXIT_NEED_UPGRADE = 4; +MongoRunner.EXIT_SHARDING_ERROR = 5; +// SIGKILL is translated to TerminateProcess() on Windows, which causes the program to +// terminate with exit code 1. +MongoRunner.EXIT_SIGKILL = _isWindows() ? 1 : -9; +MongoRunner.EXIT_KILL = 12; +MongoRunner.EXIT_ABRUPT = 14; +MongoRunner.EXIT_NTSERVICE_ERROR = 20; +MongoRunner.EXIT_JAVA = 21; +MongoRunner.EXIT_OOM_MALLOC = 42; +MongoRunner.EXIT_OOM_REALLOC = 43; +MongoRunner.EXIT_FS = 45; +MongoRunner.EXIT_CLOCK_SKEW = 47; // OpTime clock skew; deprecated +MongoRunner.EXIT_NET_ERROR = 48; +MongoRunner.EXIT_WINDOWS_SERVICE_STOP = 49; +MongoRunner.EXIT_POSSIBLE_CORRUPTION = 60; +MongoRunner.EXIT_NEED_DOWNGRADE = 62; +MongoRunner.EXIT_UNCAUGHT = 100; // top level exception that wasn't caught +MongoRunner.EXIT_TEST = 101; + +MongoRunner.validateCollectionsCallback = function(port) {}; + +/** + * Kills a mongod process. + * + * @param {Mongo} conn the connection object to the process to kill + * @param {number} signal The signal number to use for killing + * @param {Object} opts Additional options. Format: + * { + * auth: { + * user {string}: admin user name + * pwd {string}: admin password + * }, + * skipValidation: <bool>, + * allowedExitCode: <int> + * } + * + * Note: The auth option is required in a authenticated mongod running in Windows since + * it uses the shutdown command, which requires admin credentials. + */ +MongoRunner.stopMongod = function(conn, signal, opts) { + if (!conn.pid) { + throw new Error("first arg must have a `pid` property; " + + "it is usually the object returned from MongoRunner.runMongod/s"); + } - var allowedExitCode = MongoRunner.EXIT_CLEAN; + if (!conn.port) { + throw new Error("first arg must have a `port` property; " + + "it is usually the object returned from MongoRunner.runMongod/s"); + } - if (opts.allowedExitCode) { - allowedExitCode = opts.allowedExitCode; - } + signal = parseInt(signal) || 15; + opts = opts || {}; - var port = parseInt(conn.port); + var allowedExitCode = MongoRunner.EXIT_CLEAN; - var pid = conn.pid; - // If the return code is in the serverExitCodeMap, it means the server crashed on startup. - // We just use the recorded return code instead of stopping the program. - var returnCode; - if (serverExitCodeMap.hasOwnProperty(port)) { - returnCode = serverExitCodeMap[port]; - delete serverExitCodeMap[port]; - } else { - // Invoke callback to validate collections and indexes before shutting down mongod. - // We skip calling the callback function when the expected return code of - // the mongod process is non-zero since it's likely the process has already exited. + if (opts.allowedExitCode) { + allowedExitCode = opts.allowedExitCode; + } - var skipValidation = false; - if (opts.skipValidation) { - skipValidation = true; - } + var port = parseInt(conn.port); - if (allowedExitCode === MongoRunner.EXIT_CLEAN && !skipValidation) { - MongoRunner.validateCollectionsCallback(port); - } + var pid = conn.pid; + // If the return code is in the serverExitCodeMap, it means the server crashed on startup. + // We just use the recorded return code instead of stopping the program. + var returnCode; + if (serverExitCodeMap.hasOwnProperty(port)) { + returnCode = serverExitCodeMap[port]; + delete serverExitCodeMap[port]; + } else { + // Invoke callback to validate collections and indexes before shutting down mongod. + // We skip calling the callback function when the expected return code of + // the mongod process is non-zero since it's likely the process has already exited. - returnCode = _stopMongoProgram(port, signal, opts); + var skipValidation = false; + if (opts.skipValidation) { + skipValidation = true; } - if (allowedExitCode !== returnCode) { - throw new MongoRunner.StopError(returnCode); - } else if (returnCode !== MongoRunner.EXIT_CLEAN) { - print("MongoDB process on port " + port + " intentionally exited with error code ", - returnCode); + + if (allowedExitCode === MongoRunner.EXIT_CLEAN && !skipValidation) { + MongoRunner.validateCollectionsCallback(port); } - return returnCode; - }; + returnCode = _stopMongoProgram(port, signal, opts); + } + if (allowedExitCode !== returnCode) { + throw new MongoRunner.StopError(returnCode); + } else if (returnCode !== MongoRunner.EXIT_CLEAN) { + print("MongoDB process on port " + port + " intentionally exited with error code ", + returnCode); + } - MongoRunner.stopMongos = MongoRunner.stopMongod; - - /** - * Starts an instance of the specified mongo tool - * - * @param {String} binaryName - The name of the tool to run. - * @param {Object} [opts={}] - Options of the form --flag or --key=value to pass to the tool. - * @param {string} [opts.binVersion] - The version of the tool to run. - * - * @param {...string} positionalArgs - Positional arguments to pass to the tool after all - * options have been specified. For example, - * MongoRunner.runMongoTool("executable", {key: value}, arg1, arg2) would invoke - * ./executable --key value arg1 arg2. - * - * @see MongoRunner.arrOptions - */ - MongoRunner.runMongoTool = function(binaryName, opts, ...positionalArgs) { - - var opts = opts || {}; - - // Normalize and get the binary version to use - if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { - // Advance the version iterator so that subsequent calls to MongoRunner.runMongoTool() - // use the next version in the list. - const iterator = opts.binVersion; - opts.binVersion = iterator.current(); - iterator.advance(); - } - opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); + return returnCode; +}; + +MongoRunner.stopMongos = MongoRunner.stopMongod; + +/** + * Starts an instance of the specified mongo tool + * + * @param {String} binaryName - The name of the tool to run. + * @param {Object} [opts={}] - Options of the form --flag or --key=value to pass to the tool. + * @param {string} [opts.binVersion] - The version of the tool to run. + * + * @param {...string} positionalArgs - Positional arguments to pass to the tool after all + * options have been specified. For example, + * MongoRunner.runMongoTool("executable", {key: value}, arg1, arg2) would invoke + * ./executable --key value arg1 arg2. + * + * @see MongoRunner.arrOptions + */ +MongoRunner.runMongoTool = function(binaryName, opts, ...positionalArgs) { + var opts = opts || {}; + + // Normalize and get the binary version to use + if (opts.binVersion instanceof MongoRunner.versionIterator.iterator) { + // Advance the version iterator so that subsequent calls to MongoRunner.runMongoTool() + // use the next version in the list. + const iterator = opts.binVersion; + opts.binVersion = iterator.current(); + iterator.advance(); + } + opts.binVersion = MongoRunner.getBinVersionFor(opts.binVersion); - // Recent versions of the mongo tools support a --dialTimeout flag to set for how - // long they retry connecting to a mongod or mongos process. We have them retry - // connecting for up to 30 seconds to handle when the tests are run on a - // resource-constrained host machine. - // - // The bsondump tool doesn't accept the --dialTimeout flag because it doesn't connect to a - // mongod or mongos process. - if (!opts.hasOwnProperty('dialTimeout') && binaryName !== 'bsondump' && - _toolVersionSupportsDialTimeout(opts.binVersion)) { - opts['dialTimeout'] = '30'; - } + // Recent versions of the mongo tools support a --dialTimeout flag to set for how + // long they retry connecting to a mongod or mongos process. We have them retry + // connecting for up to 30 seconds to handle when the tests are run on a + // resource-constrained host machine. + // + // The bsondump tool doesn't accept the --dialTimeout flag because it doesn't connect to a + // mongod or mongos process. + if (!opts.hasOwnProperty('dialTimeout') && binaryName !== 'bsondump' && + _toolVersionSupportsDialTimeout(opts.binVersion)) { + opts['dialTimeout'] = '30'; + } - // Convert 'opts' into an array of arguments. - var argsArray = MongoRunner.arrOptions(binaryName, opts); + // Convert 'opts' into an array of arguments. + var argsArray = MongoRunner.arrOptions(binaryName, opts); - // Append any positional arguments that were specified. - argsArray.push(...positionalArgs); + // Append any positional arguments that were specified. + argsArray.push(...positionalArgs); - return runMongoProgram.apply(null, argsArray); + return runMongoProgram.apply(null, argsArray); +}; - }; +var _toolVersionSupportsDialTimeout = function(version) { + if (version === "latest" || version === "") { + return true; + } + var versionParts = + convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); + if (versionParts.length === 2) { + versionParts.push(Infinity); + } - var _toolVersionSupportsDialTimeout = function(version) { - if (version === "latest" || version === "") { - return true; - } - var versionParts = - convertVersionStringToArray(version).slice(0, 3).map(part => parseInt(part, 10)); - if (versionParts.length === 2) { - versionParts.push(Infinity); - } + if (versionParts[0] > 3 || (versionParts[0] === 3 && versionParts[1] > 3)) { + // The --dialTimeout command line option is supported by the tools + // with a major version newer than 3.3. + return true; + } - if (versionParts[0] > 3 || (versionParts[0] === 3 && versionParts[1] > 3)) { - // The --dialTimeout command line option is supported by the tools - // with a major version newer than 3.3. + for (var supportedVersion of ["3.3.4", "3.2.5", "3.0.12"]) { + var supportedVersionParts = convertVersionStringToArray(supportedVersion) + .slice(0, 3) + .map(part => parseInt(part, 10)); + if (versionParts[0] === supportedVersionParts[0] && + versionParts[1] === supportedVersionParts[1] && + versionParts[2] >= supportedVersionParts[2]) { return true; } + } + return false; +}; + +// Given a test name figures out a directory for that test to use for dump files and makes sure +// that directory exists and is empty. +MongoRunner.getAndPrepareDumpDirectory = function(testName) { + var dir = MongoRunner.dataPath + testName + "_external/"; + resetDbpath(dir); + return dir; +}; + +// Start a mongod instance and return a 'Mongo' object connected to it. +// This function's arguments are passed as command line arguments to mongod. +// The specified 'dbpath' is cleared if it exists, created if not. +// var conn = _startMongodEmpty("--port", 30000, "--dbpath", "asdf"); +var _startMongodEmpty = function() { + var args = createMongoArgs("mongod", Array.from(arguments)); + + var dbpath = _parsePath.apply(null, args); + resetDbpath(dbpath); + + return startMongoProgram.apply(null, args); +}; + +_startMongod = function() { + print("startMongod WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING ONLY"); + return _startMongodEmpty.apply(null, arguments); +}; + +/** + * Returns a new argArray with any test-specific arguments added. + */ +function appendSetParameterArgs(argArray) { + function argArrayContains(key) { + return (argArray + .filter((val) => { + return typeof val === "string" && val.indexOf(key) === 0; + }) + .length > 0); + } - for (var supportedVersion of["3.3.4", "3.2.5", "3.0.12"]) { - var supportedVersionParts = convertVersionStringToArray(supportedVersion) - .slice(0, 3) - .map(part => parseInt(part, 10)); - if (versionParts[0] === supportedVersionParts[0] && - versionParts[1] === supportedVersionParts[1] && - versionParts[2] >= supportedVersionParts[2]) { - return true; - } - } - return false; - }; - - // Given a test name figures out a directory for that test to use for dump files and makes sure - // that directory exists and is empty. - MongoRunner.getAndPrepareDumpDirectory = function(testName) { - var dir = MongoRunner.dataPath + testName + "_external/"; - resetDbpath(dir); - return dir; - }; - - // Start a mongod instance and return a 'Mongo' object connected to it. - // This function's arguments are passed as command line arguments to mongod. - // The specified 'dbpath' is cleared if it exists, created if not. - // var conn = _startMongodEmpty("--port", 30000, "--dbpath", "asdf"); - var _startMongodEmpty = function() { - var args = createMongoArgs("mongod", Array.from(arguments)); - - var dbpath = _parsePath.apply(null, args); - resetDbpath(dbpath); + function argArrayContainsSetParameterValue(value) { + assert(value.endsWith("="), "Expected value argument to be of the form <parameterName>="); + return argArray.some(function(el) { + return typeof el === "string" && el.startsWith(value); + }); + } - return startMongoProgram.apply(null, args); - }; + // programName includes the version, e.g., mongod-3.2. + // baseProgramName is the program name without any version information, e.g., mongod. + let programName = argArray[0]; - _startMongod = function() { - print("startMongod WARNING DELETES DATA DIRECTORY THIS IS FOR TESTING ONLY"); - return _startMongodEmpty.apply(null, arguments); - }; + let [baseProgramName, programVersion] = programName.split("-"); + let programMajorMinorVersion = 0; + if (programVersion) { + let [major, minor, point] = programVersion.split("."); + programMajorMinorVersion = parseInt(major) * 100 + parseInt(minor); + } - /** - * Returns a new argArray with any test-specific arguments added. - */ - function appendSetParameterArgs(argArray) { - function argArrayContains(key) { - return (argArray - .filter((val) => { - return typeof val === "string" && val.indexOf(key) === 0; - }) - .length > 0); + if (baseProgramName === 'mongod' || baseProgramName === 'mongos') { + if (jsTest.options().enableTestCommands) { + argArray.push(...['--setParameter', "enableTestCommands=1"]); } - - function argArrayContainsSetParameterValue(value) { - assert(value.endsWith("="), - "Expected value argument to be of the form <parameterName>="); - return argArray.some(function(el) { - return typeof el === "string" && el.startsWith(value); - }); + if (jsTest.options().authMechanism && jsTest.options().authMechanism != "SCRAM-SHA-1") { + if (!argArrayContainsSetParameterValue('authenticationMechanisms=')) { + argArray.push(...['--setParameter', + "authenticationMechanisms=" + jsTest.options().authMechanism]); + } } - - // programName includes the version, e.g., mongod-3.2. - // baseProgramName is the program name without any version information, e.g., mongod. - let programName = argArray[0]; - - let [baseProgramName, programVersion] = programName.split("-"); - let programMajorMinorVersion = 0; - if (programVersion) { - let [major, minor, point] = programVersion.split("."); - programMajorMinorVersion = parseInt(major) * 100 + parseInt(minor); + if (jsTest.options().auth) { + argArray.push(...['--setParameter', "enableLocalhostAuthBypass=false"]); } - if (baseProgramName === 'mongod' || baseProgramName === 'mongos') { - if (jsTest.options().enableTestCommands) { - argArray.push(...['--setParameter', "enableTestCommands=1"]); - } - if (jsTest.options().authMechanism && jsTest.options().authMechanism != "SCRAM-SHA-1") { - if (!argArrayContainsSetParameterValue('authenticationMechanisms=')) { - argArray.push( - ...['--setParameter', - "authenticationMechanisms=" + jsTest.options().authMechanism]); + // New options in 3.5.x + if (!programMajorMinorVersion || programMajorMinorVersion >= 305) { + if (jsTest.options().serviceExecutor) { + if (!argArrayContains("--serviceExecutor")) { + argArray.push(...["--serviceExecutor", jsTest.options().serviceExecutor]); } } - if (jsTest.options().auth) { - argArray.push(...['--setParameter', "enableLocalhostAuthBypass=false"]); + + if (jsTest.options().transportLayer) { + if (!argArrayContains("--transportLayer")) { + argArray.push(...["--transportLayer", jsTest.options().transportLayer]); + } } - // New options in 3.5.x - if (!programMajorMinorVersion || programMajorMinorVersion >= 305) { - if (jsTest.options().serviceExecutor) { - if (!argArrayContains("--serviceExecutor")) { - argArray.push(...["--serviceExecutor", jsTest.options().serviceExecutor]); + // Disable background cache refreshing to avoid races in tests + argArray.push(...['--setParameter', "disableLogicalSessionCacheRefresh=true"]); + } + + // Since options may not be backward compatible, mongos options are not + // set on older versions, e.g., mongos-3.0. + if (programName.endsWith('mongos')) { + // apply setParameters for mongos + if (jsTest.options().setParametersMongos) { + let params = jsTest.options().setParametersMongos; + for (let paramName of Object.keys(params)) { + // Only set the 'logComponentVerbosity' parameter if it has not already + // been specified in the given argument array. This means that any + // 'logComponentVerbosity' settings passed through via TestData will + // always be overridden by settings passed directly to MongoRunner from + // within the shell. + if (paramName === "logComponentVerbosity" && + argArrayContains("logComponentVerbosity")) { + continue; } + const paramVal = ((param) => { + if (typeof param === "object") { + return JSON.stringify(param); + } + + return param; + })(params[paramName]); + const setParamStr = paramName + "=" + paramVal; + argArray.push(...['--setParameter', setParamStr]); + } + } + } else if (baseProgramName === 'mongod') { + if (jsTestOptions().roleGraphInvalidationIsFatal) { + argArray.push(...['--setParameter', "roleGraphInvalidationIsFatal=true"]); + } + + // Set storageEngine for mongod. There was no storageEngine parameter before 3.0. + if (jsTest.options().storageEngine && + (!programVersion || programMajorMinorVersion >= 300)) { + if (!argArrayContains("--storageEngine")) { + argArray.push(...['--storageEngine', jsTest.options().storageEngine]); } + } - if (jsTest.options().transportLayer) { - if (!argArrayContains("--transportLayer")) { - argArray.push(...["--transportLayer", jsTest.options().transportLayer]); + // New mongod-specific options in 4.0.x + if (!programMajorMinorVersion || programMajorMinorVersion >= 400) { + if (jsTest.options().transactionLifetimeLimitSeconds !== undefined) { + if (!argArrayContainsSetParameterValue("transactionLifetimeLimitSeconds=")) { + argArray.push(...["--setParameter", + "transactionLifetimeLimitSeconds=" + + jsTest.options().transactionLifetimeLimitSeconds]); } } + } - // Disable background cache refreshing to avoid races in tests - argArray.push(...['--setParameter', "disableLogicalSessionCacheRefresh=true"]); + // TODO: Make this unconditional in 3.8. + if (!programMajorMinorVersion || programMajorMinorVersion > 304) { + if (!argArrayContainsSetParameterValue('orphanCleanupDelaySecs=')) { + argArray.push(...['--setParameter', 'orphanCleanupDelaySecs=1']); + } } - // Since options may not be backward compatible, mongos options are not - // set on older versions, e.g., mongos-3.0. - if (programName.endsWith('mongos')) { - // apply setParameters for mongos - if (jsTest.options().setParametersMongos) { - let params = jsTest.options().setParametersMongos; + // Since options may not be backward compatible, mongod options are not + // set on older versions, e.g., mongod-3.0. + if (programName.endsWith('mongod')) { + if (jsTest.options().storageEngine === "wiredTiger" || + !jsTest.options().storageEngine) { + if (jsTest.options().enableMajorityReadConcern !== undefined && + !argArrayContains("--enableMajorityReadConcern")) { + argArray.push(...['--enableMajorityReadConcern', + jsTest.options().enableMajorityReadConcern.toString()]); + } + if (jsTest.options().storageEngineCacheSizeGB && + !argArrayContains('--wiredTigerCacheSizeGB')) { + argArray.push(...['--wiredTigerCacheSizeGB', + jsTest.options().storageEngineCacheSizeGB]); + } + if (jsTest.options().wiredTigerEngineConfigString && + !argArrayContains('--wiredTigerEngineConfigString')) { + argArray.push(...['--wiredTigerEngineConfigString', + jsTest.options().wiredTigerEngineConfigString]); + } + if (jsTest.options().wiredTigerCollectionConfigString && + !argArrayContains('--wiredTigerCollectionConfigString')) { + argArray.push(...['--wiredTigerCollectionConfigString', + jsTest.options().wiredTigerCollectionConfigString]); + } + if (jsTest.options().wiredTigerIndexConfigString && + !argArrayContains('--wiredTigerIndexConfigString')) { + argArray.push(...['--wiredTigerIndexConfigString', + jsTest.options().wiredTigerIndexConfigString]); + } + } else if (jsTest.options().storageEngine === "rocksdb") { + if (jsTest.options().storageEngineCacheSizeGB) { + argArray.push( + ...['--rocksdbCacheSizeGB', jsTest.options().storageEngineCacheSizeGB]); + } + } else if (jsTest.options().storageEngine === "inMemory") { + if (jsTest.options().storageEngineCacheSizeGB && + !argArrayContains("--inMemorySizeGB")) { + argArray.push( + ...["--inMemorySizeGB", jsTest.options().storageEngineCacheSizeGB]); + } + } + // apply setParameters for mongod. The 'setParameters' field should be given as + // a plain JavaScript object, where each key is a parameter name and the value + // is the value to set for that parameter. + if (jsTest.options().setParameters) { + let params = jsTest.options().setParameters; for (let paramName of Object.keys(params)) { // Only set the 'logComponentVerbosity' parameter if it has not already // been specified in the given argument array. This means that any @@ -1118,6 +1198,7 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro argArrayContains("logComponentVerbosity")) { continue; } + const paramVal = ((param) => { if (typeof param === "object") { return JSON.stringify(param); @@ -1129,261 +1210,157 @@ var MongoRunner, _startMongod, startMongoProgram, runMongoProgram, startMongoPro argArray.push(...['--setParameter', setParamStr]); } } - } else if (baseProgramName === 'mongod') { - if (jsTestOptions().roleGraphInvalidationIsFatal) { - argArray.push(...['--setParameter', "roleGraphInvalidationIsFatal=true"]); - } - - // Set storageEngine for mongod. There was no storageEngine parameter before 3.0. - if (jsTest.options().storageEngine && - (!programVersion || programMajorMinorVersion >= 300)) { - if (!argArrayContains("--storageEngine")) { - argArray.push(...['--storageEngine', jsTest.options().storageEngine]); - } - } - - // New mongod-specific options in 4.0.x - if (!programMajorMinorVersion || programMajorMinorVersion >= 400) { - if (jsTest.options().transactionLifetimeLimitSeconds !== undefined) { - if (!argArrayContainsSetParameterValue( - "transactionLifetimeLimitSeconds=")) { - argArray.push( - ...["--setParameter", - "transactionLifetimeLimitSeconds=" + - jsTest.options().transactionLifetimeLimitSeconds]); - } - } - } - - // TODO: Make this unconditional in 3.8. - if (!programMajorMinorVersion || programMajorMinorVersion > 304) { - if (!argArrayContainsSetParameterValue('orphanCleanupDelaySecs=')) { - argArray.push(...['--setParameter', 'orphanCleanupDelaySecs=1']); - } - } - - // Since options may not be backward compatible, mongod options are not - // set on older versions, e.g., mongod-3.0. - if (programName.endsWith('mongod')) { - if (jsTest.options().storageEngine === "wiredTiger" || - !jsTest.options().storageEngine) { - if (jsTest.options().enableMajorityReadConcern !== undefined && - !argArrayContains("--enableMajorityReadConcern")) { - argArray.push( - ...['--enableMajorityReadConcern', - jsTest.options().enableMajorityReadConcern.toString()]); - } - if (jsTest.options().storageEngineCacheSizeGB && - !argArrayContains('--wiredTigerCacheSizeGB')) { - argArray.push(...['--wiredTigerCacheSizeGB', - jsTest.options().storageEngineCacheSizeGB]); - } - if (jsTest.options().wiredTigerEngineConfigString && - !argArrayContains('--wiredTigerEngineConfigString')) { - argArray.push(...['--wiredTigerEngineConfigString', - jsTest.options().wiredTigerEngineConfigString]); - } - if (jsTest.options().wiredTigerCollectionConfigString && - !argArrayContains('--wiredTigerCollectionConfigString')) { - argArray.push(...['--wiredTigerCollectionConfigString', - jsTest.options().wiredTigerCollectionConfigString]); - } - if (jsTest.options().wiredTigerIndexConfigString && - !argArrayContains('--wiredTigerIndexConfigString')) { - argArray.push(...['--wiredTigerIndexConfigString', - jsTest.options().wiredTigerIndexConfigString]); - } - } else if (jsTest.options().storageEngine === "rocksdb") { - if (jsTest.options().storageEngineCacheSizeGB) { - argArray.push(...['--rocksdbCacheSizeGB', - jsTest.options().storageEngineCacheSizeGB]); - } - } else if (jsTest.options().storageEngine === "inMemory") { - if (jsTest.options().storageEngineCacheSizeGB && - !argArrayContains("--inMemorySizeGB")) { - argArray.push( - ...["--inMemorySizeGB", jsTest.options().storageEngineCacheSizeGB]); - } - } - // apply setParameters for mongod. The 'setParameters' field should be given as - // a plain JavaScript object, where each key is a parameter name and the value - // is the value to set for that parameter. - if (jsTest.options().setParameters) { - let params = jsTest.options().setParameters; - for (let paramName of Object.keys(params)) { - // Only set the 'logComponentVerbosity' parameter if it has not already - // been specified in the given argument array. This means that any - // 'logComponentVerbosity' settings passed through via TestData will - // always be overridden by settings passed directly to MongoRunner from - // within the shell. - if (paramName === "logComponentVerbosity" && - argArrayContains("logComponentVerbosity")) { - continue; - } - - const paramVal = ((param) => { - if (typeof param === "object") { - return JSON.stringify(param); - } - - return param; - })(params[paramName]); - const setParamStr = paramName + "=" + paramVal; - argArray.push(...['--setParameter', setParamStr]); - } - } - } } } - - return argArray; } - /** - * Start a mongo process with a particular argument array. - * If we aren't waiting for connect, return {pid: <pid>}. - * If we are waiting for connect: - * returns connection to process on success; - * otherwise returns null if we fail to connect. - */ - MongoRunner._startWithArgs = function(argArray, env, waitForConnect) { - // TODO: Make there only be one codepath for starting mongo processes - - argArray = appendSetParameterArgs(argArray); - var port = _parsePort.apply(null, argArray); - var pid = -1; - if (env === undefined) { - pid = _startMongoProgram.apply(null, argArray); - } else { - pid = _startMongoProgram({args: argArray, env: env}); - } + return argArray; +} + +/** + * Start a mongo process with a particular argument array. + * If we aren't waiting for connect, return {pid: <pid>}. + * If we are waiting for connect: + * returns connection to process on success; + * otherwise returns null if we fail to connect. + */ +MongoRunner._startWithArgs = function(argArray, env, waitForConnect) { + // TODO: Make there only be one codepath for starting mongo processes + + argArray = appendSetParameterArgs(argArray); + var port = _parsePort.apply(null, argArray); + var pid = -1; + if (env === undefined) { + pid = _startMongoProgram.apply(null, argArray); + } else { + pid = _startMongoProgram({args: argArray, env: env}); + } - delete serverExitCodeMap[port]; - if (!waitForConnect) { - return { - pid: pid, - port: port, - }; - } + delete serverExitCodeMap[port]; + if (!waitForConnect) { + return { + pid: pid, + port: port, + }; + } - var conn = null; - assert.soon(function() { - try { - conn = new Mongo("127.0.0.1:" + port); - conn.pid = pid; + var conn = null; + assert.soon(function() { + try { + conn = new Mongo("127.0.0.1:" + port); + conn.pid = pid; + return true; + } catch (e) { + var res = checkProgram(pid); + if (!res.alive) { + print("Could not start mongo program at " + port + + ", process ended with exit code: " + res.exitCode); + serverExitCodeMap[port] = res.exitCode; return true; - } catch (e) { - var res = checkProgram(pid); - if (!res.alive) { - print("Could not start mongo program at " + port + - ", process ended with exit code: " + res.exitCode); - serverExitCodeMap[port] = res.exitCode; - return true; - } } - return false; - }, "unable to connect to mongo program on port " + port, 600 * 1000); - - return conn; - }; - - /** - * DEPRECATED - * - * Start mongod or mongos and return a Mongo() object connected to there. - * This function's first argument is "mongod" or "mongos" program name, \ - * and subsequent arguments to this function are passed as - * command line arguments to the program. - */ - startMongoProgram = function() { - var port = _parsePort.apply(null, arguments); - - // Enable test commands. - // TODO: Make this work better with multi-version testing so that we can support - // enabling this on 2.4 when testing 2.6 - var args = Array.from(arguments); - args = appendSetParameterArgs(args); - var pid = _startMongoProgram.apply(null, args); - - var m; - assert.soon(function() { - try { - m = new Mongo("127.0.0.1:" + port); - m.pid = pid; + } + return false; + }, "unable to connect to mongo program on port " + port, 600 * 1000); + + return conn; +}; + +/** + * DEPRECATED + * + * Start mongod or mongos and return a Mongo() object connected to there. + * This function's first argument is "mongod" or "mongos" program name, \ + * and subsequent arguments to this function are passed as + * command line arguments to the program. + */ +startMongoProgram = function() { + var port = _parsePort.apply(null, arguments); + + // Enable test commands. + // TODO: Make this work better with multi-version testing so that we can support + // enabling this on 2.4 when testing 2.6 + var args = Array.from(arguments); + args = appendSetParameterArgs(args); + var pid = _startMongoProgram.apply(null, args); + + var m; + assert.soon(function() { + try { + m = new Mongo("127.0.0.1:" + port); + m.pid = pid; + return true; + } catch (e) { + var res = checkProgram(pid); + if (!res.alive) { + print("Could not start mongo program at " + port + + ", process ended with exit code: " + res.exitCode); + // Break out + m = null; return true; - } catch (e) { - var res = checkProgram(pid); - if (!res.alive) { - print("Could not start mongo program at " + port + - ", process ended with exit code: " + res.exitCode); - // Break out - m = null; - return true; - } } - return false; - }, "unable to connect to mongo program on port " + port, 600 * 1000); - - return m; - }; - - runMongoProgram = function() { - var args = Array.from(arguments); - args = appendSetParameterArgs(args); - var progName = args[0]; - - // The bsondump tool doesn't support these auth related command line flags. - if (jsTestOptions().auth && progName != 'mongod' && progName != 'bsondump') { - args = args.slice(1); - args.unshift(progName, - '-u', - jsTestOptions().authUser, - '-p', - jsTestOptions().authPassword, - '--authenticationDatabase=admin'); } + return false; + }, "unable to connect to mongo program on port " + port, 600 * 1000); + + return m; +}; + +runMongoProgram = function() { + var args = Array.from(arguments); + args = appendSetParameterArgs(args); + var progName = args[0]; + + // The bsondump tool doesn't support these auth related command line flags. + if (jsTestOptions().auth && progName != 'mongod' && progName != 'bsondump') { + args = args.slice(1); + args.unshift(progName, + '-u', + jsTestOptions().authUser, + '-p', + jsTestOptions().authPassword, + '--authenticationDatabase=admin'); + } - if (progName == 'mongo' && !_useWriteCommandsDefault()) { - progName = args[0]; - args = args.slice(1); - args.unshift(progName, '--useLegacyWriteOps'); - } - - return _runMongoProgram.apply(null, args); - }; - - // Start a mongo program instance. This function's first argument is the - // program name, and subsequent arguments to this function are passed as - // command line arguments to the program. Returns pid of the spawned program. - startMongoProgramNoConnect = function() { - var args = Array.from(arguments); - args = appendSetParameterArgs(args); - var progName = args[0]; - - if (jsTestOptions().auth) { - args = args.slice(1); - args.unshift(progName, - '-u', - jsTestOptions().authUser, - '-p', - jsTestOptions().authPassword, - '--authenticationDatabase=admin'); - } + if (progName == 'mongo' && !_useWriteCommandsDefault()) { + progName = args[0]; + args = args.slice(1); + args.unshift(progName, '--useLegacyWriteOps'); + } - if (progName == 'mongo' && !_useWriteCommandsDefault()) { - args = args.slice(1); - args.unshift(progName, '--useLegacyWriteOps'); - } + return _runMongoProgram.apply(null, args); +}; + +// Start a mongo program instance. This function's first argument is the +// program name, and subsequent arguments to this function are passed as +// command line arguments to the program. Returns pid of the spawned program. +startMongoProgramNoConnect = function() { + var args = Array.from(arguments); + args = appendSetParameterArgs(args); + var progName = args[0]; + + if (jsTestOptions().auth) { + args = args.slice(1); + args.unshift(progName, + '-u', + jsTestOptions().authUser, + '-p', + jsTestOptions().authPassword, + '--authenticationDatabase=admin'); + } - return _startMongoProgram.apply(null, args); - }; + if (progName == 'mongo' && !_useWriteCommandsDefault()) { + args = args.slice(1); + args.unshift(progName, '--useLegacyWriteOps'); + } - myPort = function() { - var m = db.getMongo(); - if (m.host.match(/:/)) - return m.host.match(/:(.*)/)[1]; - else - return 27017; - }; + return _startMongoProgram.apply(null, args); +}; +myPort = function() { + var m = db.getMongo(); + if (m.host.match(/:/)) + return m.host.match(/:(.*)/)[1]; + else + return 27017; +}; }()); |