mongodb-memory-server
Version:
In-memory MongoDB Server. Designed with testing in mind, the server will allow you to connect your favourite ODM or client library to the MongoDB Server and run integration tests isolated from each other.
182 lines (143 loc) • 6.28 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _child_process = require("child_process");
var _path = _interopRequireDefault(require("path"));
var _MongoBinary = _interopRequireDefault(require("./MongoBinary"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
class MongodbInstance {
static run(opts) {
const instance = new this(opts);
return instance.run();
}
constructor(opts) {
_defineProperty(this, "opts", void 0);
_defineProperty(this, "debug", void 0);
_defineProperty(this, "childProcess", void 0);
_defineProperty(this, "killerProcess", void 0);
_defineProperty(this, "instanceReady", void 0);
_defineProperty(this, "instanceFailed", void 0);
this.opts = opts;
if (this.opts.debug) {
if (!this.opts.instance) this.opts.instance = {};
if (!this.opts.binary) this.opts.binary = {};
this.opts.instance.debug = this.opts.debug;
this.opts.binary.debug = this.opts.debug;
}
if (this.opts.instance && this.opts.instance.debug) {
if (this.opts.instance.debug.call && typeof this.opts.instance.debug === 'function' && this.opts.instance.debug.apply) {
this.debug = this.opts.instance.debug;
} else {
this.debug = console.log.bind(null);
}
} else {
this.debug = () => {};
}
}
prepareCommandArgs() {
const _this$opts$instance = this.opts.instance,
ip = _this$opts$instance.ip,
port = _this$opts$instance.port,
storageEngine = _this$opts$instance.storageEngine,
dbPath = _this$opts$instance.dbPath,
replSet = _this$opts$instance.replSet,
auth = _this$opts$instance.auth,
args = _this$opts$instance.args;
const result = [];
result.push('--bind_ip', ip || '127.0.0.1');
if (port) result.push('--port', port.toString());
if (storageEngine) result.push('--storageEngine', storageEngine);
if (dbPath) result.push('--dbpath', dbPath);
if (!auth) result.push('--noauth');
if (replSet) result.push('--replSet', replSet);
return result.concat(args || []);
}
run() {
var _this = this;
return _asyncToGenerator(function* () {
const launch = new Promise((resolve, reject) => {
_this.instanceReady = () => {
_this.debug('MongodbInstance: is ready!');
resolve(_this.childProcess);
};
_this.instanceFailed = err => {
_this.debug(`MongodbInstance: is failed: ${err.toString()}`);
if (_this.killerProcess) _this.killerProcess.kill();
reject(err);
};
});
const mongoBin = yield _MongoBinary.default.getPath(_this.opts.binary);
_this.childProcess = _this._launchMongod(mongoBin);
_this.killerProcess = _this._launchKiller(process.pid, _this.childProcess.pid);
yield launch;
return _this;
})();
}
kill() {
var _this2 = this;
return _asyncToGenerator(function* () {
if (_this2.childProcess && !_this2.childProcess.killed) {
yield new Promise(resolve => {
_this2.childProcess.once(`exit`, resolve);
_this2.childProcess.kill();
});
}
return _this2;
})();
}
getPid() {
return this.childProcess ? this.childProcess.pid : undefined;
}
_launchMongod(mongoBin) {
const spawnOpts = this.opts.spawn || {};
if (!spawnOpts.stdio) spawnOpts.stdio = 'pipe';
const childProcess = (0, _child_process.spawn)(mongoBin, this.prepareCommandArgs(), spawnOpts);
childProcess.stderr.on('data', this.stderrHandler.bind(this));
childProcess.stdout.on('data', this.stdoutHandler.bind(this));
childProcess.on('close', this.closeHandler.bind(this));
childProcess.on('error', this.errorHandler.bind(this));
return childProcess;
}
_launchKiller(parentPid, childPid) {
// spawn process which kills itself and mongo process if current process is dead
const killer = (0, _child_process.spawn)(process.argv[0], [_path.default.resolve(__dirname, 'mongo_killer.js'), parentPid.toString(), childPid.toString()], {
stdio: 'pipe'
});
return killer;
}
errorHandler(err) {
this.instanceFailed(err);
}
closeHandler(code) {
this.debug(`CLOSE: ${code}`);
}
stderrHandler(message) {
this.debug(`STDERR: ${message.toString()}`);
}
stdoutHandler(message) {
this.debug(`${message.toString()}`);
const log = message.toString();
if (/waiting for connections on port/i.test(log)) {
this.instanceReady();
} else if (/addr already in use/i.test(log)) {
this.instanceFailed(`Port ${this.opts.instance.port} already in use`);
} else if (/mongod instance already running/i.test(log)) {
this.instanceFailed('Mongod already running');
} else if (/permission denied/i.test(log)) {
this.instanceFailed('Mongod permission denied');
} else if (/Data directory .*? not found/i.test(log)) {
this.instanceFailed('Data directory not found');
} else if (/shutting down with code/i.test(log)) {
this.instanceFailed('Mongod shutting down');
} else if (/\*\*\*aborting after/i.test(log)) {
this.instanceFailed('Mongod internal error');
}
}
}
exports.default = MongodbInstance;
_defineProperty(MongodbInstance, "childProcessList", []);