From 35d02747e5daca6bbeb0fbec7b0192b77ccc5ac9 Mon Sep 17 00:00:00 2001 From: Matt Broadstone Date: Sat, 11 Jan 2020 08:22:42 -0500 Subject: [PATCH] fix: report the correct platform in client metadata This relatively large refactoring ultimately corrects the fact that the platform was not always reported correctly in client metadata during initial handshake. It also takes the steps to localize the creation of that metadata to one place, and makes the metadata consistent across legacy and unified topologies NODE-2418 --- lib/cmap/connection_pool.js | 3 +- lib/core/connection/connect.js | 4 +- lib/core/sdam/server.js | 3 - lib/core/sdam/topology.js | 19 ++++--- lib/core/topologies/mongos.js | 18 ++---- lib/core/topologies/replset.js | 15 ++--- lib/core/topologies/server.js | 13 +++-- lib/core/topologies/shared.js | 60 -------------------- lib/core/utils.js | 50 +++++++++++++++- lib/topologies/mongos.js | 7 --- lib/topologies/native_topology.js | 5 -- lib/topologies/replset.js | 7 --- lib/topologies/server.js | 7 --- lib/topologies/topology_base.js | 29 ++-------- lib/utils.js | 1 - test/functional/core/client_metadata.test.js | 12 ++-- test/functional/mongo_client.test.js | 4 +- test/unit/client_metadata.test.js | 51 +++++++++++++++++ test/unit/core/connect.test.js | 29 ---------- 19 files changed, 143 insertions(+), 194 deletions(-) create mode 100644 test/unit/client_metadata.test.js diff --git a/lib/cmap/connection_pool.js b/lib/cmap/connection_pool.js index 55305c51856..829075aca60 100644 --- a/lib/cmap/connection_pool.js +++ b/lib/cmap/connection_pool.js @@ -131,7 +131,8 @@ class ConnectionPool extends EventEmitter { maxIdleTimeMS: typeof options.maxIdleTimeMS === 'number' ? options.maxIdleTimeMS : 0, waitQueueTimeoutMS: typeof options.waitQueueTimeoutMS === 'number' ? options.waitQueueTimeoutMS : 0, - autoEncrypter: options.autoEncrypter + autoEncrypter: options.autoEncrypter, + metadata: options.metadata }); if (options.minSize > options.maxSize) { diff --git a/lib/core/connection/connect.js b/lib/core/connection/connect.js index 15cfad58601..2922c61b45a 100644 --- a/lib/core/connection/connect.js +++ b/lib/core/connection/connect.js @@ -3,11 +3,11 @@ const net = require('net'); const tls = require('tls'); const Connection = require('./connection'); const Query = require('./commands').Query; -const createClientInfo = require('../topologies/shared').createClientInfo; const MongoError = require('../error').MongoError; const MongoNetworkError = require('../error').MongoNetworkError; const defaultAuthProviders = require('../auth/defaultAuthProviders').defaultAuthProviders; const WIRE_CONSTANTS = require('../wireprotocol/constants'); +const makeClientMetadata = require('../utils').makeClientMetadata; const MAX_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_WIRE_VERSION; const MAX_SUPPORTED_SERVER_VERSION = WIRE_CONSTANTS.MAX_SUPPORTED_SERVER_VERSION; const MIN_SUPPORTED_WIRE_VERSION = WIRE_CONSTANTS.MIN_SUPPORTED_WIRE_VERSION; @@ -105,7 +105,7 @@ function performInitialHandshake(conn, options, _callback) { const handshakeDoc = Object.assign( { ismaster: true, - client: createClientInfo(options), + client: options.metadata || makeClientMetadata(options), compression: compressors }, getSaslSupportedMechs(options) diff --git a/lib/core/sdam/server.js b/lib/core/sdam/server.js index 1935c84dd2a..7855c2a09da 100644 --- a/lib/core/sdam/server.js +++ b/lib/core/sdam/server.js @@ -4,7 +4,6 @@ const ConnectionPool = require('../../cmap/connection_pool').ConnectionPool; const MongoError = require('../error').MongoError; const relayEvents = require('../utils').relayEvents; const BSON = require('../connection/utils').retrieveBSON(); -const createClientInfo = require('../topologies/shared').createClientInfo; const Logger = require('../connection/logger'); const ServerDescription = require('./server_description').ServerDescription; const ReadPreference = require('../topologies/read_preference'); @@ -99,8 +98,6 @@ class Server extends EventEmitter { BSON.Symbol, BSON.Timestamp ]), - // client metadata for the initial handshake - clientInfo: createClientInfo(options), // the server state state: STATE_CLOSED, credentials: options.credentials, diff --git a/lib/core/sdam/topology.js b/lib/core/sdam/topology.js index 02a65ac6b17..2fbefee707f 100644 --- a/lib/core/sdam/topology.js +++ b/lib/core/sdam/topology.js @@ -16,7 +16,6 @@ const createCompressionInfo = require('../topologies/shared').createCompressionI const isRetryableError = require('../error').isRetryableError; const isSDAMUnrecoverableError = require('../error').isSDAMUnrecoverableError; const ClientSession = require('../sessions').ClientSession; -const createClientInfo = require('../topologies/shared').createClientInfo; const MongoError = require('../error').MongoError; const resolveClusterTime = require('../topologies/shared').resolveClusterTime; const SrvPoller = require('./srv_polling').SrvPoller; @@ -25,6 +24,7 @@ const makeStateMachine = require('../utils').makeStateMachine; const eachAsync = require('../utils').eachAsync; const emitDeprecationWarning = require('../../utils').emitDeprecationWarning; const ServerSessionPool = require('../sessions').ServerSessionPool; +const makeClientMetadata = require('../utils').makeClientMetadata; const common = require('./common'); const drainTimerQueue = common.drainTimerQueue; @@ -119,6 +119,13 @@ class Topology extends EventEmitter { } options = Object.assign({}, common.TOPOLOGY_DEFAULTS, options); + options = Object.freeze( + Object.assign(options, { + metadata: makeClientMetadata(options), + compression: { compressors: createCompressionInfo(options) } + }) + ); + DEPRECATED_OPTIONS.forEach(optionName => { if (options[optionName]) { emitDeprecationWarning( @@ -196,12 +203,6 @@ class Topology extends EventEmitter { connectionTimers: new Set() }; - // amend options for server instance creation - this.s.options.compression = { compressors: createCompressionInfo(options) }; - - // add client info - this.s.clientInfo = createClientInfo(options); - if (options.srvHost) { this.s.srvPoller = options.srvPoller || @@ -705,8 +706,8 @@ class Topology extends EventEmitter { return new CursorClass(topology, ns, cmd, options); } - get clientInfo() { - return this.s.clientInfo; + get clientMetadata() { + return this.s.options.metadata; } isConnected() { diff --git a/lib/core/topologies/mongos.js b/lib/core/topologies/mongos.js index 681b01fd70e..29371931af7 100644 --- a/lib/core/topologies/mongos.js +++ b/lib/core/topologies/mongos.js @@ -8,16 +8,15 @@ const Logger = require('../connection/logger'); const retrieveBSON = require('../connection/utils').retrieveBSON; const MongoError = require('../error').MongoError; const Server = require('./server'); -const clone = require('./shared').clone; const diff = require('./shared').diff; const cloneOptions = require('./shared').cloneOptions; -const createClientInfo = require('./shared').createClientInfo; const SessionMixins = require('./shared').SessionMixins; const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported; const relayEvents = require('../utils').relayEvents; const isRetryableError = require('../error').isRetryableError; const BSON = retrieveBSON(); const getMMAPError = require('./shared').getMMAPError; +const makeClientMetadata = require('../utils').makeClientMetadata; /** * @fileOverview The **Mongos** class is a class that represents a Mongos Proxy topology and is @@ -116,7 +115,7 @@ var Mongos = function(seedlist, options) { // Internal state this.s = { - options: Object.assign({}, options), + options: Object.assign({ metadata: makeClientMetadata(options) }, options), // BSON instance bson: options.bson || @@ -153,14 +152,9 @@ var Mongos = function(seedlist, options) { // Are we running in debug mode debug: typeof options.debug === 'boolean' ? options.debug : false, // localThresholdMS - localThresholdMS: options.localThresholdMS || 15, - // Client info - clientInfo: createClientInfo(options) + localThresholdMS: options.localThresholdMS || 15 }; - // Set the client info - this.s.options.clientInfo = createClientInfo(options); - // Log info warning if the socketTimeout < haInterval as it will cause // a lot of recycled connections to happen. if ( @@ -265,8 +259,7 @@ Mongos.prototype.connect = function(options) { Object.assign({}, self.s.options, x, options, { reconnect: false, monitoring: false, - parent: self, - clientInfo: clone(self.s.clientInfo) + parent: self }) ); @@ -607,8 +600,7 @@ function reconnectProxies(self, proxies, callback) { port: parseInt(_server.name.split(':')[1], 10), reconnect: false, monitoring: false, - parent: self, - clientInfo: clone(self.s.clientInfo) + parent: self }) ); diff --git a/lib/core/topologies/replset.js b/lib/core/topologies/replset.js index 0f03e9940de..b289d59a345 100644 --- a/lib/core/topologies/replset.js +++ b/lib/core/topologies/replset.js @@ -10,10 +10,8 @@ const Logger = require('../connection/logger'); const MongoError = require('../error').MongoError; const Server = require('./server'); const ReplSetState = require('./replset_state'); -const clone = require('./shared').clone; const Timeout = require('./shared').Timeout; const Interval = require('./shared').Interval; -const createClientInfo = require('./shared').createClientInfo; const SessionMixins = require('./shared').SessionMixins; const isRetryableWritesSupported = require('./shared').isRetryableWritesSupported; const relayEvents = require('../utils').relayEvents; @@ -21,6 +19,7 @@ const isRetryableError = require('../error').isRetryableError; const BSON = retrieveBSON(); const calculateDurationInMs = require('../utils').calculateDurationInMs; const getMMAPError = require('./shared').getMMAPError; +const makeClientMetadata = require('../utils').makeClientMetadata; // // States @@ -140,7 +139,7 @@ var ReplSet = function(seedlist, options) { // Internal state this.s = { - options: Object.assign({}, options), + options: Object.assign({ metadata: makeClientMetadata(options) }, options), // BSON instance bson: options.bson || @@ -187,9 +186,7 @@ var ReplSet = function(seedlist, options) { // Connect function options passed in connectOptions: {}, // Are we running in debug mode - debug: typeof options.debug === 'boolean' ? options.debug : false, - // Client info - clientInfo: createClientInfo(options) + debug: typeof options.debug === 'boolean' ? options.debug : false }; // Add handler for topology change @@ -369,8 +366,7 @@ function connectNewServers(self, servers, callback) { port: parseInt(_server.split(':')[1], 10), reconnect: false, monitoring: false, - parent: self, - clientInfo: clone(self.s.clientInfo) + parent: self }) ); @@ -918,8 +914,7 @@ ReplSet.prototype.connect = function(options) { Object.assign({}, self.s.options, x, options, { reconnect: false, monitoring: false, - parent: self, - clientInfo: clone(self.s.clientInfo) + parent: self }) ); }); diff --git a/lib/core/topologies/server.js b/lib/core/topologies/server.js index c81d5e8e40c..6f6de12eaa7 100644 --- a/lib/core/topologies/server.js +++ b/lib/core/topologies/server.js @@ -13,13 +13,13 @@ var inherits = require('util').inherits, wireProtocol = require('../wireprotocol'), CoreCursor = require('../cursor').CoreCursor, sdam = require('./shared'), - createClientInfo = require('./shared').createClientInfo, createCompressionInfo = require('./shared').createCompressionInfo, resolveClusterTime = require('./shared').resolveClusterTime, SessionMixins = require('./shared').SessionMixins, relayEvents = require('../utils').relayEvents; const collationNotSupported = require('../utils').collationNotSupported; +const makeClientMetadata = require('../utils').makeClientMetadata; // Used for filtering out fields for loggin var debugFields = [ @@ -120,7 +120,7 @@ var Server = function(options) { // Internal state this.s = { // Options - options: options, + options: Object.assign({ metadata: makeClientMetadata(options) }, options), // Logger logger: Logger('Server', options), // Factory overrides @@ -175,8 +175,6 @@ var Server = function(options) { this.initialConnect = true; // Default type this._type = 'server'; - // Set the client info - this.clientInfo = createClientInfo(options); // Max Stalleness values // last time we updated the ismaster state @@ -212,6 +210,13 @@ Object.defineProperty(Server.prototype, 'logicalSessionTimeoutMinutes', { } }); +Object.defineProperty(Server.prototype, 'clientMetadata', { + enumerable: true, + get: function() { + return this.s.options.metadata; + } +}); + // In single server deployments we track the clusterTime directly on the topology, however // in Mongos and ReplSet deployments we instead need to delegate the clusterTime up to the // tracking objects so we can ensure we are gossiping the maximum time received from the diff --git a/lib/core/topologies/shared.js b/lib/core/topologies/shared.js index d69e88bf40d..c0d0f14d69c 100644 --- a/lib/core/topologies/shared.js +++ b/lib/core/topologies/shared.js @@ -1,8 +1,5 @@ 'use strict'; - -const os = require('os'); const ReadPreference = require('./read_preference'); -const Buffer = require('safe-buffer').Buffer; const TopologyType = require('../sdam/common').TopologyType; const MongoError = require('../error').MongoError; @@ -18,62 +15,6 @@ function emitSDAMEvent(self, event, description) { } } -// Get package.json variable -const driverVersion = require('../../../package.json').version; -const nodejsVersion = `'Node.js ${process.version}, ${os.endianness}`; -const type = os.type(); -const name = process.platform; -const architecture = process.arch; -const release = os.release(); - -function createClientInfo(options) { - const clientInfo = options.clientInfo - ? clone(options.clientInfo) - : { - driver: { - name: 'nodejs', - version: driverVersion - }, - os: { - type: type, - name: name, - architecture: architecture, - version: release - } - }; - - if (options.useUnifiedTopology) { - clientInfo.platform = `${nodejsVersion} (${options.useUnifiedTopology ? 'unified' : 'legacy'})`; - } - - // Do we have an application specific string - if (options.appname) { - // Cut at 128 bytes - var buffer = Buffer.from(options.appname); - // Return the truncated appname - var appname = buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname; - // Add to the clientInfo - clientInfo.application = { name: appname }; - } - - // support optionally provided wrapping driver info - if (options.driverInfo) { - if (options.driverInfo.name) { - clientInfo.driver.name = `${clientInfo.driver.name}|${options.driverInfo.name}`; - } - - if (options.driverInfo.version) { - clientInfo.driver.version = `${clientInfo.driver.version}|${options.driverInfo.version}`; - } - - if (options.driverInfo.platform) { - clientInfo.platform = `${clientInfo.platform}|${options.driverInfo.platform}`; - } - } - - return clientInfo; -} - function createCompressionInfo(options) { if (!options.compression || !options.compression.compressors) { return []; @@ -475,7 +416,6 @@ module.exports.getTopologyType = getTopologyType; module.exports.emitServerDescriptionChanged = emitServerDescriptionChanged; module.exports.emitTopologyDescriptionChanged = emitTopologyDescriptionChanged; module.exports.cloneOptions = cloneOptions; -module.exports.createClientInfo = createClientInfo; module.exports.createCompressionInfo = createCompressionInfo; module.exports.clone = clone; module.exports.diff = diff; diff --git a/lib/core/utils.js b/lib/core/utils.js index 9e71f09f473..d9f487db01e 100644 --- a/lib/core/utils.js +++ b/lib/core/utils.js @@ -1,5 +1,5 @@ 'use strict'; - +const os = require('os'); const crypto = require('crypto'); const requireOptional = require('require_optional'); @@ -210,6 +210,51 @@ function makeStateMachine(stateTable) { }; } +function makeClientMetadata(options) { + options = options || {}; + + const metadata = { + driver: { + name: 'nodejs', + version: require('../../package.json').version + }, + os: { + type: os.type(), + name: process.platform, + architecture: process.arch, + version: os.release() + }, + platform: `'Node.js ${process.version}, ${os.endianness} (${ + options.useUnifiedTopology ? 'unified' : 'legacy' + })` + }; + + // support optionally provided wrapping driver info + if (options.driverInfo) { + if (options.driverInfo.name) { + metadata.driver.name = `${metadata.driver.name}|${options.driverInfo.name}`; + } + + if (options.driverInfo.version) { + metadata.version = `${metadata.driver.version}|${options.driverInfo.version}`; + } + + if (options.driverInfo.platform) { + metadata.platform = `${metadata.platform}|${options.driverInfo.platform}`; + } + } + + if (options.appname) { + // MongoDB requires the appname not exceed a byte length of 128 + const buffer = Buffer.from(options.appname); + metadata.application = { + name: buffer.length > 128 ? buffer.slice(0, 128).toString('utf8') : options.appname + }; + } + + return metadata; +} + module.exports = { uuidV4, calculateDurationInMs, @@ -224,5 +269,6 @@ module.exports = { arrayStrictEqual, tagsStrictEqual, errorStrictEqual, - makeStateMachine + makeStateMachine, + makeClientMetadata }; diff --git a/lib/topologies/mongos.js b/lib/topologies/mongos.js index 5250a8a5814..10e66d2151b 100644 --- a/lib/topologies/mongos.js +++ b/lib/topologies/mongos.js @@ -168,13 +168,6 @@ class Mongos extends TopologyBase { // Translate all the options to the core types clonedOptions = translateOptions(clonedOptions, socketOptions); - // Build default client information - clonedOptions.clientInfo = this.clientInfo; - // Do we have an application specific string - if (options.appname) { - clonedOptions.clientInfo.application = { name: options.appname }; - } - // Internal state this.s = { // Create the Mongos diff --git a/lib/topologies/native_topology.js b/lib/topologies/native_topology.js index ce53f7f3e96..778ddc9fab7 100644 --- a/lib/topologies/native_topology.js +++ b/lib/topologies/native_topology.js @@ -35,11 +35,6 @@ class NativeTopology extends Topology { clonedOptions = translateOptions(clonedOptions, socketOptions); super(servers, clonedOptions); - - // Do we have an application specific string - if (options.appname) { - this.s.clientInfo.application = { name: options.appname }; - } } capabilities() { diff --git a/lib/topologies/replset.js b/lib/topologies/replset.js index d78ae13b616..69df26d19e0 100644 --- a/lib/topologies/replset.js +++ b/lib/topologies/replset.js @@ -175,13 +175,6 @@ class ReplSet extends TopologyBase { // Translate all the options to the core types clonedOptions = translateOptions(clonedOptions, socketOptions); - // Build default client information - clonedOptions.clientInfo = this.clientInfo; - // Do we have an application specific string - if (options.appname) { - clonedOptions.clientInfo.application = { name: options.appname }; - } - // Create the ReplSet var coreTopology = new CReplSet(seedlist, clonedOptions); diff --git a/lib/topologies/server.js b/lib/topologies/server.js index 2d6c65359dd..3079cb9953e 100644 --- a/lib/topologies/server.js +++ b/lib/topologies/server.js @@ -168,13 +168,6 @@ class Server extends TopologyBase { // Translate all the options to the core types clonedOptions = translateOptions(clonedOptions, socketOptions); - // Build default client information - clonedOptions.clientInfo = this.clientInfo; - // Do we have an application specific string - if (options.appname) { - clonedOptions.clientInfo.application = { name: options.appname }; - } - // Define the internal properties this.s = { // Create an instance of a server instance from core module diff --git a/lib/topologies/topology_base.js b/lib/topologies/topology_base.js index e74cb9ff601..967b4cd4627 100644 --- a/lib/topologies/topology_base.js +++ b/lib/topologies/topology_base.js @@ -3,7 +3,6 @@ const EventEmitter = require('events'), MongoError = require('../core').MongoError, f = require('util').format, - os = require('os'), translateReadPreference = require('../utils').translateReadPreference, ClientSession = require('../core').Sessions.ClientSession; @@ -254,33 +253,9 @@ var ServerCapabilities = function(ismaster) { setup_get_property(this, 'commandsTakeCollation', commandsTakeCollation); }; -// Get package.json variable -const driverVersion = require('../../package.json').version, - nodejsversion = f('Node.js %s, %s', process.version, os.endianness()), - type = os.type(), - name = process.platform, - architecture = process.arch, - release = os.release(); - class TopologyBase extends EventEmitter { constructor() { super(); - - // Build default client information - this.clientInfo = { - driver: { - name: 'nodejs', - version: driverVersion - }, - os: { - type: type, - name: name, - architecture: architecture, - version: release - }, - platform: nodejsversion - }; - this.setMaxListeners(Infinity); } @@ -304,6 +279,10 @@ class TopologyBase extends EventEmitter { return this.s.coreTopology.endSessions(sessions, callback); } + get clientMetadata() { + return this.s.coreTopology.s.options.metadata; + } + // Server capabilities capabilities() { if (this.s.sCapabilities) return this.s.sCapabilities; diff --git a/lib/utils.js b/lib/utils.js index 052bcabdade..dd6cbe8ce88 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -1,5 +1,4 @@ 'use strict'; - const MongoError = require('./core/error').MongoError; const ReadPreference = require('./core/topologies/read_preference'); const WriteConcern = require('./write_concern'); diff --git a/test/functional/core/client_metadata.test.js b/test/functional/core/client_metadata.test.js index 7bdcf014457..62089f36f50 100644 --- a/test/functional/core/client_metadata.test.js +++ b/test/functional/core/client_metadata.test.js @@ -22,7 +22,7 @@ describe('Client metadata tests', function() { } ); - expect(server.clientInfo.application.name).to.equal('My application name'); + expect(server.clientMetadata.application.name).to.equal('My application name'); done(); } }); @@ -53,9 +53,8 @@ describe('Client metadata tests', function() { server.on('connect', function(_server) { _server.s.replicaSetState.allServers().forEach(function(x) { - // console.dir(x.clientInfo) - expect(x.clientInfo.application.name).to.equal('My application name'); - expect(x.clientInfo.platform.split('mongodb-core').length).to.equal(2); + expect(x.clientMetadata.application.name).to.equal('My application name'); + expect(x.clientMetadata.platform.split('mongodb-core').length).to.equal(2); }); _server.destroy(done); @@ -86,9 +85,8 @@ describe('Client metadata tests', function() { // Add event listeners _server.once('connect', function(server) { server.connectedProxies.forEach(function(x) { - // console.dir(x.clientInfo) - expect(x.clientInfo.application.name).to.equal('My application name'); - expect(x.clientInfo.platform.split('mongodb-core').length).to.equal(2); + expect(x.clientMetadata.application.name).to.equal('My application name'); + expect(x.clientMetadata.platform.split('mongodb-core').length).to.equal(2); }); server.destroy(done); diff --git a/test/functional/mongo_client.test.js b/test/functional/mongo_client.test.js index a3878c1e57b..c46c81aea9d 100644 --- a/test/functional/mongo_client.test.js +++ b/test/functional/mongo_client.test.js @@ -642,7 +642,7 @@ describe('MongoClient', function() { const client = configuration.newClient(url); client.connect(function(err, client) { test.equal(null, err); - test.equal('hello world', client.topology.clientInfo.application.name); + test.equal('hello world', client.topology.clientMetadata.application.name); client.close(done); }); @@ -664,7 +664,7 @@ describe('MongoClient', function() { const client = configuration.newClient(url, { appname: 'hello world' }); client.connect(err => { test.equal(null, err); - test.equal('hello world', client.topology.clientInfo.application.name); + test.equal('hello world', client.topology.clientMetadata.application.name); client.close(done); }); diff --git a/test/unit/client_metadata.test.js b/test/unit/client_metadata.test.js new file mode 100644 index 00000000000..21b51274189 --- /dev/null +++ b/test/unit/client_metadata.test.js @@ -0,0 +1,51 @@ +'use strict'; +const mock = require('mongodb-mock-server'); +const expect = require('chai').expect; + +describe('Client Metadata', function() { + let mockServer; + before(() => mock.createServer().then(server => (mockServer = server))); + after(() => mock.cleanup()); + + it('should report the correct platform in client metadata', function(done) { + const ismasters = []; + mockServer.setMessageHandler(request => { + const doc = request.document; + if (doc.ismaster) { + ismasters.push(doc); + request.reply(mock.DEFAULT_ISMASTER); + } else { + request.reply({ ok: 1 }); + } + }); + + const isUnifiedTopology = this.configuration.usingUnifiedTopology(); + const client = this.configuration.newClient(`mongodb://${mockServer.uri()}/`); + client.connect(err => { + expect(err).to.not.exist; + this.defer(() => client.close()); + + client.db().command({ ping: 1 }, err => { + expect(err).to.not.exist; + + if (isUnifiedTopology) { + expect(ismasters).to.have.length.greaterThan(1); + ismasters.forEach(ismaster => + expect(ismaster) + .nested.property('client.platform') + .to.match(/unified/) + ); + } else { + expect(ismasters).to.have.length(1); + ismasters.forEach(ismaster => + expect(ismaster) + .nested.property('client.platform') + .to.match(/legacy/) + ); + } + + done(); + }); + }); + }); +}); diff --git a/test/unit/core/connect.test.js b/test/unit/core/connect.test.js index a3db4940c60..312553771cc 100644 --- a/test/unit/core/connect.test.js +++ b/test/unit/core/connect.test.js @@ -100,35 +100,6 @@ describe('Connect Tests', function() { }); }); - it( - 'should report the correct metadata for unified topology', - { requires: { unifiedTopology: true, topology: ['single'] } }, - function(done) { - let ismaster; - test.server.setMessageHandler(request => { - const doc = request.document; - const $clusterTime = genClusterTime(Date.now()); - if (doc.ismaster) { - ismaster = doc; - request.reply( - Object.assign({}, mock.DEFAULT_ISMASTER, { - $clusterTime, - arbiterOnly: true - }) - ); - } - }); - - const topology = this.configuration.newTopology(test.connectOptions); - topology.connect(test.connectOptions, err => { - expect(err).to.not.exist; - const platform = ismaster.client.platform; - expect(platform).to.match(/unified/); - topology.close(done); - }); - } - ); - it('should allow a cancellaton token', function(done) { const cancellationToken = new EventEmitter(); setTimeout(() => cancellationToken.emit('cancel'), 500);