From b9fbac5b13e0305a196f05b30b25111632f3ef13 Mon Sep 17 00:00:00 2001 From: Bailey Pearson Date: Wed, 1 Dec 2021 16:12:46 -0500 Subject: [PATCH] fix(NODE-3705): ReadPreference.fromOptions omitting hedge and maxStalenessSeconds when readPreference is a string (#3060) --- CONTRIBUTORS.md | 1 + src/read_preference.ts | 5 +- test/functional/readpreference.test.js | 64 ------------ test/unit/read_preference.test.ts | 134 +++++++++++++++++++++++++ 4 files changed, 139 insertions(+), 65 deletions(-) create mode 100644 test/unit/read_preference.test.ts diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d3c99a84d3..598ac02663 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -58,6 +58,7 @@ - Neal Beeken <> - Durran Jordan <> - Daria Pardue <> +- Bailey Pearson <> ## Community Types diff --git a/src/read_preference.ts b/src/read_preference.ts index d0ffd6e3c5..e2a713e9ea 100644 --- a/src/read_preference.ts +++ b/src/read_preference.ts @@ -156,7 +156,10 @@ export class ReadPreference { } if (typeof readPreference === 'string') { - return new ReadPreference(readPreference as ReadPreferenceMode, readPreferenceTags); + return new ReadPreference(readPreference as ReadPreferenceMode, readPreferenceTags, { + maxStalenessSeconds: options.maxStalenessSeconds, + hedge: options.hedge + }); } else if (!(readPreference instanceof ReadPreference) && typeof readPreference === 'object') { const mode = readPreference.mode || readPreference.preference; if (mode && typeof mode === 'string') { diff --git a/test/functional/readpreference.test.js b/test/functional/readpreference.test.js index 49f4ccff7d..2888e14bf3 100644 --- a/test/functional/readpreference.test.js +++ b/test/functional/readpreference.test.js @@ -14,70 +14,6 @@ describe('ReadPreference', function () { return setupDatabase(this.configuration); }); - describe('::constructor', function () { - const maxStalenessSeconds = 1234; - const { PRIMARY, SECONDARY, NEAREST } = ReadPreference; - const TAGS = [{ loc: 'dc' }]; - - it('should accept (mode)', function () { - expect(new ReadPreference(PRIMARY)).to.be.an.instanceOf(ReadPreference); - }); - - it('should accept valid (mode, tags)', function () { - expect(new ReadPreference(PRIMARY, [])).to.be.an.instanceOf(ReadPreference); - const p0 = new ReadPreference(NEAREST, TAGS); - expect(p0.mode).to.equal(NEAREST); - }); - - it('should not accept invalid tags', function () { - expect(() => new ReadPreference(PRIMARY, 'invalid')).to.throw( - 'ReadPreference tags must be an array' - ); - expect(() => new ReadPreference(PRIMARY, { loc: 'dc' }, { maxStalenessSeconds })).to.throw( - 'ReadPreference tags must be an array' - ); - }); - - it('should accept (mode, options)', function () { - const p1 = new ReadPreference(SECONDARY, { maxStalenessSeconds }); - expect(p1.mode).to.equal(SECONDARY); - expect(p1.maxStalenessSeconds).to.equal(maxStalenessSeconds); - }); - - it('should not accept mode=primary + tags', function () { - expect(() => new ReadPreference(PRIMARY, TAGS)).to.throw( - 'Primary read preference cannot be combined with tags' - ); - }); - - it('should not accept mode=primary + options.maxStalenessSeconds', function () { - expect(() => new ReadPreference(PRIMARY, null, { maxStalenessSeconds })).to.throw( - 'Primary read preference cannot be combined with maxStalenessSeconds' - ); - }); - - it('should accept (mode=secondary, tags=null, options)', function () { - const p2 = new ReadPreference(SECONDARY, null, { maxStalenessSeconds }); - expect(p2).to.be.an.instanceOf(ReadPreference); - expect(p2.mode).to.equal(SECONDARY); - expect(p2.maxStalenessSeconds).to.equal(maxStalenessSeconds); - }); - - it('should accept (mode=secondary, tags, options)', function () { - const p3 = new ReadPreference(SECONDARY, TAGS, { maxStalenessSeconds }); - expect(p3).to.be.an.instanceOf(ReadPreference); - expect(p3.mode).to.equal(SECONDARY); - expect(p3.tags).to.eql(TAGS); - expect(p3.maxStalenessSeconds).to.equal(maxStalenessSeconds); - }); - - it('should not accept (mode, options, tags)', function () { - expect(() => new ReadPreference(PRIMARY, { maxStalenessSeconds }, TAGS)).to.throw( - 'ReadPreference tags must be an array' - ); - }); - }); - it('Should correctly apply collection level read Preference to count', { metadata: { requires: { mongodb: '>=2.6.0', topology: ['single', 'ssl'] } }, diff --git a/test/unit/read_preference.test.ts b/test/unit/read_preference.test.ts new file mode 100644 index 0000000000..a149eda990 --- /dev/null +++ b/test/unit/read_preference.test.ts @@ -0,0 +1,134 @@ +import { ReadPreference } from '../../src'; +import { expect } from 'chai'; + +describe('class ReadPreference', function () { + const maxStalenessSeconds = 1234; + const { PRIMARY, SECONDARY, NEAREST } = ReadPreference; + const TAGS = [{ loc: 'dc' }]; + describe('::constructor', function () { + it('should accept (mode)', function () { + expect(new ReadPreference(PRIMARY)).to.be.an.instanceOf(ReadPreference); + }); + + it('should accept valid (mode, tags)', function () { + expect(new ReadPreference(PRIMARY, [])).to.be.an.instanceOf(ReadPreference); + const p0 = new ReadPreference(NEAREST, TAGS); + expect(p0).to.have.property('mode', NEAREST); + }); + + it('should not accept invalid tags', function () { + expect(() => new ReadPreference(PRIMARY, 'invalid' as any)).to.throw( + 'ReadPreference tags must be an array' + ); + expect( + () => new ReadPreference(PRIMARY, { loc: 'dc' } as any, { maxStalenessSeconds }) + ).to.throw('ReadPreference tags must be an array'); + }); + + it('should accept (mode, options)', function () { + const p1 = new ReadPreference(SECONDARY, { maxStalenessSeconds } as any); + expect(p1.mode).to.equal(SECONDARY); + expect(p1).to.have.property('maxStalenessSeconds', maxStalenessSeconds); + }); + + it('should not accept mode=primary + tags', function () { + expect(() => new ReadPreference(PRIMARY, TAGS)).to.throw( + 'Primary read preference cannot be combined with tags' + ); + }); + + it('should not accept mode=primary + options.maxStalenessSeconds', function () { + expect(() => new ReadPreference(PRIMARY, null, { maxStalenessSeconds })).to.throw( + 'Primary read preference cannot be combined with maxStalenessSeconds' + ); + }); + + it('should not accept mode=primary + options.hedge enabled', function () { + expect(() => new ReadPreference(PRIMARY, null, { hedge: { enabled: true } })).to.throw( + 'Primary read preference cannot be combined with hedge' + ); + }); + + it('should accept (mode=secondary, tags=null, options)', function () { + const p2 = new ReadPreference(SECONDARY, null, { maxStalenessSeconds }); + expect(p2).to.be.an.instanceOf(ReadPreference); + expect(p2).to.have.property('mode', SECONDARY); + expect(p2).to.have.property('maxStalenessSeconds', maxStalenessSeconds); + }); + + it('should accept (mode=secondary, tags, options)', function () { + const p3 = new ReadPreference(SECONDARY, TAGS, { maxStalenessSeconds }); + expect(p3).to.be.an.instanceOf(ReadPreference); + expect(p3).to.have.property('mode', SECONDARY); + expect(p3.tags).to.deep.equal(TAGS); + expect(p3).to.have.property('maxStalenessSeconds', maxStalenessSeconds); + }); + + it('should not accept (mode, options, tags)', function () { + expect( + () => new ReadPreference(PRIMARY, { maxStalenessSeconds } as any, TAGS as any) + ).to.throw('ReadPreference tags must be an array'); + }); + }); + + describe('fromOptions factory method', () => { + it('should return undefined if no options are passed', () => { + const readPreference = ReadPreference.fromOptions(); + expect(readPreference).to.be.undefined; + }); + + context('readPreference is string', () => { + it('should accept { readPreference }', function () { + const readPreference = ReadPreference.fromOptions({ + readPreference: PRIMARY + }); + expect(readPreference).to.be.an.instanceOf(ReadPreference); + expect(readPreference).to.have.property('mode', PRIMARY); + }); + + it('should accept { readPreference, readPreferenceTags }', function () { + const readPreference = ReadPreference.fromOptions({ + readPreference: SECONDARY, + readPreferenceTags: TAGS + }); + expect(readPreference).to.be.an.instanceOf(ReadPreference); + expect(readPreference).to.have.property('mode', SECONDARY); + expect(readPreference.tags).to.deep.equal(TAGS); + }); + + it('should accept { readPreference, maxStalenessSeconds }', function () { + const readPreference = ReadPreference.fromOptions({ + readPreference: SECONDARY, + maxStalenessSeconds: maxStalenessSeconds + }); + expect(readPreference).to.be.an.instanceOf(ReadPreference); + expect(readPreference).to.have.property('mode', SECONDARY); + expect(readPreference).to.have.property('maxStalenessSeconds', maxStalenessSeconds); + }); + + it('should accept { readPreference, hedge }', function () { + const readPreference = ReadPreference.fromOptions({ + readPreference: SECONDARY, + hedge: { + enabled: true + } + }); + expect(readPreference).to.be.an.instanceOf(ReadPreference); + expect(readPreference).to.have.property('mode', SECONDARY); + expect(readPreference.hedge).to.deep.equal({ enabled: true }); + }); + }); + + it('should not accept mode=primary + options.hedge', function () { + expect(() => + ReadPreference.fromOptions({ readPreference: PRIMARY, hedge: { enabled: true } }) + ).to.throw('Primary read preference cannot be combined with hedge'); + }); + + it('should not accept mode=primary + options.maxStalenessSeconds', function () { + expect(() => + ReadPreference.fromOptions({ readPreference: PRIMARY, maxStalenessSeconds }) + ).to.throw('Primary read preference cannot be combined with maxStalenessSeconds'); + }); + }); +});