From b2199a6e22048f838215658d8c97242d7351f828 Mon Sep 17 00:00:00 2001 From: Daria Pardue <81593090+dariakp@users.noreply.github.com> Date: Wed, 5 May 2021 17:07:05 -0400 Subject: [PATCH 1/4] fix(NODE-3194): Ignore undefined and null options in MongoClient constructor --- src/connection_string.ts | 4 ++- test/unit/mongo_client_options.test.js | 34 +++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/connection_string.ts b/src/connection_string.ts index 3d367b46115..979ac4a4216 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -340,7 +340,9 @@ export function parseOptions( } } - const objectOptions = new CaseInsensitiveMap(Object.entries(options)); + const objectOptions = new CaseInsensitiveMap( + Object.entries(options).filter(([, v]) => (v ?? null) !== null) + ); const allOptions = new CaseInsensitiveMap(); diff --git a/test/unit/mongo_client_options.test.js b/test/unit/mongo_client_options.test.js index c848809f5b9..21e00269809 100644 --- a/test/unit/mongo_client_options.test.js +++ b/test/unit/mongo_client_options.test.js @@ -8,7 +8,7 @@ const { WriteConcern } = require('../../src/write_concern'); const { ReadPreference } = require('../../src/read_preference'); const { Logger } = require('../../src/logger'); const { MongoCredentials } = require('../../src/cmap/auth/mongo_credentials'); -const { MongoClient } = require('../../src'); +const { MongoClient, MongoParseError } = require('../../src'); describe('MongoOptions', function () { it('MongoClient should always freeze public options', function () { @@ -138,9 +138,8 @@ describe('MongoOptions', function () { zlibCompressionLevel: 2 }; - it('All options', function () { + it('should parse all options from the options object', function () { const options = parseOptions('mongodb://localhost:27017/', ALL_OPTIONS); - // Check consolidated options expect(options).has.property('writeConcern'); expect(options.writeConcern).has.property('w', 2); @@ -183,7 +182,7 @@ describe('MongoOptions', function () { 'zlibCompressionLevel=2' ].join('&'); - it('All URI options', function () { + it('should parse all options from the URI string', function () { const options = parseOptions(allURIOptions); expect(options).has.property('zlibCompressionLevel', 2); @@ -192,6 +191,33 @@ describe('MongoOptions', function () { expect(options.writeConcern).has.property('wtimeout', 2); }); + it('should ignore undefined and null values in the options object', function () { + const options = parseOptions('mongodb://localhost:27017/', { + maxPoolSize: null, + servername: undefined, + randomopt: null, + otherrandomopt: undefined + }); + + // test valid option key with default value + expect(options).to.have.property('maxPoolSize', 100); + + // test valid option key without default value + expect(options).not.to.have.property('servername'); + + // test invalid option keys that are null/undefined + expect(options).not.to.have.property('randomopt'); + expect(options).not.to.have.property('otherrandomopt'); + }); + + it('should throw an error on unrecognized keys in the options object if they are defined', function () { + expect(() => + parseOptions('mongodb://localhost:27017/', { + randomopt: 'test' + }) + ).to.throw(MongoParseError, /randomopt.+not supported$/); + }); + it('srvHost saved to options for later resolution', function () { const options = parseOptions('mongodb+srv://server.example.com/'); expect(options).has.property('srvHost', 'server.example.com'); From 55b08b51454341bd6b63552aab7ad429e7b23f26 Mon Sep 17 00:00:00 2001 From: Daria Pardue <81593090+dariakp@users.noreply.github.com> Date: Wed, 5 May 2021 17:07:45 -0400 Subject: [PATCH 2/4] refactor: better message for option validation --- src/connection_string.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/connection_string.ts b/src/connection_string.ts index 979ac4a4216..2b3cec769d4 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -370,9 +370,11 @@ export function parseOptions( allKeys, Array.from(Object.keys(OPTIONS)).map(s => s.toLowerCase()) ); + const optionWord = unsupportedOptions.size > 1 ? 'options' : 'option'; + const isOrAre = unsupportedOptions.size > 1 ? 'are' : 'is'; if (unsupportedOptions.size !== 0) { throw new MongoParseError( - `options ${Array.from(unsupportedOptions).join(', ')} are not supported` + `${optionWord} ${Array.from(unsupportedOptions).join(', ')} ${isOrAre} not supported` ); } From 65acdd70d14c6cffa99543b09c435bf92e22e19f Mon Sep 17 00:00:00 2001 From: Daria Pardue <81593090+dariakp@users.noreply.github.com> Date: Thu, 6 May 2021 14:58:23 -0400 Subject: [PATCH 3/4] Clean up src/connection_string.ts Co-authored-by: Neal Beeken --- src/connection_string.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/connection_string.ts b/src/connection_string.ts index 2b3cec769d4..04532ae678f 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -370,9 +370,9 @@ export function parseOptions( allKeys, Array.from(Object.keys(OPTIONS)).map(s => s.toLowerCase()) ); - const optionWord = unsupportedOptions.size > 1 ? 'options' : 'option'; - const isOrAre = unsupportedOptions.size > 1 ? 'are' : 'is'; if (unsupportedOptions.size !== 0) { + const optionWord = unsupportedOptions.size > 1 ? 'options' : 'option'; + const isOrAre = unsupportedOptions.size > 1 ? 'are' : 'is'; throw new MongoParseError( `${optionWord} ${Array.from(unsupportedOptions).join(', ')} ${isOrAre} not supported` ); From 5f38518c97d8779f5aa334d7579c36a01599abb4 Mon Sep 17 00:00:00 2001 From: Daria Pardue <81593090+dariakp@users.noreply.github.com> Date: Thu, 6 May 2021 15:01:19 -0400 Subject: [PATCH 4/4] Update test/unit/mongo_client_options.test.js Co-authored-by: Neal Beeken --- test/unit/mongo_client_options.test.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/unit/mongo_client_options.test.js b/test/unit/mongo_client_options.test.js index 21e00269809..0ceb8ce076e 100644 --- a/test/unit/mongo_client_options.test.js +++ b/test/unit/mongo_client_options.test.js @@ -215,7 +215,14 @@ describe('MongoOptions', function () { parseOptions('mongodb://localhost:27017/', { randomopt: 'test' }) - ).to.throw(MongoParseError, /randomopt.+not supported$/); + ).to.throw(MongoParseError, 'option randomopt is not supported'); + + expect(() => + parseOptions('mongodb://localhost:27017/', { + randomopt: 'test', + randomopt2: 'test' + }) + ).to.throw(MongoParseError, 'options randomopt, randomopt2 are not supported'); }); it('srvHost saved to options for later resolution', function () {