Skip to content

Commit

Permalink
fix(MongoMemoryReplSet): dont warn unless storage engine is set expli…
Browse files Browse the repository at this point in the history
…citly

previously it would warn because the instance sees the storage engine as explicitly set
because the replset default it already.
  • Loading branch information
hasezoey committed Jun 5, 2024
1 parent a852513 commit 582bf0a
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 24 deletions.
18 changes: 16 additions & 2 deletions packages/mongodb-memory-server-core/src/MongoMemoryReplSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ensureAsync,
generateDbName,
getHost,
getStorageEngine,
isNullOrUndefined,
ManagerAdvanced,
removeDir,
Expand All @@ -33,6 +34,8 @@ import {
} from './util/errors';
import { promises as fs } from 'fs';
import { resolve } from 'path';
import * as semver from 'semver';
import { DryMongoBinary } from './util/DryMongoBinary';

const log = debug('MongoMS:MongoMemoryReplSet');

Expand Down Expand Up @@ -239,6 +242,16 @@ export class MongoMemoryReplSet extends EventEmitter implements ManagerAdvanced

set replSetOpts(val: ReplSetOpts) {
assertionIsMMSRSState(MongoMemoryReplSetStates.stopped, this._state);

// the following needs to be done because we set the default "storageEngine" here
// which means the default is seen as set "explicitly" by the instance and would warn
// in binary versions >=7.0.0
const opts = DryMongoBinary.getEnsuredOptions(this.binaryOpts);
// try to convert a string to a valid semver, like "v6.0-latest" (compiles to "6.0.0")
// use "0.0.0" as a fallback to have a valid semver for later checks, but warn on invalid
const coercedVersion = semver.coerce(opts.version) ?? new semver.SemVer('0.0.0');
const storageEngine = getStorageEngine(val.storageEngine, coercedVersion);

const defaults: Required<ReplSetOpts> = {
auth: { enable: false },
args: [],
Expand All @@ -247,10 +260,11 @@ export class MongoMemoryReplSet extends EventEmitter implements ManagerAdvanced
dbName: generateDbName(),
ip: '127.0.0.1',
spawn: {},
storageEngine: 'ephemeralForTest',
storageEngine,
configSettings: {},
};
this._replSetOpts = { ...defaults, ...val };
// force overwrite "storageEngine" because it is transformed already
this._replSetOpts = { ...defaults, ...val, storageEngine };

assertion(this._replSetOpts.count > 0, new ReplsetCountLowError(this._replSetOpts.count));

Expand Down
19 changes: 2 additions & 17 deletions packages/mongodb-memory-server-core/src/MongoMemoryServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Cleanup,
createTmpDir,
removeDir,
getStorageEngine,
} from './util/utils';
import { MongoInstance, MongodOpts, MongoMemoryInstanceOpts } from './util/MongoInstance';
import { MongoBinaryOpts } from './util/MongoBinary';
Expand Down Expand Up @@ -381,23 +382,7 @@ export class MongoMemoryServer extends EventEmitter implements ManagerAdvanced {
console.warn(new UnknownVersionError(opts.version));
}

// warn when storage engine "ephemeralForTest" is explicitly used and switch to "wiredTiger"
if (storageEngine === 'ephemeralForTest' && semver.gte(coercedVersion, '7.0.0')) {
console.warn(
'Storage Engine "ephemeralForTest" is removed since mongodb 7.0.0, automatically using "wiredTiger"!\n' +
'This warning is because the mentioned storage engine is explicitly used and mongodb version is 7.0.0 or higher'
);

storageEngine = 'wiredTiger';
}

if (isNullOrUndefined(storageEngine)) {
if (semver.gte(coercedVersion, '7.0.0')) {
storageEngine = 'wiredTiger';
} else {
storageEngine = 'ephemeralForTest';
}
}
storageEngine = getStorageEngine(storageEngine, coercedVersion);

// use pre-defined port if available, otherwise generate a new port
let port = typeof instOpts.port === 'number' ? instOpts.port : undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,4 +746,56 @@ describe('MongoMemoryReplSet', () => {
replSet.servers[0]._instanceInfo.tmpDir!
); // manual cleanup
});

describe('server version specific', () => {
// should use default options that are supported for 7.0 (like not using "ephemeralForTest" by default)
it('should allow mongodb by default 7.0', async () => {
const server = await MongoMemoryReplSet.create({ binary: { version: '7.0.7' } });

await server.stop();
});

it('should not warn if "ephemeralForTest" is used explicitly in mongodb 6.0', async () => {
jest.spyOn(console, 'warn');
const server = await MongoMemoryReplSet.create({
binary: { version: '6.0.14' },
replSet: { storageEngine: 'ephemeralForTest' },
});

expect(console.warn).toHaveBeenCalledTimes(0);

expect(server.replSetOpts?.storageEngine).toStrictEqual('ephemeralForTest');

await server.stop();
});

it('should not warn if no explicit storage engine is set in 7.0', async () => {
jest.spyOn(console, 'warn');
const server = await MongoMemoryReplSet.create({
binary: { version: '7.0.7' },
// replSet: { storageEngine: 'ephemeralForTest' },
});

expect(console.warn).toHaveBeenCalledTimes(0);

expect(server.replSetOpts?.storageEngine).toStrictEqual('wiredTiger');

await server.stop();
});

it('should warn if "ephemeralForTest" is used explicitly in mongodb 7.0', async () => {
const spy = jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
const server = await MongoMemoryReplSet.create({
binary: { version: '7.0.7' },
replSet: { storageEngine: 'ephemeralForTest' },
});

expect(console.warn).toHaveBeenCalledTimes(1);
expect(spy.mock.calls).toMatchSnapshot();

expect(server.replSetOpts?.storageEngine).toStrictEqual('wiredTiger');

await server.stop();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,34 @@ describe('MongoMemoryServer', () => {
await server.stop();
});

it('should not warn if "ephemeralForTest" is used explicitly in mongodb 6.0', async () => {
jest.spyOn(console, 'warn');
const server = await MongoMemoryServer.create({
binary: { version: '6.0.14' },
instance: { storageEngine: 'ephemeralForTest' },
});

expect(console.warn).toHaveBeenCalledTimes(0);

expect(server.instanceInfo?.storageEngine).toStrictEqual('ephemeralForTest');

await server.stop();
});

it('should not warn if no explicit storage engine is set in 7.0', async () => {
jest.spyOn(console, 'warn');
const server = await MongoMemoryServer.create({
binary: { version: '7.0.7' },
// instance: { storageEngine: 'ephemeralForTest' },
});

expect(console.warn).toHaveBeenCalledTimes(0);

expect(server.instanceInfo?.storageEngine).toStrictEqual('wiredTiger');

await server.stop();
});

it('should warn if "ephemeralForTest" is used explicitly in mongodb 7.0', async () => {
const spy = jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
const server = await MongoMemoryServer.create({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ This may be because of using a v6.x way of calling functions, look at the follow
https://nodkz.github.io/mongodb-memory-server/docs/guides/migration/migrate7#no-function-other-than-start-create-ensureinstance-will-be-starting-anything"
`;

exports[`MongoMemoryReplSet server version specific should warn if "ephemeralForTest" is used explicitly in mongodb 7.0 1`] = `
Array [
Array [
"Storage Engine \\"ephemeralForTest\\" is removed since mongodb 7.0.0, automatically using \\"wiredTiger\\"!
This warning is because the mentioned storage engine is explicitly used and mongodb version is 7.0.0 or higher",
],
]
`;

exports[`single server replset "_initReplSet" should throw an error if _state is not "init" 1`] = `
"Incorrect State for operation: \\"running\\", allowed States: \\"[init]\\"
This may be because of using a v6.x way of calling functions, look at the following guide if anything applies:
Expand Down
20 changes: 15 additions & 5 deletions packages/mongodb-memory-server-core/src/util/DryMongoBinary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,20 +130,30 @@ export class DryMongoBinary {
return returnValue[1];
}

/**
* Ensure the given options fulfill {@link DryMongoBinaryOptions} by defaulting them
* @param opts The options to ensure
* @returns The ensured options
*/
static getEnsuredOptions(opts?: BaseDryMongoBinaryOptions): DryMongoBinaryOptions {
const defaultVersion = resolveConfig(ResolveConfigVariables.VERSION) ?? DEFAULT_VERSION;

return isNullOrUndefined(opts)
? { version: defaultVersion }
: { ...opts, version: opts.version || defaultVersion };
}

/**
* Generate All required options for the binary name / path generation
*/
static async generateOptions(
opts?: BaseDryMongoBinaryOptions
): Promise<Required<DryMongoBinaryOptions>> {
log('generateOptions');
const defaultVersion = resolveConfig(ResolveConfigVariables.VERSION) ?? DEFAULT_VERSION;
const ensuredOpts: BaseDryMongoBinaryOptions = isNullOrUndefined(opts)
? { version: defaultVersion }
: opts;
const ensuredOpts = DryMongoBinary.getEnsuredOptions(opts);

const final: Required<DryMongoBinaryOptions> = {
version: ensuredOpts.version || defaultVersion,
version: ensuredOpts.version,
downloadDir:
resolveConfig(ResolveConfigVariables.DOWNLOAD_DIR) || ensuredOpts.downloadDir || '',
os: ensuredOpts.os ?? (await getOS()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
InsufficientPermissionsError,
} from '../errors';
import { assertIsError } from '../../__tests__/testUtils/test_utils';
import { SemVer } from 'semver';

describe('utils', () => {
describe('uriTemplate', () => {
Expand Down Expand Up @@ -224,4 +225,36 @@ describe('utils', () => {
expect(spy).toHaveBeenCalledTimes(1);
});
});

describe('getStorageEngine', () => {
it('should get default without warning for versions', () => {
jest.spyOn(console, 'warn');
expect(utils.getStorageEngine(undefined, new SemVer('6.0.0'))).toStrictEqual(
'ephemeralForTest'
);
expect(utils.getStorageEngine(undefined, new SemVer('7.0.0'))).toStrictEqual('wiredTiger');

expect(console.warn).toHaveBeenCalledTimes(0);
});

it('should not warn for versions below 7.0.0', () => {
jest.spyOn(console, 'warn');
expect(utils.getStorageEngine('ephemeralForTest', new SemVer('6.0.0'))).toStrictEqual(
'ephemeralForTest'
);
expect(utils.getStorageEngine('wiredTiger', new SemVer('6.0.0'))).toStrictEqual('wiredTiger');

expect(console.warn).toHaveBeenCalledTimes(0);
});

it('should warn for versions above 7.0.0 for ephemeralForTest', () => {
jest.spyOn(console, 'warn').mockImplementationOnce(() => void 0);
expect(utils.getStorageEngine('ephemeralForTest', new SemVer('7.0.0'))).toStrictEqual(
'wiredTiger'
);
expect(utils.getStorageEngine('wiredTiger', new SemVer('7.0.0'))).toStrictEqual('wiredTiger');

expect(console.warn).toHaveBeenCalledTimes(1);
});
});
});
33 changes: 33 additions & 0 deletions packages/mongodb-memory-server-core/src/util/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
import { tmpdir } from 'os';
import * as path from 'path';
import { BinaryLike, createHash, randomUUID } from 'crypto';
import { StorageEngine } from './MongoInstance';
import * as semver from 'semver';

const log = debug('MongoMS:utils');

Expand Down Expand Up @@ -372,3 +374,34 @@ export async function md5FromFile(file: string): Promise<string> {
export function lockfilePath(downloadDir: string, version: string): string {
return path.resolve(downloadDir, `${version}.lock`);
}

/**
* Get the storage engine for the given given binary version, and issue a warning if it needs to be changed
* @param storageEngine The engine that is configured
* @param coercedVersion The binary version as semver
* @returns The engine that actually will run in the given binary version
*/
export function getStorageEngine(
storageEngine: StorageEngine | undefined,
coercedVersion: semver.SemVer
): StorageEngine {
// warn when storage engine "ephemeralForTest" is explicitly used and switch to "wiredTiger"
if (storageEngine === 'ephemeralForTest' && semver.gte(coercedVersion, '7.0.0')) {
console.warn(
'Storage Engine "ephemeralForTest" is removed since mongodb 7.0.0, automatically using "wiredTiger"!\n' +
'This warning is because the mentioned storage engine is explicitly used and mongodb version is 7.0.0 or higher'
);

return 'wiredTiger';
}

if (isNullOrUndefined(storageEngine)) {
if (semver.gte(coercedVersion, '7.0.0')) {
return 'wiredTiger';
}

return 'ephemeralForTest';
}

return storageEngine;
}

0 comments on commit 582bf0a

Please sign in to comment.