Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | 10x 10x 10x 10x | 'use strict';
/**
* @module test/support/mongod
* @description Starts a throwaway MongoDB server for a suite that needs the real database —
* unique indexes, duplicate-key errors, cursors, transactions — rather than a fake of it. Uses
* the binary `UNDERPOST_MONGOD_BIN` names, or `mongod` on PATH; `mongodBinary` is `null` without
* one, so a suite can `describe.skipIf(!mongodBinary)` and still run where no server can be started.
*/
import os from 'os';
import net from 'net';
import nodePath from 'path';
import { spawn } from 'child_process';
import fs from 'fs-extra';
import mongoose from 'mongoose';
import { findBinary } from './binary.js';
const mongodBinary = findBinary('mongod', 'UNDERPOST_MONGOD_BIN');
const freePort = () =>
new Promise((resolve, reject) => {
const server = net.createServer();
server.on('error', reject);
server.listen(0, '127.0.0.1', () => {
const { port } = server.address();
server.close(() => resolve(port));
});
});
/** Makes a started `mongod` the one member of replica set `name` and waits until it is primary. */
const initiateReplicaSet = async (host, name) => {
const client = await new mongoose.mongo.MongoClient(`mongodb://${host}/?directConnection=true`).connect();
try {
const admin = client.db('admin');
await admin.command({ replSetInitiate: { _id: name, members: [{ _id: 0, host }] } });
for (let attempt = 0; attempt < 300; attempt++) {
if ((await admin.command({ hello: 1 })).isWritablePrimary) return;
await new Promise((resolve) => setTimeout(resolve, 100));
}
throw new Error(`Replica set ${name} elected no primary`);
} finally {
await client.close();
}
};
/**
* @param {string} [dbName='test']
* @param {{ replSet?: string }} [options] - `replSet` starts a one-member replica set of that name.
* @returns {Promise<{ host: string, port: number, uri: string, stop: () => Promise<void> }>}
*/
const startMongod = async (dbName = 'test', { replSet = '' } = {}) => {
const dbPath = await fs.mkdtemp(nodePath.join(os.tmpdir(), 'underpost-mongod-'));
const port = await freePort();
const args = ['--dbpath', dbPath, '--port', `${port}`, '--bind_ip', '127.0.0.1', '--quiet'];
if (replSet) args.push('--replSet', replSet);
const child = spawn(mongodBinary, args, { stdio: ['ignore', 'pipe', 'pipe'] });
await new Promise((resolve, reject) => {
let output = '';
const onData = (chunk) => {
output += chunk;
if (output.includes('Waiting for connections')) resolve();
};
child.stdout.on('data', onData);
child.stderr.on('data', onData);
child.on('exit', (code) => reject(new Error(`mongod exited with ${code}\n${output}`)));
setTimeout(() => reject(new Error(`mongod did not start\n${output}`)), 30000);
});
const host = `127.0.0.1:${port}`;
if (replSet) await initiateReplicaSet(host, replSet);
return {
host,
port,
uri: `mongodb://${host}/${dbName}?${replSet ? `replicaSet=${replSet}` : 'directConnection=true'}`,
stop: async () => {
child.kill('SIGTERM');
await new Promise((resolve) => child.on('exit', resolve));
await fs.remove(dbPath);
},
};
};
export { mongodBinary, freePort, startMongod };
|