diff --git a/src/operations/operation.ts b/src/operations/operation.ts index 1142b6cf9e5..7fc4f73978a 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -49,7 +49,7 @@ export abstract class AbstractOperation { readPreference: ReadPreference; server!: Server; bypassPinningCheck: boolean; - trySecondaryWrite = false; + trySecondaryWrite: boolean; // BSON serialization options bsonOptions?: BSONSerializeOptions; @@ -73,6 +73,7 @@ export abstract class AbstractOperation { this.options = options; this.bypassPinningCheck = !!options.bypassPinningCheck; + this.trySecondaryWrite = false; } abstract execute(server: Server, session: ClientSession, callback: Callback): void; diff --git a/src/sdam/server_selection.ts b/src/sdam/server_selection.ts index 95010d66f9d..a39304841e2 100644 --- a/src/sdam/server_selection.ts +++ b/src/sdam/server_selection.ts @@ -46,6 +46,8 @@ export function secondaryWritableServerSelector( /* eslint no-console: 0 */ console.log('select', readPreference, wireVersion); if (!readPreference || (wireVersion && wireVersion < MIN_SECONDARY_WRITE_WIRE_VERSION)) { + /* eslint no-console: 0 */ + console.log('force select primary'); return readPreferenceServerSelector(ReadPreference.primary); } return readPreferenceServerSelector(readPreference); diff --git a/test/functional/crud_spec.test.js b/test/functional/crud_spec.test.js index 4e2b8e27822..cc26c0e9f60 100644 --- a/test/functional/crud_spec.test.js +++ b/test/functional/crud_spec.test.js @@ -424,7 +424,7 @@ describe('CRUD spec v1', function () { } }); -describe('CRUD unified', function () { +describe.only('CRUD unified', function () { for (const crudSpecTest of loadSpecTests('crud/unified')) { expect(crudSpecTest).to.exist; const testDescription = String(crudSpecTest.description); diff --git a/test/unit/sdam/server_selection.test.js b/test/unit/sdam/server_selection.test.js index 6e6c799ca31..715615a4be8 100644 --- a/test/unit/sdam/server_selection.test.js +++ b/test/unit/sdam/server_selection.test.js @@ -11,46 +11,107 @@ const { ServerDescription } = require('../../../src/sdam/server_description'); const { TopologyDescription } = require('../../../src/sdam/topology_description'); const { TopologyType } = require('../../../src/sdam/common'); -describe('ServerSelector', function () { +describe('server selection', function () { + const primary = new ServerDescription('127.0.0.1:27017', { + setName: 'test', + isWritablePrimary: true, + ok: 1 + }); + const secondary = new ServerDescription('127.0.0.1:27018', { + setName: 'test', + secondary: true, + ok: 1 + }); + const mongos = new ServerDescription('127.0.0.1:27019', { + msg: 'isdbgrid', + ok: 1 + }); + const loadBalancer = new ServerDescription('127.0.0.1:27020', { ok: 1 }, { loadBalanced: true }); + const single = new ServerDescription('127.0.0.1:27021', { + isWritablePrimary: true, + ok: 1 + }); + describe('#secondaryWritableServerSelector', function () { - const primary = new ServerDescription('127.0.0.1:27017', { - setName: 'test', - isWritablePrimary: true, - ok: 1 - }); - const secondary = new ServerDescription('127.0.0.1:27018', { - setName: 'test', - secondary: true, - ok: 1 - }); - const serverDescriptions = new Map(); - serverDescriptions.set('127.0.0.1:27017', primary); - serverDescriptions.set('127.0.0.1:27018', secondary); - - context('when the common server version is >= 5.0', function () { - const topologyDescription = new TopologyDescription( - TopologyType.ReplicaSetWithPrimary, - serverDescriptions, - 'test', - MIN_SECONDARY_WRITE_WIRE_VERSION, - new ObjectId(), - MIN_SECONDARY_WRITE_WIRE_VERSION - ); - - context('when a read preference is provided', function () { - const selector = secondaryWritableServerSelector( + context('when the topology is a replica set', function () { + const serverDescriptions = new Map(); + serverDescriptions.set('127.0.0.1:27017', primary); + serverDescriptions.set('127.0.0.1:27018', secondary); + + context('when the common server version is >= 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.ReplicaSetWithPrimary, + serverDescriptions, + 'test', MIN_SECONDARY_WRITE_WIRE_VERSION, - ReadPreference.secondary + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION ); - const server = selector(topologyDescription, Array.from(serverDescriptions.values())); - it('uses the provided read preference', function () { - expect(server).to.deep.equal([secondary]); + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('uses the provided read preference', function () { + expect(server).to.deep.equal([secondary]); + }); + }); + + context('when a read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a primary', function () { + expect(server).to.deep.equal([primary]); + }); }); }); - context('when a read preference is not provided', function () { - const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); + context('when the common server version is < 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.ReplicaSetWithPrimary, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION - 1 + ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a primary', function () { + expect(server).to.deep.equal([primary]); + }); + }); + + context('when read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a primary', function () { + expect(server).to.deep.equal([primary]); + }); + }); + }); + + context('when a common wire version is not provided', function () { + const topologyDescription = new TopologyDescription( + TopologyType.ReplicaSetWithPrimary, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + const selector = secondaryWritableServerSelector(); const server = selector(topologyDescription, Array.from(serverDescriptions.values())); it('selects a primary', function () { @@ -59,52 +120,261 @@ describe('ServerSelector', function () { }); }); - context('when the common server version is < 5.0', function () { - const topologyDescription = new TopologyDescription( - TopologyType.ReplicaSetWithPrimary, - serverDescriptions, - 'test', - MIN_SECONDARY_WRITE_WIRE_VERSION - 1, - new ObjectId(), - MIN_SECONDARY_WRITE_WIRE_VERSION - 1 - ); - - context('when a read preference is provided', function () { - const selector = secondaryWritableServerSelector( + context('when the topology is sharded', function () { + const serverDescriptions = new Map(); + serverDescriptions.set('127.0.0.1:27019', mongos); + + context('when the common server version is >= 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.Sharded, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a mongos', function () { + expect(server).to.deep.equal([mongos]); + }); + }); + + context('when a read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a mongos', function () { + expect(server).to.deep.equal([mongos]); + }); + }); + }); + + context('when the common server version is < 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.Sharded, + serverDescriptions, + 'test', MIN_SECONDARY_WRITE_WIRE_VERSION - 1, - ReadPreference.secondary + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION - 1 ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a mongos', function () { + expect(server).to.deep.equal([mongos]); + }); + }); + + context('when read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a mongos', function () { + expect(server).to.deep.equal([mongos]); + }); + }); + }); + + context('when a common wire version is not provided', function () { + const topologyDescription = new TopologyDescription( + TopologyType.Sharded, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + const selector = secondaryWritableServerSelector(); const server = selector(topologyDescription, Array.from(serverDescriptions.values())); - it('selects a primary', function () { - expect(server).to.deep.equal([primary]); + it('selects a mongos', function () { + expect(server).to.deep.equal([mongos]); + }); + }); + }); + + context('when the topology is load balanced', function () { + const serverDescriptions = new Map(); + serverDescriptions.set('127.0.0.1:27020', loadBalancer); + + context('when the common server version is >= 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.LoadBalanced, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a load balancer', function () { + expect(server).to.deep.equal([loadBalancer]); + }); + }); + + context('when a read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a load balancer', function () { + expect(server).to.deep.equal([loadBalancer]); + }); }); }); - context('when read preference is not provided', function () { - const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); + context('when the common server version is < 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.LoadBalanced, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION - 1 + ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a load balancer', function () { + expect(server).to.deep.equal([loadBalancer]); + }); + }); + + context('when read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a load balancer', function () { + expect(server).to.deep.equal([loadBalancer]); + }); + }); + }); + + context('when a common wire version is not provided', function () { + const topologyDescription = new TopologyDescription( + TopologyType.LoadBalanced, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + const selector = secondaryWritableServerSelector(); const server = selector(topologyDescription, Array.from(serverDescriptions.values())); - it('selects a primary', function () { - expect(server).to.deep.equal([primary]); + it('selects a load balancer', function () { + expect(server).to.deep.equal([loadBalancer]); }); }); }); - context('when a common wire version is not provided', function () { - const topologyDescription = new TopologyDescription( - TopologyType.ReplicaSetWithPrimary, - serverDescriptions, - 'test', - MIN_SECONDARY_WRITE_WIRE_VERSION, - new ObjectId(), - MIN_SECONDARY_WRITE_WIRE_VERSION - ); - const selector = secondaryWritableServerSelector(); - const server = selector(topologyDescription, Array.from(serverDescriptions.values())); - - it('selects a primary', function () { - expect(server).to.deep.equal([primary]); + context('when the topology is single', function () { + const serverDescriptions = new Map(); + serverDescriptions.set('127.0.0.1:27020', single); + + context('when the common server version is >= 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.Single, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a standalone', function () { + expect(server).to.deep.equal([single]); + }); + }); + + context('when a read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a standalone', function () { + expect(server).to.deep.equal([single]); + }); + }); + }); + + context('when the common server version is < 5.0', function () { + const topologyDescription = new TopologyDescription( + TopologyType.Single, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION - 1 + ); + + context('when a read preference is provided', function () { + const selector = secondaryWritableServerSelector( + MIN_SECONDARY_WRITE_WIRE_VERSION - 1, + ReadPreference.secondary + ); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a standalone', function () { + expect(server).to.deep.equal([single]); + }); + }); + + context('when read preference is not provided', function () { + const selector = secondaryWritableServerSelector(MIN_SECONDARY_WRITE_WIRE_VERSION - 1); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a standalone', function () { + expect(server).to.deep.equal([single]); + }); + }); + }); + + context('when a common wire version is not provided', function () { + const topologyDescription = new TopologyDescription( + TopologyType.Single, + serverDescriptions, + 'test', + MIN_SECONDARY_WRITE_WIRE_VERSION, + new ObjectId(), + MIN_SECONDARY_WRITE_WIRE_VERSION + ); + const selector = secondaryWritableServerSelector(); + const server = selector(topologyDescription, Array.from(serverDescriptions.values())); + + it('selects a standalone', function () { + expect(server).to.deep.equal([single]); + }); }); }); });