Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const mongod = new MongoMemoryServer({
platform?: string, // by default os.platform()
arch?: string, // by default os.arch()
debug?: boolean, // by default false
skipMD5?: boolean, // by default false OR process.env.MONGOMS_SKIP_MD5_CHECK
},
debug?: boolean, // by default false
autoStart?: boolean, // by default true
Expand All @@ -76,6 +77,8 @@ MONGOMS_VERSION=3
MONGOMS_DEBUG=1 # also available case-insensitive values: "on" "yes" "true"
MONGOMS_DOWNLOAD_MIRROR=url # your mirror url to download the mongodb binary
MONGOMS_DISABLE_POSTINSTALL=1 # if you want to skip download binaries on `npm i` command
MONGOMS_SKIP_MD5_CHECK=1 # if you want to skip MD5 check of downloaded binary.
# Passed constructor parameter `binary.skipMD5` has higher priority.
```

### Replica Set start:
Expand Down
5 changes: 5 additions & 0 deletions postinstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ if (isModuleExists('./lib/util/MongoBinary')) {
console.log('mongodb-memory-server: checking MongoDB binaries cache...');
MongoBinary.getPath({}).then(binPath => {
console.log(`mongodb-memory-server: binary path is ${binPath}`);
})
.catch((err) => {
console.log(`failed to download/install MongoDB binaries. The error:
${err}`)
process.exit(1)
});
} else {
console.log("Can't resolve MongoBinary module");
Expand Down
28 changes: 24 additions & 4 deletions src/util/MongoBinaryDownload.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,38 @@ export type MongoBinaryDownloadOpts = {
platform: string,
arch: string,
debug?: DebugPropT,
skipMD5?: boolean,
};

export default class MongoBinaryDownload {
debug: DebugFn;
dlProgress: DownloadProgressT;

skipMD5: boolean;
downloadDir: string;
arch: string;
version: string;
platform: string;

constructor({ platform, arch, downloadDir, version, debug }: $Shape<MongoBinaryDownloadOpts>) {
constructor({
platform,
arch,
downloadDir,
version,
skipMD5,
debug,
}: $Shape<MongoBinaryDownloadOpts>) {
this.platform = platform || os.platform();
this.arch = arch || os.arch();
this.version = version || 'latest';
this.downloadDir = path.resolve(downloadDir || 'mongodb-download');
if (skipMD5 === undefined) {
this.skipMD5 =
typeof process.env.MONGOMS_SKIP_MD5_CHECK === 'string' &&
['1', 'on', 'yes', 'true'].indexOf(process.env.MONGOMS_SKIP_MD5_CHECK.toLowerCase()) !== -1;
} else {
this.skipMD5 = skipMD5;
}
this.dlProgress = {
current: 0,
length: 0,
Expand Down Expand Up @@ -84,20 +100,24 @@ export default class MongoBinaryDownload {
const downloadUrl = await mbdUrl.getDownloadUrl();
const mongoDBArchive = await this.download(downloadUrl);

const mongoDBArchiveMd5 = await this.download(`${downloadUrl}.md5`);
await this.checkMd5(mongoDBArchiveMd5, mongoDBArchive);
await this.checkMD5(`${downloadUrl}.md5`, mongoDBArchive);

return mongoDBArchive;
}

async checkMd5(mongoDBArchiveMd5: string, mongoDBArchive: string) {
async checkMD5(urlForReferenceMD5: string, mongoDBArchive: string): Promise<?boolean> {
if (this.skipMD5) {
return undefined;
}
const mongoDBArchiveMd5 = await this.download(urlForReferenceMD5);
const signatureContent = fs.readFileSync(mongoDBArchiveMd5).toString('UTF-8');
const m = signatureContent.match(/(.*?)\s/);
const md5Remote = m ? m[1] : null;
const md5Local = md5File.sync(mongoDBArchive);
if (md5Remote !== md5Local) {
throw new Error('MongoBinaryDownload: md5 check is failed');
}
return true;
}

async download(downloadUrl: string) {
Expand Down
63 changes: 63 additions & 0 deletions src/util/__tests__/MongoBinaryDownload-test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,29 @@
/* @flow */

import fs from 'fs';
import md5file from 'md5-file';
import MongoBinaryDownload from '../MongoBinaryDownload';

jest.mock('fs');
jest.mock('md5-file');

describe('MongoBinaryDownload', () => {
afterEach(() => {
delete process.env.MONGOMS_SKIP_MD5_CHECK;
});

it('skipMD5 attribute can be set via constructor parameter', () => {
expect(new MongoBinaryDownload({ skipMD5: true }).skipMD5).toBe(true);
expect(new MongoBinaryDownload({ skipMD5: false }).skipMD5).toBe(false);
});

it(`if skipMD5 input parameter is missing, then it checks
MONGOMS_SKIP_MD5_CHECK environment variable`, () => {
expect(new MongoBinaryDownload({}).skipMD5).toBe(false);
process.env.MONGOMS_SKIP_MD5_CHECK = '1';
expect(new MongoBinaryDownload({}).skipMD5).toBe(true);
});

it('should use direct download', async () => {
process.env['yarn_https-proxy'] = '';
process.env.yarn_proxy = '';
Expand Down Expand Up @@ -34,4 +55,46 @@ describe('MongoBinaryDownload', () => {
expect(callArg1.agent).toBeDefined();
expect(callArg1.agent.options.href).toBe('http://user:pass@proxy:8080/');
});

it(`checkMD5 returns true if md5 of downloaded mongoDBArchive is
the same as in the reference result`, () => {
const someMd5 = 'md5';
fs.readFileSync.mockImplementationOnce(() => `${someMd5} fileName`);
md5file.sync.mockImplementationOnce(() => someMd5);
const mongoDBArchivePath = '/some/path';
const fileWithReferenceMd5 = '/another/path';
const du = new MongoBinaryDownload({});
// $FlowFixMe
du.download = jest.fn(() => Promise.resolve(fileWithReferenceMd5));
const urlToMongoDBArchivePath = 'some-url';
return du.checkMD5(urlToMongoDBArchivePath, mongoDBArchivePath).then(res => {
expect(res).toBe(true);
expect(du.download).toBeCalledWith(urlToMongoDBArchivePath);
expect(fs.readFileSync).toBeCalledWith(fileWithReferenceMd5);
expect(md5file.sync).toBeCalledWith(mongoDBArchivePath);
});
});

it(`checkMD5 throws an error if md5 of downloaded mongoDBArchive is NOT
the same as in the reference result`, () => {
fs.readFileSync.mockImplementationOnce(() => 'someMd5 fileName');
md5file.sync.mockImplementationOnce(() => 'anotherMd5');
const du = new MongoBinaryDownload({});
// $FlowFixMe
du.download = jest.fn(() => Promise.resolve(''));
expect(du.checkMD5('', '')).rejects.toMatchInlineSnapshot(
`[Error: MongoBinaryDownload: md5 check is failed]`
);
});

it('true value of skipMD5 attribute disables checkMD5 validation', () => {
expect.assertions(1);
fs.readFileSync.mockImplementationOnce(() => 'someMd5 fileName');
md5file.sync.mockImplementationOnce(() => 'anotherMd5');
const du = new MongoBinaryDownload({});
du.skipMD5 = true;
return du.checkMD5('', '').then(res => {
expect(res).toBe(undefined);
});
});
});