UNPKG

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.

271 lines (201 loc) 8.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _os = _interopRequireDefault(require("os")); var _url = _interopRequireDefault(require("url")); var _path = _interopRequireDefault(require("path")); var _fs = _interopRequireDefault(require("fs")); var _md5File = _interopRequireDefault(require("md5-file")); var _https = _interopRequireDefault(require("https")); var _httpsProxyAgent = _interopRequireDefault(require("https-proxy-agent")); var _decompress = _interopRequireDefault(require("decompress")); var _MongoBinaryDownloadUrl = _interopRequireDefault(require("./MongoBinaryDownloadUrl")); 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 MongoBinaryDownload { constructor({ platform, arch, downloadDir, version, debug }) { _defineProperty(this, "debug", void 0); _defineProperty(this, "dlProgress", void 0); _defineProperty(this, "downloadDir", void 0); _defineProperty(this, "arch", void 0); _defineProperty(this, "version", void 0); _defineProperty(this, "platform", void 0); this.platform = platform || _os.default.platform(); this.arch = arch || _os.default.arch(); this.version = version || 'latest'; this.downloadDir = _path.default.resolve(downloadDir || 'mongodb-download'); this.dlProgress = { current: 0, length: 0, totalMb: 0, lastPrintedAt: 0 }; if (debug) { if (debug.call && typeof debug === 'function' && debug.apply) { this.debug = debug; } else { this.debug = console.log.bind(null); } } else { this.debug = () => {}; } } getMongodPath() { var _this = this; return _asyncToGenerator(function* () { const binaryName = _this.platform === 'win32' ? 'mongod.exe' : 'mongod'; const mongodPath = _path.default.resolve(_this.downloadDir, _this.version, binaryName); if (_this.locationExists(mongodPath)) { return mongodPath; } const mongoDBArchive = yield _this.startDownload(); yield _this.extract(mongoDBArchive); _fs.default.unlinkSync(mongoDBArchive); if (_this.locationExists(mongodPath)) { return mongodPath; } throw new Error(`Cannot find downloaded mongod binary by path ${mongodPath}`); })(); } startDownload() { var _this2 = this; return _asyncToGenerator(function* () { const mbdUrl = new _MongoBinaryDownloadUrl.default({ platform: _this2.platform, arch: _this2.arch, version: _this2.version }); if (!_fs.default.existsSync(_this2.downloadDir)) { _fs.default.mkdirSync(_this2.downloadDir); } const downloadUrl = yield mbdUrl.getDownloadUrl(); const mongoDBArchive = yield _this2.download(downloadUrl); const mongoDBArchiveMd5 = yield _this2.download(`${downloadUrl}.md5`); yield _this2.checkMd5(mongoDBArchiveMd5, mongoDBArchive); return mongoDBArchive; })(); } checkMd5(mongoDBArchiveMd5, mongoDBArchive) { return _asyncToGenerator(function* () { const signatureContent = _fs.default.readFileSync(mongoDBArchiveMd5).toString('UTF-8'); const m = signatureContent.match(/(.*?)\s/); const md5Remote = m ? m[1] : null; const md5Local = _md5File.default.sync(mongoDBArchive); if (md5Remote !== md5Local) { throw new Error('MongoBinaryDownload: md5 check is failed'); } })(); } download(downloadUrl) { var _this3 = this; return _asyncToGenerator(function* () { const proxy = process.env['yarn_https-proxy'] || process.env.yarn_proxy || process.env['npm_config_https-proxy'] || process.env.npm_config_proxy || process.env.https_proxy || process.env.http_proxy; const urlObject = _url.default.parse(downloadUrl); const downloadOptions = { hostname: urlObject.hostname, port: urlObject.port || 443, path: urlObject.path, method: 'GET', agent: proxy ? new _httpsProxyAgent.default(proxy) : undefined }; const filename = (urlObject.pathname || '').split('/').pop(); if (!filename) { throw new Error(`MongoBinaryDownload: missing filename for url ${downloadUrl}`); } const downloadLocation = _path.default.resolve(_this3.downloadDir, filename); const tempDownloadLocation = _path.default.resolve(_this3.downloadDir, `${filename}.downloading`); _this3.debug(`Downloading${proxy ? ` via proxy ${proxy}` : ''}:`, downloadUrl); const downloadedFile = yield _this3.httpDownload(downloadOptions, downloadLocation, tempDownloadLocation); return downloadedFile; })(); } extract(mongoDBArchive) { var _this4 = this; return _asyncToGenerator(function* () { const binaryName = _this4.platform === 'win32' ? 'mongod.exe' : 'mongod'; const extractDir = _path.default.resolve(_this4.downloadDir, _this4.version); _this4.debug(`extract(): ${extractDir}`); if (!_fs.default.existsSync(extractDir)) { _fs.default.mkdirSync(extractDir); } let filter; if (_this4.platform === 'win32') { filter = file => { return /bin\/mongod.exe$/.test(file.path) || /.dll$/.test(file.path); }; } else { filter = file => /bin\/mongod$/.test(file.path); } yield (0, _decompress.default)(mongoDBArchive, extractDir, { // extract only `bin/mongod` file filter, // extract to root folder map: file => { file.path = _path.default.basename(file.path); // eslint-disable-line return file; } }); if (!_this4.locationExists(_path.default.resolve(_this4.downloadDir, _this4.version, binaryName))) { throw new Error(`MongoBinaryDownload: missing mongod binary in ${mongoDBArchive}`); } return extractDir; })(); } httpDownload(httpOptions, downloadLocation, tempDownloadLocation) { var _this5 = this; return _asyncToGenerator(function* () { return new Promise((resolve, reject) => { const fileStream = _fs.default.createWriteStream(tempDownloadLocation); const req = _https.default.get(httpOptions, response => { _this5.dlProgress.current = 0; _this5.dlProgress.length = parseInt(response.headers['content-length'], 10); _this5.dlProgress.totalMb = Math.round(_this5.dlProgress.length / 1048576 * 10) / 10; response.pipe(fileStream); fileStream.on('finish', () => { fileStream.close(); _fs.default.renameSync(tempDownloadLocation, downloadLocation); _this5.debug(`renamed ${tempDownloadLocation} to ${downloadLocation}`); resolve(downloadLocation); }); response.on('data', chunk => { _this5.printDownloadProgress(chunk); }); req.on('error', e => { _this5.debug('request error:', e); reject(e); }); }); }); })(); } printDownloadProgress(chunk) { this.dlProgress.current += chunk.length; const now = Date.now(); if (now - this.dlProgress.lastPrintedAt < 2000) return; this.dlProgress.lastPrintedAt = now; const percentComplete = Math.round(100.0 * this.dlProgress.current / this.dlProgress.length * 10) / 10; const mbComplete = Math.round(this.dlProgress.current / 1048576 * 10) / 10; const crReturn = this.platform === 'win32' ? '\x1b[0G' : '\r'; process.stdout.write(`Downloading MongoDB ${this.version}: ${percentComplete} % (${mbComplete}mb ` + `/ ${this.dlProgress.totalMb}mb)${crReturn}`); } locationExists(location) { try { _fs.default.lstatSync(location); return true; } catch (e) { if (e.code !== 'ENOENT') throw e; return false; } } } exports.default = MongoBinaryDownload;