Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/mongodb-runner/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ import type { MongoClientOptions } from 'mongodb';
type: 'string',
describe: 'Configure OIDC authentication on the server',
})
.config()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha I can't believe I missed this option. 😅

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified that it passes options through that aren't defined in the cli options, so we don't need to add all of the new options to the cli.

.env('MONGODB_RUNNER')
.option('debug', { type: 'boolean', describe: 'Enable debug output' })
.option('verbose', { type: 'boolean', describe: 'Enable verbose output' })
.command('start', 'Start a MongoDB instance')
.command('stop', 'Stop a MongoDB instance')
.command('prune', 'Clean up metadata for any dead MongoDB instances')
Expand All @@ -86,9 +89,12 @@ import type { MongoClientOptions } from 'mongodb';
.demandCommand(1, 'A command needs to be provided')
.help().argv;
const [command, ...args] = argv._.map(String);
if (argv.debug) {
if (argv.debug || argv.verbose) {
createDebug.enable('mongodb-runner');
}
if (argv.verbose) {
createDebug.enable('mongodb-runner:*');
}

if (argv.oidc && process.platform !== 'linux') {
console.warn(
Expand Down
1 change: 1 addition & 0 deletions packages/mongodb-runner/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export {
MongoCluster,
type MongoClusterEvents,
MongoClusterOptions,
MongoDBUserDoc,
} from './mongocluster';
export type { LogEntry } from './mongologreader';
export type { ConnectionString } from 'mongodb-connection-string-url';
Expand Down
178 changes: 177 additions & 1 deletion packages/mongodb-runner/src/mongocluster.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ describe('MongoCluster', function () {
const hello = await cluster.withClient(async (client) => {
return await client.db('admin').command({ hello: 1 });
});
expect(+hello.passives.length + +hello.hosts.length).to.equal(5);
expect(hello.hosts).to.have.lengthOf(1);
expect(hello.passives).to.have.lengthOf(3);
expect(hello.arbiters).to.have.lengthOf(1);
});

it('can spawn a 6.x sharded cluster', async function () {
Expand Down Expand Up @@ -343,4 +345,178 @@ describe('MongoCluster', function () {
baddoc: 1,
});
});

it('can pass custom arguments for replica set members', async function () {
cluster = await MongoCluster.start({
version: '6.x',
topology: 'replset',
tmpDir,
rsMembers: [
{ args: ['--setParameter', 'cursorTimeoutMillis=60000'] },
{ args: ['--setParameter', 'cursorTimeoutMillis=50000'] },
],
});

expect(cluster.connectionString).to.be.a('string');
expect(cluster.serverVersion).to.match(/^6\./);
const hello = await cluster.withClient(async (client) => {
return await client.db('admin').command({ hello: 1 });
});
expect(hello.hosts).to.have.lengthOf(1);
expect(hello.passives).to.have.lengthOf(1);

const servers = cluster['servers'];
expect(servers).to.have.lengthOf(2);
const values = await Promise.all(
servers.map((srv) =>
srv.withClient(async (client) => {
return await Promise.all([
client
.db('admin')
.command({ getParameter: 1, cursorTimeoutMillis: 1 }),
client.db('admin').command({ hello: 1 }),
]);
}),
),
);

expect(
values.map((v) => [v[0].cursorTimeoutMillis, v[1].isWritablePrimary]),
).to.deep.equal([
[60000, true],
[50000, false],
]);
});

it('can pass custom arguments for shards', async function () {
cluster = await MongoCluster.start({
version: '6.x',
topology: 'sharded',
tmpDir,
secondaries: 0,
shardArgs: [
['--setParameter', 'cursorTimeoutMillis=60000'],
['--setParameter', 'cursorTimeoutMillis=50000'],
],
});

expect(cluster.connectionString).to.be.a('string');
expect(cluster.serverVersion).to.match(/^6\./);

const shards = cluster['shards'];
expect(shards).to.have.lengthOf(2);
const values = await Promise.all(
shards.map((srv) =>
srv.withClient(async (client) => {
return await Promise.all([
client
.db('admin')
.command({ getParameter: 1, cursorTimeoutMillis: 1 }),
client.db('admin').command({ hello: 1 }),
]);
}),
),
);

expect(
values.map((v) => [
v[0].cursorTimeoutMillis,
v[1].setName === values[0][1].setName,
]),
).to.deep.equal([
[60000, true],
[50000, false],
]);
});

it('can pass custom arguments for mongoses', async function () {
cluster = await MongoCluster.start({
version: '6.x',
topology: 'sharded',
tmpDir,
secondaries: 0,
mongosArgs: [
['--setParameter', 'cursorTimeoutMillis=60000'],
['--setParameter', 'cursorTimeoutMillis=50000'],
],
});

expect(cluster.connectionString).to.be.a('string');
expect(cluster.serverVersion).to.match(/^6\./);

const mongoses = cluster['servers'];
expect(mongoses).to.have.lengthOf(2);
const values = await Promise.all(
mongoses.map((srv) =>
srv.withClient(async (client) => {
return await Promise.all([
client
.db('admin')
.command({ getParameter: 1, cursorTimeoutMillis: 1 }),
client.db('admin').command({ hello: 1 }),
]);
}),
),
);

const processIdForMongos = (v: any) =>
v[1].topologyVersion.processId.toHexString();
expect(
values.map((v) => [
v[0].cursorTimeoutMillis,
v[1].msg,
processIdForMongos(v) === processIdForMongos(values[0]),
]),
).to.deep.equal([
[60000, 'isdbgrid', true],
[50000, 'isdbgrid', false],
]);

const mongosList = await cluster.withClient(
async (client) =>
await client.db('config').collection('mongos').find().toArray(),
);
expect(mongosList).to.have.lengthOf(2);
});

it('can add authentication options and verify them after serialization', async function () {
cluster = await MongoCluster.start({
version: '6.x',
topology: 'sharded',
tmpDir,
secondaries: 1,
shards: 1,
users: [
{
username: 'testuser',
password: 'testpass',
roles: [{ role: 'readWriteAnyDatabase', db: 'admin' }],
},
],
mongosArgs: [[], []],
});
expect(cluster.connectionString).to.be.a('string');
expect(cluster.serverVersion).to.match(/^6\./);
expect(cluster.connectionString).to.include('testuser:testpass@');
await cluster.withClient(async (client) => {
const result = await client
.db('test')
.collection('test')
.insertOne({ foo: 42 });
expect(result.insertedId).to.exist;
});

cluster = await MongoCluster.deserialize(cluster.serialize());
expect(cluster.connectionString).to.include('testuser:testpass@');
const [doc, status] = await cluster.withClient(async (client) => {
return Promise.all([
client.db('test').collection('test').findOne({ foo: 42 }),
client.db('admin').command({ connectionStatus: 1 }),
] as const);
});
expect(doc?.foo).to.equal(42);
expect(status.authInfo.authenticatedUsers).to.deep.equal([
{ user: 'testuser', db: 'admin' },
]);
});
});
Loading
Loading