From eb31ad849e9d232aec7139f0a309ef768714ce3e Mon Sep 17 00:00:00 2001 From: Warren James Date: Tue, 10 Dec 2024 13:36:09 -0500 Subject: [PATCH 1/9] wip --- src/client-side-encryption/auto_encrypter.ts | 1 + src/cmap/connection.ts | 2 +- src/cmap/wire_protocol/responses.ts | 4 ++-- src/connection_string.ts | 17 +++++------------ src/constants.ts | 4 ++-- src/mongo_client.ts | 6 +++++- src/operations/execute_operation.ts | 4 ++-- src/sdam/topology.ts | 2 +- ...nt_side_encryption.prose.12.deadlock.test.ts | 2 +- .../client-side-encryption/driver.test.ts | 6 +++--- ...command_logging_and_monitoring.prose.test.ts | 2 +- .../node-specific/feature_flags.test.ts | 12 ++++++------ test/integration/node-specific/ipv6.test.ts | 2 +- .../node-specific/mongo_client.test.ts | 8 ++++---- test/tools/spec-runner/index.js | 2 +- test/tools/unified-spec-runner/entities.ts | 6 +++--- .../auto_encrypter.test.ts | 12 ++++++------ test/unit/connection_string.test.ts | 10 +++++----- test/unit/mongo_client.test.ts | 2 +- test/unit/tools/mongodb-legacy.test.ts | 2 +- 20 files changed, 52 insertions(+), 54 deletions(-) diff --git a/src/client-side-encryption/auto_encrypter.ts b/src/client-side-encryption/auto_encrypter.ts index edf731b92ac..08b72af3993 100644 --- a/src/client-side-encryption/auto_encrypter.ts +++ b/src/client-side-encryption/auto_encrypter.ts @@ -160,6 +160,7 @@ export class AutoEncrypter { _mongocrypt: MongoCrypt; /** + * @internal * Used by devtools to enable decorating decryption results. * * When set and enabled, `decrypt` will automatically recursively diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 6df81b34d94..bf36bfe8d83 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -889,7 +889,7 @@ export class CryptoConnection extends Connection { const decryptedResponse = responseType?.make(result) ?? deserialize(result, options); - if (autoEncrypter[kDecorateResult]) { + if (autoEncrypter.__decorateDecryptionResult) { if (responseType == null) { decorateDecryptionResult(decryptedResponse, encryptedResponse.toObject(), true); } else if (decryptedResponse instanceof CursorResponse) { diff --git a/src/cmap/wire_protocol/responses.ts b/src/cmap/wire_protocol/responses.ts index 1d20566e2d5..7f358a8a47c 100644 --- a/src/cmap/wire_protocol/responses.ts +++ b/src/cmap/wire_protocol/responses.ts @@ -221,9 +221,9 @@ export class MongoDBResponse extends OnDemandDocument { export class CursorResponse extends MongoDBResponse { /** * Devtools need to know which keys were encrypted before the driver automatically decrypted them. - * If decorating is enabled (`Symbol.for('@@mdb.decorateDecryptionResult')`), this field will be set, + * If decorating is enabled (`__decorateDecryptionResult`), this field will be set, * storing the original encrypted response from the server, so that we can build an object that has - * the list of BSON keys that were encrypted stored at a well known symbol: `Symbol.for('@@mdb.decryptedKeys')`. + * the list of BSON keys that were encrypted stored at a well known symbol: `__decryptedKeys`. */ encryptedResponse?: MongoDBResponse; /** diff --git a/src/connection_string.ts b/src/connection_string.ts index ce20b9e90a9..b2e3765e318 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -249,13 +249,6 @@ export function parseOptions( const mongoOptions = Object.create(null); - // Feature flags - for (const flag of Object.getOwnPropertySymbols(options)) { - if (FEATURE_FLAGS.has(flag)) { - mongoOptions[flag] = options[flag]; - } - } - mongoOptions.hosts = isSRV ? [] : hosts.map(HostAddress.fromString); const urlOptions = new CaseInsensitiveMap(); @@ -515,7 +508,7 @@ export function parseOptions( ); } - const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger'); + const loggerFeatureFlag = '__enableMongoLogger'; mongoOptions[loggerFeatureFlag] = mongoOptions[loggerFeatureFlag] ?? false; let loggerEnvOptions: MongoLoggerEnvOptions = {}; @@ -530,7 +523,7 @@ export function parseOptions( MONGODB_LOG_ALL: process.env.MONGODB_LOG_ALL, MONGODB_LOG_MAX_DOCUMENT_LENGTH: process.env.MONGODB_LOG_MAX_DOCUMENT_LENGTH, MONGODB_LOG_PATH: process.env.MONGODB_LOG_PATH, - ...mongoOptions[Symbol.for('@@mdb.internalLoggerConfig')] + ...mongoOptions['__internalLoggerConfig'] }; loggerClientOptions = { mongodbLogPath: mongoOptions.mongodbLogPath, @@ -1331,7 +1324,7 @@ export const DEFAULT_OPTIONS = new CaseInsensitiveMap( * @internal */ export const FEATURE_FLAGS = new Set([ - Symbol.for('@@mdb.skipPingOnConnect'), - Symbol.for('@@mdb.enableMongoLogger'), - Symbol.for('@@mdb.internalLoggerConfig') + '__skipPingOnConnect', + '__enableMongoLogger', + '__internalLoggerConfig' ]); diff --git a/src/constants.ts b/src/constants.ts index 623b6c919b1..430afa1a9b7 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -172,6 +172,6 @@ export const LEGACY_HELLO_COMMAND_CAMEL_CASE = 'isMaster'; // the objects (and class) that we expect to see them on and prevent TS // errors. /** @internal */ -export const kDecorateResult = Symbol.for('@@mdb.decorateDecryptionResult'); +export const kDecorateResult = '__decorateDecryptionResult'; /** @internal */ -export const kDecoratedKeys = Symbol.for('@@mdb.decryptedKeys'); +export const kDecoratedKeys = '__decryptedKeys'; diff --git a/src/mongo_client.ts b/src/mongo_client.ts index dea069cc949..395b269eaeb 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -299,7 +299,11 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC mongodbLogMaxDocumentLength?: number; /** @internal */ - [featureFlag: symbol]: any; + __skipPingOnConnect?: boolean; + /** @internal */ + __internalLoggerConfig?: any; + /** @internal */ + __enableMongoLogger?: boolean; } /** @public */ diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index f59df27569f..a51e3e1e789 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -131,7 +131,7 @@ async function autoConnect(client: MongoClient): Promise { if (client.s.hasBeenClosed) { throw new MongoNotConnectedError('Client must be connected before running operations'); } - client.s.options[Symbol.for('@@mdb.skipPingOnConnect')] = true; + client.s.options[__skipPingOnConnect] = true; try { await client.connect(); if (client.topology == null) { @@ -141,7 +141,7 @@ async function autoConnect(client: MongoClient): Promise { } return client.topology; } finally { - delete client.s.options[Symbol.for('@@mdb.skipPingOnConnect')]; + delete client.s.options[__skipPingOnConnect]; } } return client.topology; diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index 61a3bb84fec..feca6e78095 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -466,7 +466,7 @@ export class Topology extends TypedEventEmitter { readPreferenceServerSelector(readPreference), selectServerOptions ); - const skipPingOnConnect = this.s.options[Symbol.for('@@mdb.skipPingOnConnect')] === true; + const skipPingOnConnect = this.s.options[__skipPingOnConnect] === true; if (!skipPingOnConnect && this.s.credentials) { await server.command(ns('admin.$cmd'), { ping: 1 }, { timeoutContext }); stateTransition(this, STATE_CONNECTED); diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts index d4fde19f682..9a5a89fafcd 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts +++ b/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts @@ -34,7 +34,7 @@ class CapturingMongoClient extends MongoClient { commandStartedEvents: Array = []; clientsCreated = 0; constructor(url: string, options: MongoClientOptions = {}) { - options = { ...options, monitorCommands: true, [Symbol.for('@@mdb.skipPingOnConnect')]: true }; + options = { ...options, monitorCommands: true, [__skipPingOnConnect]: true }; if (process.env.MONGODB_API_VERSION) { options.serverApi = process.env.MONGODB_API_VERSION as MongoClientOptions['serverApi']; } diff --git a/test/integration/client-side-encryption/driver.test.ts b/test/integration/client-side-encryption/driver.test.ts index 720d67c4565..7e25a798c3e 100644 --- a/test/integration/client-side-encryption/driver.test.ts +++ b/test/integration/client-side-encryption/driver.test.ts @@ -394,7 +394,7 @@ describe('Client Side Encryption Functional', function () { } ); - encryptedClient.autoEncrypter[Symbol.for('@@mdb.decorateDecryptionResult')] = true; + encryptedClient.autoEncrypter[__decorateDecryptionResult] = true; await encryptedClient.connect(); }); @@ -418,13 +418,13 @@ describe('Client Side Encryption Functional', function () { expect(decrypted).to.deep.equal(data); expect(decrypted) - .to.have.property(Symbol.for('@@mdb.decryptedKeys')) + .to.have.property(__decryptedKeys) .that.deep.equals(['a', 'b']); // Nested expect(decrypted).to.have.property('c'); expect(decrypted.c) - .to.have.property(Symbol.for('@@mdb.decryptedKeys')) + .to.have.property(__decryptedKeys) .that.deep.equals(['d']); }); } diff --git a/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts b/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts index 22857a6cc38..6be429cadbe 100644 --- a/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts +++ b/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { DEFAULT_MAX_DOCUMENT_LENGTH, type Document } from '../../mongodb'; describe('Command Logging and Monitoring Prose Tests', function () { - const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger'); + const loggerFeatureFlag = __enableMongoLogger; const ELLIPSES_LENGTH = 3; let client; let writable; diff --git a/test/integration/node-specific/feature_flags.test.ts b/test/integration/node-specific/feature_flags.test.ts index 14981fdd7cf..e7439a84b7d 100644 --- a/test/integration/node-specific/feature_flags.test.ts +++ b/test/integration/node-specific/feature_flags.test.ts @@ -24,7 +24,7 @@ describe('Feature Flags', () => { for (const { description, value, expectEvents } of tests) { it(description, async function () { const options = - value === undefined ? {} : { [Symbol.for('@@mdb.skipPingOnConnect')]: value }; + value === undefined ? {} : { [__skipPingOnConnect]: value }; const client = this.configuration.newClient({}, { ...options, monitorCommands: true }); const events = []; client.on('commandStarted', event => events.push(event)); @@ -48,7 +48,7 @@ describe('Feature Flags', () => { // TODO(NODE-5672): Release Standardized Logger describe('@@mdb.enableMongoLogger', () => { let cachedEnv; - const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger'); + const loggerFeatureFlag = __enableMongoLogger; before(() => { cachedEnv = process.env; @@ -138,8 +138,8 @@ describe('Feature Flags', () => { it('falls back to environment options', function () { const client = new MongoClient('mongodb://localhost:27017', { - [Symbol.for('@@mdb.enableMongoLogger')]: true, - [Symbol.for('@@mdb.internalLoggerConfig')]: undefined + [__enableMongoLogger]: true, + [__internalLoggerConfig]: undefined }); expect(client.mongoLogger?.componentSeverities).to.have.property( @@ -152,8 +152,8 @@ describe('Feature Flags', () => { context('when defined', function () { it('overrides environment options', function () { const client = new MongoClient('mongodb://localhost:27017', { - [Symbol.for('@@mdb.enableMongoLogger')]: true, - [Symbol.for('@@mdb.internalLoggerConfig')]: { + [__enableMongoLogger]: true, + [__internalLoggerConfig]: { MONGODB_LOG_COMMAND: SeverityLevel.ALERT } }); diff --git a/test/integration/node-specific/ipv6.test.ts b/test/integration/node-specific/ipv6.test.ts index 2f48b0254b4..9797157909f 100644 --- a/test/integration/node-specific/ipv6.test.ts +++ b/test/integration/node-specific/ipv6.test.ts @@ -31,7 +31,7 @@ describe('IPv6 Addresses', () => { ipv6Hosts = this.configuration.options.hostAddresses.map(({ port }) => `[::1]:${port}`); client = this.configuration.newClient(`mongodb://${ipv6Hosts.join(',')}/test`, { - [Symbol.for('@@mdb.skipPingOnConnect')]: true, + [__skipPingOnConnect]: true, maxPoolSize: 1 }); }); diff --git a/test/integration/node-specific/mongo_client.test.ts b/test/integration/node-specific/mongo_client.test.ts index 634516f8f76..e91bdb7c580 100644 --- a/test/integration/node-specific/mongo_client.test.ts +++ b/test/integration/node-specific/mongo_client.test.ts @@ -456,8 +456,8 @@ describe('class MongoClient', function () { const [findCommandStarted] = await findCommandToBeStarted; expect(findCommandStarted).to.have.property('commandName', 'find'); - expect(client.options).to.not.have.property(Symbol.for('@@mdb.skipPingOnConnect')); - expect(client.s.options).to.not.have.property(Symbol.for('@@mdb.skipPingOnConnect')); + expect(client.options).to.not.have.property(__skipPingOnConnect); + expect(client.s.options).to.not.have.property(__skipPingOnConnect); // Assertion is redundant but it shows that no initial ping is run expect(findCommandStarted.commandName).to.not.equal('ping'); @@ -475,8 +475,8 @@ describe('class MongoClient', function () { const [insertCommandStarted] = await insertOneCommandToBeStarted; expect(insertCommandStarted).to.have.property('commandName', 'insert'); - expect(client.options).to.not.have.property(Symbol.for('@@mdb.skipPingOnConnect')); - expect(client.s.options).to.not.have.property(Symbol.for('@@mdb.skipPingOnConnect')); + expect(client.options).to.not.have.property(__skipPingOnConnect); + expect(client.s.options).to.not.have.property(__skipPingOnConnect); // Assertion is redundant but it shows that no initial ping is run expect(insertCommandStarted.commandName).to.not.equal('ping'); diff --git a/test/tools/spec-runner/index.js b/test/tools/spec-runner/index.js index 9e7cc01059b..07e070d78a6 100644 --- a/test/tools/spec-runner/index.js +++ b/test/tools/spec-runner/index.js @@ -363,7 +363,7 @@ function runTestSuiteTest(configuration, spec, context) { minHeartbeatFrequencyMS: 100, monitorCommands: true, ...spec.clientOptions, - [Symbol.for('@@mdb.skipPingOnConnect')]: true + [__skipPingOnConnect]: true }); if (context.requiresCSFLE) { diff --git a/test/tools/unified-spec-runner/entities.ts b/test/tools/unified-spec-runner/entities.ts index 7f90e275dc8..90ca3f23323 100644 --- a/test/tools/unified-spec-runner/entities.ts +++ b/test/tools/unified-spec-runner/entities.ts @@ -222,9 +222,9 @@ export class UnifiedMongoClient extends MongoClient { super(uri, { monitorCommands: true, - [Symbol.for('@@mdb.skipPingOnConnect')]: true, - [Symbol.for('@@mdb.enableMongoLogger')]: true, - [Symbol.for('@@mdb.internalLoggerConfig')]: componentSeverities, + [__skipPingOnConnect]: true, + [__enableMongoLogger]: true, + [__internalLoggerConfig]: componentSeverities, ...getEnvironmentalOptions(), ...(description.serverApi ? { serverApi: description.serverApi } : {}), mongodbLogPath: logCollector, diff --git a/test/unit/client-side-encryption/auto_encrypter.test.ts b/test/unit/client-side-encryption/auto_encrypter.test.ts index 79bc321b802..2c95eaf407d 100644 --- a/test/unit/client-side-encryption/auto_encrypter.test.ts +++ b/test/unit/client-side-encryption/auto_encrypter.test.ts @@ -177,8 +177,8 @@ describe('AutoEncrypter', function () { }); const decrypted = BSON.deserialize(await mc.decrypt(input)); expect(decrypted).to.eql({ filter: { find: 'test', ssn: '457-55-5462' } }); - expect(decrypted).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); - expect(decrypted.filter).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); + expect(decrypted).to.not.have.property(__decryptedKeys); + expect(decrypted.filter).to.not.have.property(__decryptedKeys); }); it('should decrypt mock data and mark decrypted items if enabled for testing', async function () { @@ -213,14 +213,14 @@ describe('AutoEncrypter', function () { expect(decrypted).to.eql({ a: [null, 1, { c: new bson.Binary(Buffer.from('foo', 'utf8'), 1) }] }); - expect(decrypted).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); + expect(decrypted).to.not.have.property(__decryptedKeys); // The same, but with nested data inside the decrypted input decrypted = BSON.deserialize(await mc.decrypt(nestedInput)); expect(decrypted).to.eql({ nested: { x: { y: 1234 } } }); - expect(decrypted.nested).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); - expect(decrypted.nested.x).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); - expect(decrypted.nested.x.y).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); + expect(decrypted.nested).to.not.have.property(__decryptedKeys); + expect(decrypted.nested.x).to.not.have.property(__decryptedKeys); + expect(decrypted.nested.x.y).to.not.have.property(__decryptedKeys); }); context('when the aws sdk is installed', function () { diff --git a/test/unit/connection_string.test.ts b/test/unit/connection_string.test.ts index 244273ef789..d1112f221f0 100644 --- a/test/unit/connection_string.test.ts +++ b/test/unit/connection_string.test.ts @@ -751,9 +751,9 @@ describe('Connection String', function () { describe('feature flags', () => { it('should be stored in the FEATURE_FLAGS Set', () => { expect(FEATURE_FLAGS.size).to.equal(3); - expect(FEATURE_FLAGS.has(Symbol.for('@@mdb.skipPingOnConnect'))).to.be.true; - expect(FEATURE_FLAGS.has(Symbol.for('@@mdb.enableMongoLogger'))).to.be.true; - expect(FEATURE_FLAGS.has(Symbol.for('@@mdb.internalLoggerConfig'))).to.be.true; + expect(FEATURE_FLAGS.has(__skipPingOnConnect)).to.be.true; + expect(FEATURE_FLAGS.has(__enableMongoLogger)).to.be.true; + expect(FEATURE_FLAGS.has(__internalLoggerConfig)).to.be.true; // Add more flags here }); @@ -874,7 +874,7 @@ describe('Connection String', function () { }); describe('when mongodbLogPath is in options', function () { - const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger'); + const loggerFeatureFlag = __enableMongoLogger; let stderrStub; let stdoutStub; @@ -931,7 +931,7 @@ describe('Connection String', function () { process.env.MONGODB_LOG_CLIENT = undefined; }); - const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger'); + const loggerFeatureFlag = __enableMongoLogger; const test_cases = [ ['non-SRV example uri', 'mongodb://a.example.com:27017,b.example.com:27017/', ''], ['non-SRV default uri', 'mongodb://a.mongodb.net:27017', ''], diff --git a/test/unit/mongo_client.test.ts b/test/unit/mongo_client.test.ts index 194721350ac..e08d49c6648 100644 --- a/test/unit/mongo_client.test.ts +++ b/test/unit/mongo_client.test.ts @@ -829,7 +829,7 @@ describe('MongoClient', function () { }); describe('logging client options', function () { - const loggerFeatureFlag = Symbol.for('@@mdb.enableMongoLogger'); + const loggerFeatureFlag = __enableMongoLogger; describe('mongodbLogPath', function () { context('when mongodbLogPath is in options', function () { diff --git a/test/unit/tools/mongodb-legacy.test.ts b/test/unit/tools/mongodb-legacy.test.ts index a397e521b57..7c29343d3f7 100644 --- a/test/unit/tools/mongodb-legacy.test.ts +++ b/test/unit/tools/mongodb-legacy.test.ts @@ -38,7 +38,7 @@ describe('mongodb-legacy', () => { it(`test suite imports a ${className} with the legacy symbol`, () => { // Just confirming that the mongodb-legacy import is correctly overriding the local copies // of these classes from "src". See test/mongodb.ts for more. - expect(ctor.prototype).to.have.property(Symbol.for('@@mdb.callbacks.toLegacy')); + expect(ctor.prototype).to.have.property(__callbacks.toLegacy); }); } From bbf4d823e9278d9a6bc827efa923d4b44252f274 Mon Sep 17 00:00:00 2001 From: Warren James Date: Wed, 11 Dec 2024 11:58:17 -0500 Subject: [PATCH 2/9] WIP --- src/connection_string.ts | 8 ++++- src/mongo_client.ts | 9 ++++-- src/operations/execute_operation.ts | 4 +-- src/sdam/topology.ts | 4 +-- test/unit/connection_string.test.ts | 49 +++-------------------------- 5 files changed, 21 insertions(+), 53 deletions(-) diff --git a/src/connection_string.ts b/src/connection_string.ts index b2e3765e318..ed5890e8ecf 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -1311,7 +1311,13 @@ export const OPTIONS = { * TODO: NODE-5671 - remove internal flag */ mongodbLogMaxDocumentLength: { type: 'uint' } -} as Record; +} as Record< + keyof Omit< + MongoClientOptions, + '__enableMongoLogger' | '__internalLoggerConfig' | '__skipPingOnConnect' + >, + OptionDescriptor +>; export const DEFAULT_OPTIONS = new CaseInsensitiveMap( Object.entries(OPTIONS) diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 395b269eaeb..7215da61b81 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -1010,9 +1010,6 @@ export interface MongoOptions tlsCRLFile?: string; tlsCertificateKeyFile?: string; - /** @internal */ - [featureFlag: symbol]: any; - /** * @internal * TODO: NODE-5671 - remove internal flag @@ -1024,4 +1021,10 @@ export interface MongoOptions */ mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable; timeoutMS?: number; + /** @internal */ + __skipPingOnConnect?: boolean; + /** @internal */ + __internalLoggerConfig?: Document; + /** @internal */ + __enableMongoLogger?: boolean; } diff --git a/src/operations/execute_operation.ts b/src/operations/execute_operation.ts index a51e3e1e789..81601a6e160 100644 --- a/src/operations/execute_operation.ts +++ b/src/operations/execute_operation.ts @@ -131,7 +131,7 @@ async function autoConnect(client: MongoClient): Promise { if (client.s.hasBeenClosed) { throw new MongoNotConnectedError('Client must be connected before running operations'); } - client.s.options[__skipPingOnConnect] = true; + client.s.options.__skipPingOnConnect = true; try { await client.connect(); if (client.topology == null) { @@ -141,7 +141,7 @@ async function autoConnect(client: MongoClient): Promise { } return client.topology; } finally { - delete client.s.options[__skipPingOnConnect]; + delete client.s.options.__skipPingOnConnect; } } return client.topology; diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index feca6e78095..075236b024c 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -153,7 +153,7 @@ export interface TopologyOptions extends BSONSerializeOptions, ServerOptions { serverMonitoringMode: ServerMonitoringMode; /** MongoDB server API version */ serverApi?: ServerApi; - [featureFlag: symbol]: any; + __skipPingOnConnect?: boolean; } /** @public */ @@ -466,7 +466,7 @@ export class Topology extends TypedEventEmitter { readPreferenceServerSelector(readPreference), selectServerOptions ); - const skipPingOnConnect = this.s.options[__skipPingOnConnect] === true; + const skipPingOnConnect = this.s.options.__skipPingOnConnect === true; if (!skipPingOnConnect && this.s.credentials) { await server.command(ns('admin.$cmd'), { ping: 1 }, { timeoutContext }); stateTransition(this, STATE_CONNECTED); diff --git a/test/unit/connection_string.test.ts b/test/unit/connection_string.test.ts index d1112f221f0..f4a9591e038 100644 --- a/test/unit/connection_string.test.ts +++ b/test/unit/connection_string.test.ts @@ -12,7 +12,6 @@ import { COSMOS_DB_MSG, DEFAULT_ALLOWED_HOSTS, DOCUMENT_DB_MSG, - FEATURE_FLAGS, type Log, MongoAPIError, MongoClient, @@ -748,43 +747,6 @@ describe('Connection String', function () { }); }); - describe('feature flags', () => { - it('should be stored in the FEATURE_FLAGS Set', () => { - expect(FEATURE_FLAGS.size).to.equal(3); - expect(FEATURE_FLAGS.has(__skipPingOnConnect)).to.be.true; - expect(FEATURE_FLAGS.has(__enableMongoLogger)).to.be.true; - expect(FEATURE_FLAGS.has(__internalLoggerConfig)).to.be.true; - // Add more flags here - }); - - it('should should ignore unknown symbols', () => { - const randomFlag = Symbol(); - const client = new MongoClient('mongodb://iLoveJavaScript', { [randomFlag]: 23n }); - expect(client.s.options).to.not.have.property(randomFlag); - }); - - it('should be prefixed with @@mdb.', () => { - for (const flag of FEATURE_FLAGS) { - expect(flag).to.be.a('symbol'); - expect(flag).to.have.property('description'); - expect(flag.description).to.match(/@@mdb\..+/); - } - }); - - it('should only exist if specified on options', () => { - const flag = Array.from(FEATURE_FLAGS)[0]; // grab a random supported flag - const client = new MongoClient('mongodb://iLoveJavaScript', { [flag]: true }); - expect(client.s.options).to.have.property(flag, true); - expect(client.options).to.have.property(flag, true); - }); - - it('should support nullish values', () => { - const flag = Array.from(FEATURE_FLAGS.keys())[0]; // grab a random supported flag - const client = new MongoClient('mongodb://iLoveJavaScript', { [flag]: null }); - expect(client.s.options).to.have.property(flag, null); - }); - }); - describe('IPv6 host addresses', () => { it('should not allow multiple unbracketed portless localhost IPv6 addresses', () => { // Note there is no "port-full" version of this test, there's no way to distinguish when a port begins without brackets @@ -874,8 +836,6 @@ describe('Connection String', function () { }); describe('when mongodbLogPath is in options', function () { - const loggerFeatureFlag = __enableMongoLogger; - let stderrStub; let stdoutStub; @@ -891,7 +851,7 @@ describe('Connection String', function () { context('when option is `stderr`', function () { it('it is accessible through mongoLogger.logDestination', function () { const client = new MongoClient('mongodb://a/?mongodbLogPath=stderr', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); const log: Log = { t: new Date(), c: 'ConnectionStringStdErr', s: 'error' }; client.options.mongoLoggerOptions.logDestination.write(log); @@ -903,7 +863,7 @@ describe('Connection String', function () { context('when option is `stdout`', function () { it('it is accessible through mongoLogger.logDestination', function () { const client = new MongoClient('mongodb://a/?mongodbLogPath=stdout', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); const log: Log = { t: new Date(), c: 'ConnectionStringStdOut', s: 'error' }; client.options.mongoLoggerOptions.logDestination.write(log); @@ -916,7 +876,7 @@ describe('Connection String', function () { it('should throw error at construction', function () { expect( () => - new MongoClient('mongodb://a/?mongodbLogPath=stdnothing', { [loggerFeatureFlag]: true }) + new MongoClient('mongodb://a/?mongodbLogPath=stdnothing', { __enableMongoLogger: true }) ).to.throw(MongoAPIError); }); }); @@ -931,7 +891,6 @@ describe('Connection String', function () { process.env.MONGODB_LOG_CLIENT = undefined; }); - const loggerFeatureFlag = __enableMongoLogger; const test_cases = [ ['non-SRV example uri', 'mongodb://a.example.com:27017,b.example.com:27017/', ''], ['non-SRV default uri', 'mongodb://a.mongodb.net:27017', ''], @@ -960,7 +919,7 @@ describe('Connection String', function () { } }; new MongoClient(uri, { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: stream }); From 22f8edbbaf8d89a184bb1296e5e5eac941320eb9 Mon Sep 17 00:00:00 2001 From: Warren James Date: Fri, 13 Dec 2024 15:15:52 -0500 Subject: [PATCH 3/9] wip: replacing feature falgs --- src/cmap/connection.ts | 2 +- src/cmap/wire_protocol/responses.ts | 4 +-- ..._side_encryption.prose.12.deadlock.test.ts | 2 +- .../client-side-encryption/driver.test.ts | 6 ++--- ...mmand_logging_and_monitoring.prose.test.ts | 7 +++-- .../node-specific/feature_flags.test.ts | 26 +++++++++---------- test/integration/node-specific/ipv6.test.ts | 2 +- .../node-specific/mongo_client.test.ts | 8 +++--- test/tools/spec-runner/index.js | 2 +- test/tools/unified-spec-runner/entities.ts | 6 ++--- .../auto_encrypter.test.ts | 12 ++++----- 11 files changed, 37 insertions(+), 40 deletions(-) diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index bf36bfe8d83..6df81b34d94 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -889,7 +889,7 @@ export class CryptoConnection extends Connection { const decryptedResponse = responseType?.make(result) ?? deserialize(result, options); - if (autoEncrypter.__decorateDecryptionResult) { + if (autoEncrypter[kDecorateResult]) { if (responseType == null) { decorateDecryptionResult(decryptedResponse, encryptedResponse.toObject(), true); } else if (decryptedResponse instanceof CursorResponse) { diff --git a/src/cmap/wire_protocol/responses.ts b/src/cmap/wire_protocol/responses.ts index 7f358a8a47c..1d20566e2d5 100644 --- a/src/cmap/wire_protocol/responses.ts +++ b/src/cmap/wire_protocol/responses.ts @@ -221,9 +221,9 @@ export class MongoDBResponse extends OnDemandDocument { export class CursorResponse extends MongoDBResponse { /** * Devtools need to know which keys were encrypted before the driver automatically decrypted them. - * If decorating is enabled (`__decorateDecryptionResult`), this field will be set, + * If decorating is enabled (`Symbol.for('@@mdb.decorateDecryptionResult')`), this field will be set, * storing the original encrypted response from the server, so that we can build an object that has - * the list of BSON keys that were encrypted stored at a well known symbol: `__decryptedKeys`. + * the list of BSON keys that were encrypted stored at a well known symbol: `Symbol.for('@@mdb.decryptedKeys')`. */ encryptedResponse?: MongoDBResponse; /** diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts index 9a5a89fafcd..d4fde19f682 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts +++ b/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts @@ -34,7 +34,7 @@ class CapturingMongoClient extends MongoClient { commandStartedEvents: Array = []; clientsCreated = 0; constructor(url: string, options: MongoClientOptions = {}) { - options = { ...options, monitorCommands: true, [__skipPingOnConnect]: true }; + options = { ...options, monitorCommands: true, [Symbol.for('@@mdb.skipPingOnConnect')]: true }; if (process.env.MONGODB_API_VERSION) { options.serverApi = process.env.MONGODB_API_VERSION as MongoClientOptions['serverApi']; } diff --git a/test/integration/client-side-encryption/driver.test.ts b/test/integration/client-side-encryption/driver.test.ts index 7e25a798c3e..720d67c4565 100644 --- a/test/integration/client-side-encryption/driver.test.ts +++ b/test/integration/client-side-encryption/driver.test.ts @@ -394,7 +394,7 @@ describe('Client Side Encryption Functional', function () { } ); - encryptedClient.autoEncrypter[__decorateDecryptionResult] = true; + encryptedClient.autoEncrypter[Symbol.for('@@mdb.decorateDecryptionResult')] = true; await encryptedClient.connect(); }); @@ -418,13 +418,13 @@ describe('Client Side Encryption Functional', function () { expect(decrypted).to.deep.equal(data); expect(decrypted) - .to.have.property(__decryptedKeys) + .to.have.property(Symbol.for('@@mdb.decryptedKeys')) .that.deep.equals(['a', 'b']); // Nested expect(decrypted).to.have.property('c'); expect(decrypted.c) - .to.have.property(__decryptedKeys) + .to.have.property(Symbol.for('@@mdb.decryptedKeys')) .that.deep.equals(['d']); }); } diff --git a/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts b/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts index 6be429cadbe..ea909408318 100644 --- a/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts +++ b/test/integration/command-logging-and-monitoring/command_logging_and_monitoring.prose.test.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { DEFAULT_MAX_DOCUMENT_LENGTH, type Document } from '../../mongodb'; describe('Command Logging and Monitoring Prose Tests', function () { - const loggerFeatureFlag = __enableMongoLogger; const ELLIPSES_LENGTH = 3; let client; let writable; @@ -40,7 +39,7 @@ describe('Command Logging and Monitoring Prose Tests', function () { client = this.configuration.newClient( {}, { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: writable, mongodbLogComponentSeverities: { command: 'debug' @@ -124,7 +123,7 @@ describe('Command Logging and Monitoring Prose Tests', function () { client = this.configuration.newClient( {}, { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: writable, mongodbLogComponentSeverities: { command: 'debug' @@ -181,7 +180,7 @@ describe('Command Logging and Monitoring Prose Tests', function () { client = this.configuration.newClient( {}, { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: writable, mongodbLogComponentSeverities: { command: 'debug' diff --git a/test/integration/node-specific/feature_flags.test.ts b/test/integration/node-specific/feature_flags.test.ts index e7439a84b7d..785c84bd212 100644 --- a/test/integration/node-specific/feature_flags.test.ts +++ b/test/integration/node-specific/feature_flags.test.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { MongoClient, SeverityLevel } from '../../mongodb'; describe('Feature Flags', () => { - describe('@@mdb.skipPingOnConnect', () => { + describe('__skipPingOnConnect', () => { beforeEach(function () { if (process.env.AUTH !== 'auth') { this.currentTest.skipReason = 'ping count relies on auth to be enabled'; @@ -23,8 +23,7 @@ describe('Feature Flags', () => { ]; for (const { description, value, expectEvents } of tests) { it(description, async function () { - const options = - value === undefined ? {} : { [__skipPingOnConnect]: value }; + const options = value === undefined ? {} : { __skipPingOnConnect: value }; const client = this.configuration.newClient({}, { ...options, monitorCommands: true }); const events = []; client.on('commandStarted', event => events.push(event)); @@ -46,9 +45,8 @@ describe('Feature Flags', () => { }); // TODO(NODE-5672): Release Standardized Logger - describe('@@mdb.enableMongoLogger', () => { + describe('__enableMongoLogger', () => { let cachedEnv; - const loggerFeatureFlag = __enableMongoLogger; before(() => { cachedEnv = process.env; @@ -66,7 +64,7 @@ describe('Feature Flags', () => { it('enables logging for the specified component', () => { const client = new MongoClient('mongodb://localhost:27017', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); expect(client.mongoLogger?.componentSeverities).to.have.property( 'command', @@ -82,7 +80,7 @@ describe('Feature Flags', () => { it('does not create logger', () => { const client = new MongoClient('mongodb://localhost:27017', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); expect(client.mongoLogger).to.not.exist; }); @@ -98,7 +96,7 @@ describe('Feature Flags', () => { it('does not instantiate logger', () => { const client = new MongoClient('mongodb://localhost:27017', { - [loggerFeatureFlag]: featureFlagValue + __enableMongoLogger: featureFlagValue }); expect(client.mongoLogger).to.not.exist; }); @@ -111,7 +109,7 @@ describe('Feature Flags', () => { it('does not instantiate logger', () => { const client = new MongoClient('mongodb://localhost:27017', { - [loggerFeatureFlag]: featureFlagValue + __enableMongoLogger: featureFlagValue }); expect(client.mongoLogger).to.not.exist; }); @@ -120,7 +118,7 @@ describe('Feature Flags', () => { } }); - describe('@@mdb.internalLoggerConfig', () => { + describe('__internalLoggerConfig', () => { let cachedEnv: NodeJS.ProcessEnv; before(() => { @@ -138,8 +136,8 @@ describe('Feature Flags', () => { it('falls back to environment options', function () { const client = new MongoClient('mongodb://localhost:27017', { - [__enableMongoLogger]: true, - [__internalLoggerConfig]: undefined + __enableMongoLogger: true, + __internalLoggerConfig: undefined }); expect(client.mongoLogger?.componentSeverities).to.have.property( @@ -152,8 +150,8 @@ describe('Feature Flags', () => { context('when defined', function () { it('overrides environment options', function () { const client = new MongoClient('mongodb://localhost:27017', { - [__enableMongoLogger]: true, - [__internalLoggerConfig]: { + __enableMongoLogger: true, + __internalLoggerConfig: { MONGODB_LOG_COMMAND: SeverityLevel.ALERT } }); diff --git a/test/integration/node-specific/ipv6.test.ts b/test/integration/node-specific/ipv6.test.ts index 9797157909f..b030fdb210c 100644 --- a/test/integration/node-specific/ipv6.test.ts +++ b/test/integration/node-specific/ipv6.test.ts @@ -31,7 +31,7 @@ describe('IPv6 Addresses', () => { ipv6Hosts = this.configuration.options.hostAddresses.map(({ port }) => `[::1]:${port}`); client = this.configuration.newClient(`mongodb://${ipv6Hosts.join(',')}/test`, { - [__skipPingOnConnect]: true, + __skipPingOnConnect: true, maxPoolSize: 1 }); }); diff --git a/test/integration/node-specific/mongo_client.test.ts b/test/integration/node-specific/mongo_client.test.ts index e91bdb7c580..823aafb7baf 100644 --- a/test/integration/node-specific/mongo_client.test.ts +++ b/test/integration/node-specific/mongo_client.test.ts @@ -456,8 +456,8 @@ describe('class MongoClient', function () { const [findCommandStarted] = await findCommandToBeStarted; expect(findCommandStarted).to.have.property('commandName', 'find'); - expect(client.options).to.not.have.property(__skipPingOnConnect); - expect(client.s.options).to.not.have.property(__skipPingOnConnect); + expect(client.options).to.not.have.property('__skipPingOnConnect'); + expect(client.s.options).to.not.have.property('__skipPingOnConnect'); // Assertion is redundant but it shows that no initial ping is run expect(findCommandStarted.commandName).to.not.equal('ping'); @@ -475,8 +475,8 @@ describe('class MongoClient', function () { const [insertCommandStarted] = await insertOneCommandToBeStarted; expect(insertCommandStarted).to.have.property('commandName', 'insert'); - expect(client.options).to.not.have.property(__skipPingOnConnect); - expect(client.s.options).to.not.have.property(__skipPingOnConnect); + expect(client.options).to.not.have.property('__skipPingOnConnect'); + expect(client.s.options).to.not.have.property('__skipPingOnConnect'); // Assertion is redundant but it shows that no initial ping is run expect(insertCommandStarted.commandName).to.not.equal('ping'); diff --git a/test/tools/spec-runner/index.js b/test/tools/spec-runner/index.js index 07e070d78a6..42ea3b126b1 100644 --- a/test/tools/spec-runner/index.js +++ b/test/tools/spec-runner/index.js @@ -363,7 +363,7 @@ function runTestSuiteTest(configuration, spec, context) { minHeartbeatFrequencyMS: 100, monitorCommands: true, ...spec.clientOptions, - [__skipPingOnConnect]: true + __skipPingOnConnect: true }); if (context.requiresCSFLE) { diff --git a/test/tools/unified-spec-runner/entities.ts b/test/tools/unified-spec-runner/entities.ts index 90ca3f23323..04a6c6bc69c 100644 --- a/test/tools/unified-spec-runner/entities.ts +++ b/test/tools/unified-spec-runner/entities.ts @@ -222,9 +222,9 @@ export class UnifiedMongoClient extends MongoClient { super(uri, { monitorCommands: true, - [__skipPingOnConnect]: true, - [__enableMongoLogger]: true, - [__internalLoggerConfig]: componentSeverities, + __skipPingOnConnect: true, + __enableMongoLogger: true, + __internalLoggerConfig: componentSeverities, ...getEnvironmentalOptions(), ...(description.serverApi ? { serverApi: description.serverApi } : {}), mongodbLogPath: logCollector, diff --git a/test/unit/client-side-encryption/auto_encrypter.test.ts b/test/unit/client-side-encryption/auto_encrypter.test.ts index 2c95eaf407d..79bc321b802 100644 --- a/test/unit/client-side-encryption/auto_encrypter.test.ts +++ b/test/unit/client-side-encryption/auto_encrypter.test.ts @@ -177,8 +177,8 @@ describe('AutoEncrypter', function () { }); const decrypted = BSON.deserialize(await mc.decrypt(input)); expect(decrypted).to.eql({ filter: { find: 'test', ssn: '457-55-5462' } }); - expect(decrypted).to.not.have.property(__decryptedKeys); - expect(decrypted.filter).to.not.have.property(__decryptedKeys); + expect(decrypted).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); + expect(decrypted.filter).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); }); it('should decrypt mock data and mark decrypted items if enabled for testing', async function () { @@ -213,14 +213,14 @@ describe('AutoEncrypter', function () { expect(decrypted).to.eql({ a: [null, 1, { c: new bson.Binary(Buffer.from('foo', 'utf8'), 1) }] }); - expect(decrypted).to.not.have.property(__decryptedKeys); + expect(decrypted).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); // The same, but with nested data inside the decrypted input decrypted = BSON.deserialize(await mc.decrypt(nestedInput)); expect(decrypted).to.eql({ nested: { x: { y: 1234 } } }); - expect(decrypted.nested).to.not.have.property(__decryptedKeys); - expect(decrypted.nested.x).to.not.have.property(__decryptedKeys); - expect(decrypted.nested.x.y).to.not.have.property(__decryptedKeys); + expect(decrypted.nested).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); + expect(decrypted.nested.x).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); + expect(decrypted.nested.x.y).to.not.have.property(Symbol.for('@@mdb.decryptedKeys')); }); context('when the aws sdk is installed', function () { From 16b29624ccfe8d5d460e812ce6785faec446dcdb Mon Sep 17 00:00:00 2001 From: Warren James Date: Fri, 13 Dec 2024 15:33:29 -0500 Subject: [PATCH 4/9] restore autoencrypter feature flags --- src/constants.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index 430afa1a9b7..623b6c919b1 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -172,6 +172,6 @@ export const LEGACY_HELLO_COMMAND_CAMEL_CASE = 'isMaster'; // the objects (and class) that we expect to see them on and prevent TS // errors. /** @internal */ -export const kDecorateResult = '__decorateDecryptionResult'; +export const kDecorateResult = Symbol.for('@@mdb.decorateDecryptionResult'); /** @internal */ -export const kDecoratedKeys = '__decryptedKeys'; +export const kDecoratedKeys = Symbol.for('@@mdb.decryptedKeys'); From 1603f02479b1913074d0f80c1eb45c329864bb8d Mon Sep 17 00:00:00 2001 From: Warren James Date: Fri, 13 Dec 2024 16:50:03 -0500 Subject: [PATCH 5/9] add flags to options parsing --- src/connection_string.ts | 5 +++- test/unit/mongo_client.test.ts | 44 ++++++++++++++++------------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/connection_string.ts b/src/connection_string.ts index ed5890e8ecf..de8489318dd 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -1310,7 +1310,10 @@ export const OPTIONS = { * @internal * TODO: NODE-5671 - remove internal flag */ - mongodbLogMaxDocumentLength: { type: 'uint' } + mongodbLogMaxDocumentLength: { type: 'uint' }, + __enableMongoLogger: { type: 'boolean' }, + __skipPingOnConnect: { type: 'boolean' }, + __internalLoggerConfig: { type: 'any' } } as Record< keyof Omit< MongoClientOptions, diff --git a/test/unit/mongo_client.test.ts b/test/unit/mongo_client.test.ts index e08d49c6648..2dcc9210278 100644 --- a/test/unit/mongo_client.test.ts +++ b/test/unit/mongo_client.test.ts @@ -829,8 +829,6 @@ describe('MongoClient', function () { }); describe('logging client options', function () { - const loggerFeatureFlag = __enableMongoLogger; - describe('mongodbLogPath', function () { context('when mongodbLogPath is in options', function () { let stderrStub; @@ -848,7 +846,7 @@ describe('MongoClient', function () { context('when option is `stderr`', function () { it('it is accessible through mongoLogger.logDestination', function () { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: 'stderr' }); const log = { t: new Date(), c: 'constructorStdErr', s: 'error' }; @@ -867,7 +865,7 @@ describe('MongoClient', function () { } }; const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: writable }); expect(client.options.mongoLoggerOptions.logDestination).to.deep.equal(writable); @@ -877,7 +875,7 @@ describe('MongoClient', function () { context('when option is `stdout`', function () { it('it is accessible through mongoLogger.logDestination', function () { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: 'stdout' }); const log = { t: new Date(), c: 'constructorStdOut', s: 'error' }; @@ -894,7 +892,7 @@ describe('MongoClient', function () { expect( () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: invalidOption }) ).to.throw(MongoAPIError); @@ -912,7 +910,7 @@ describe('MongoClient', function () { expect( () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogPath: writable }) ).to.throw(MongoAPIError); @@ -934,7 +932,7 @@ describe('MongoClient', function () { it('should default to stderr', function () { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); const log = { t: new Date(), c: 'constructorStdErr', s: 'error' }; client.options.mongoLoggerOptions.logDestination.write(log); @@ -958,7 +956,7 @@ describe('MongoClient', function () { it(`it stores severity levels for ${components[i]} component correctly`, function () { for (const severityLevel of Object.values(SeverityLevel)) { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { [components[i]]: severityLevel } @@ -982,7 +980,7 @@ describe('MongoClient', function () { process.env[env_component_names[i]] = 'emergency'; for (const severityLevel of Object.values(SeverityLevel)) { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { [components[i]]: severityLevel } @@ -1007,7 +1005,7 @@ describe('MongoClient', function () { for (const severityLevel of Object.values(SeverityLevel)) { for (const defaultSeverityLevel of Object.values(SeverityLevel)) { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { [components[i]]: severityLevel, default: defaultSeverityLevel @@ -1032,7 +1030,7 @@ describe('MongoClient', function () { context('when invalid client option is provided', function () { const badClientCreator = () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { default: 'imFake' } @@ -1077,12 +1075,12 @@ describe('MongoClient', function () { expect( () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: {} }) ).to.not.throw(MongoAPIError); const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { client: 'error' } // dummy so logger doesn't turn on }); expect(client.mongoLogger?.componentSeverities.command).to.equal('off'); @@ -1093,12 +1091,12 @@ describe('MongoClient', function () { expect( () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { default: 'emergency' } }) ).to.not.throw(MongoAPIError); const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogComponentSeverities: { command: 'emergency' } }); expect(client.mongoLogger?.componentSeverities.command).to.equal('emergency'); @@ -1113,7 +1111,7 @@ describe('MongoClient', function () { context('when env option for MONGODB_LOG_MAX_DOCUMENT_LENGTH is not provided', function () { it('should store value for maxDocumentLength correctly', function () { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogMaxDocumentLength: 290 }); expect(client.options.mongoLoggerOptions.maxDocumentLength).to.equal(290); @@ -1122,7 +1120,7 @@ describe('MongoClient', function () { expect( () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogMaxDocumentLength: -290 }) ).to.throw(MongoParseError); @@ -1139,7 +1137,7 @@ describe('MongoClient', function () { it('should store value for maxDocumentLength correctly (client option value takes precedence)', function () { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogMaxDocumentLength: 290 }); expect(client.options.mongoLoggerOptions.maxDocumentLength).to.equal(290); @@ -1148,7 +1146,7 @@ describe('MongoClient', function () { expect( () => new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true, + __enableMongoLogger: true, mongodbLogMaxDocumentLength: -290 }) ).to.throw(MongoParseError); @@ -1159,7 +1157,7 @@ describe('MongoClient', function () { context('when env option for MONGODB_LOG_MAX_DOCUMENT_LENGTH is not provided', function () { it('should store value for default maxDocumentLength correctly', function () { const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); expect(client.options.mongoLoggerOptions.maxDocumentLength).to.equal(1000); }); @@ -1172,7 +1170,7 @@ describe('MongoClient', function () { it('should store value for maxDocumentLength correctly', function () { process.env.MONGODB_LOG_MAX_DOCUMENT_LENGTH = '155'; const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); expect(client.options.mongoLoggerOptions.maxDocumentLength).to.equal(155); }); @@ -1180,7 +1178,7 @@ describe('MongoClient', function () { it('should not throw error for negative MONGODB_MAX_DOCUMENT_LENGTH and set to default', function () { process.env.MONGODB_LOG_MAX_DOCUMENT_LENGTH = '-14'; const client = new MongoClient('mongodb://a/', { - [loggerFeatureFlag]: true + __enableMongoLogger: true }); expect(client.options.mongoLoggerOptions.maxDocumentLength).to.equal(1000); }); From a4b6c5d5c3b5a1f6f9c0660544f050d93cdb476a Mon Sep 17 00:00:00 2001 From: Warren James Date: Fri, 13 Dec 2024 16:57:00 -0500 Subject: [PATCH 6/9] restore callbacks symbol for legacy --- test/unit/tools/mongodb-legacy.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/tools/mongodb-legacy.test.ts b/test/unit/tools/mongodb-legacy.test.ts index 7c29343d3f7..a397e521b57 100644 --- a/test/unit/tools/mongodb-legacy.test.ts +++ b/test/unit/tools/mongodb-legacy.test.ts @@ -38,7 +38,7 @@ describe('mongodb-legacy', () => { it(`test suite imports a ${className} with the legacy symbol`, () => { // Just confirming that the mongodb-legacy import is correctly overriding the local copies // of these classes from "src". See test/mongodb.ts for more. - expect(ctor.prototype).to.have.property(__callbacks.toLegacy); + expect(ctor.prototype).to.have.property(Symbol.for('@@mdb.callbacks.toLegacy')); }); } From 303b2d13927029b8f97fa9ed44b8ed7193199627 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Mon, 16 Dec 2024 13:49:00 -0500 Subject: [PATCH 7/9] chore: fixups --- src/client-side-encryption/auto_encrypter.ts | 1 - src/connection_string.ts | 27 ++++--------------- src/mongo_client.ts | 3 ++- src/sdam/topology.ts | 5 ++-- ..._side_encryption.prose.12.deadlock.test.ts | 2 +- 5 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/client-side-encryption/auto_encrypter.ts b/src/client-side-encryption/auto_encrypter.ts index 08b72af3993..edf731b92ac 100644 --- a/src/client-side-encryption/auto_encrypter.ts +++ b/src/client-side-encryption/auto_encrypter.ts @@ -160,7 +160,6 @@ export class AutoEncrypter { _mongocrypt: MongoCrypt; /** - * @internal * Used by devtools to enable decorating decryption results. * * When set and enabled, `decrypt` will automatically recursively diff --git a/src/connection_string.ts b/src/connection_string.ts index de8489318dd..d50a1fcfa94 100644 --- a/src/connection_string.ts +++ b/src/connection_string.ts @@ -508,12 +508,11 @@ export function parseOptions( ); } - const loggerFeatureFlag = '__enableMongoLogger'; - mongoOptions[loggerFeatureFlag] = mongoOptions[loggerFeatureFlag] ?? false; + mongoOptions.__enableMongoLogger = mongoOptions.__enableMongoLogger ?? false; let loggerEnvOptions: MongoLoggerEnvOptions = {}; let loggerClientOptions: MongoLoggerMongoClientOptions = {}; - if (mongoOptions[loggerFeatureFlag]) { + if (mongoOptions.__enableMongoLogger) { loggerEnvOptions = { MONGODB_LOG_COMMAND: process.env.MONGODB_LOG_COMMAND, MONGODB_LOG_TOPOLOGY: process.env.MONGODB_LOG_TOPOLOGY, @@ -523,7 +522,7 @@ export function parseOptions( MONGODB_LOG_ALL: process.env.MONGODB_LOG_ALL, MONGODB_LOG_MAX_DOCUMENT_LENGTH: process.env.MONGODB_LOG_MAX_DOCUMENT_LENGTH, MONGODB_LOG_PATH: process.env.MONGODB_LOG_PATH, - ...mongoOptions['__internalLoggerConfig'] + ...mongoOptions.__internalLoggerConfig }; loggerClientOptions = { mongodbLogPath: mongoOptions.mongodbLogPath, @@ -1313,27 +1312,11 @@ export const OPTIONS = { mongodbLogMaxDocumentLength: { type: 'uint' }, __enableMongoLogger: { type: 'boolean' }, __skipPingOnConnect: { type: 'boolean' }, - __internalLoggerConfig: { type: 'any' } -} as Record< - keyof Omit< - MongoClientOptions, - '__enableMongoLogger' | '__internalLoggerConfig' | '__skipPingOnConnect' - >, - OptionDescriptor ->; + __internalLoggerConfig: { type: 'record' } +} as Record; export const DEFAULT_OPTIONS = new CaseInsensitiveMap( Object.entries(OPTIONS) .filter(([, descriptor]) => descriptor.default != null) .map(([k, d]) => [k, d.default]) ); - -/** - * Set of permitted feature flags - * @internal - */ -export const FEATURE_FLAGS = new Set([ - '__skipPingOnConnect', - '__enableMongoLogger', - '__internalLoggerConfig' -]); diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 7215da61b81..61cc94d94cd 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -26,6 +26,7 @@ import { type LogComponentSeveritiesClientOptions, type MongoDBLogWritable, MongoLogger, + type MongoLoggerEnvOptions, type MongoLoggerOptions, SeverityLevel } from './mongo_logger'; @@ -301,7 +302,7 @@ export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeC /** @internal */ __skipPingOnConnect?: boolean; /** @internal */ - __internalLoggerConfig?: any; + __internalLoggerConfig?: MongoLoggerEnvOptions; /** @internal */ __enableMongoLogger?: boolean; } diff --git a/src/sdam/topology.ts b/src/sdam/topology.ts index 075236b024c..b6cad4097e8 100644 --- a/src/sdam/topology.ts +++ b/src/sdam/topology.ts @@ -3,7 +3,7 @@ import type { MongoCredentials } from '../cmap/auth/mongo_credentials'; import type { ConnectionEvents } from '../cmap/connection'; import type { ConnectionPoolEvents } from '../cmap/connection_pool'; import type { ClientMetadata } from '../cmap/handshake/client_metadata'; -import { DEFAULT_OPTIONS, FEATURE_FLAGS } from '../connection_string'; +import { DEFAULT_OPTIONS } from '../connection_string'; import { CLOSE, CONNECT, @@ -251,8 +251,7 @@ export class Topology extends TypedEventEmitter { // Options should only be undefined in tests, MongoClient will always have defined options options = options ?? { hosts: [HostAddress.fromString('localhost:27017')], - ...Object.fromEntries(DEFAULT_OPTIONS.entries()), - ...Object.fromEntries(FEATURE_FLAGS.entries()) + ...Object.fromEntries(DEFAULT_OPTIONS.entries()) }; if (typeof seeds === 'string') { diff --git a/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts b/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts index d4fde19f682..ee833fcbd52 100644 --- a/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts +++ b/test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts @@ -34,7 +34,7 @@ class CapturingMongoClient extends MongoClient { commandStartedEvents: Array = []; clientsCreated = 0; constructor(url: string, options: MongoClientOptions = {}) { - options = { ...options, monitorCommands: true, [Symbol.for('@@mdb.skipPingOnConnect')]: true }; + options = { ...options, monitorCommands: true, __skipPingOnConnect: true }; if (process.env.MONGODB_API_VERSION) { options.serverApi = process.env.MONGODB_API_VERSION as MongoClientOptions['serverApi']; } From ea94a328ebb40662198c46762c338c29148a596c Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 19 Dec 2024 13:12:31 -0500 Subject: [PATCH 8/9] chore: move tests --- .../node-specific/feature_flags.test.ts | 166 ----------------- .../node-specific/mongo_client.test.ts | 168 ++++++++++++++++++ 2 files changed, 168 insertions(+), 166 deletions(-) delete mode 100644 test/integration/node-specific/feature_flags.test.ts diff --git a/test/integration/node-specific/feature_flags.test.ts b/test/integration/node-specific/feature_flags.test.ts deleted file mode 100644 index 785c84bd212..00000000000 --- a/test/integration/node-specific/feature_flags.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { expect } from 'chai'; - -import { MongoClient, SeverityLevel } from '../../mongodb'; - -describe('Feature Flags', () => { - describe('__skipPingOnConnect', () => { - beforeEach(function () { - if (process.env.AUTH !== 'auth') { - this.currentTest.skipReason = 'ping count relies on auth to be enabled'; - this.skip(); - } - }); - - const tests = [ - // only skipInitiaPing=true will have no events upon connect - { description: 'should skip ping command when set to true', value: true, expectEvents: 0 }, - { - description: 'should not skip ping command when set to false', - value: false, - expectEvents: 1 - }, - { description: 'should not skip ping command when unset', value: undefined, expectEvents: 1 } - ]; - for (const { description, value, expectEvents } of tests) { - it(description, async function () { - const options = value === undefined ? {} : { __skipPingOnConnect: value }; - const client = this.configuration.newClient({}, { ...options, monitorCommands: true }); - const events = []; - client.on('commandStarted', event => events.push(event)); - - try { - await client.connect(); - } finally { - await client.close(); - } - - expect(events).to.have.lengthOf(expectEvents); - if (expectEvents > 1) { - for (const event of events) { - expect(event).to.have.property('commandName', 'ping'); - } - } - }); - } - }); - - // TODO(NODE-5672): Release Standardized Logger - describe('__enableMongoLogger', () => { - let cachedEnv; - - before(() => { - cachedEnv = process.env; - }); - - after(() => { - process.env = cachedEnv; - }); - - context('when enabled', () => { - context('when logging is enabled for any component', () => { - before(() => { - process.env.MONGODB_LOG_COMMAND = SeverityLevel.EMERGENCY; - }); - - it('enables logging for the specified component', () => { - const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: true - }); - expect(client.mongoLogger?.componentSeverities).to.have.property( - 'command', - SeverityLevel.EMERGENCY - ); - }); - }); - - context('when logging is not enabled for any component', () => { - before(() => { - process.env = {}; - }); - - it('does not create logger', () => { - const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: true - }); - expect(client.mongoLogger).to.not.exist; - }); - }); - }); - - for (const featureFlagValue of [false, undefined]) { - context(`when set to ${featureFlagValue}`, () => { - context('when logging is enabled for a component', () => { - before(() => { - process.env['MONGODB_LOG_COMMAND'] = SeverityLevel.EMERGENCY; - }); - - it('does not instantiate logger', () => { - const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: featureFlagValue - }); - expect(client.mongoLogger).to.not.exist; - }); - }); - - context('when logging is not enabled for any component', () => { - before(() => { - process.env = {}; - }); - - it('does not instantiate logger', () => { - const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: featureFlagValue - }); - expect(client.mongoLogger).to.not.exist; - }); - }); - }); - } - }); - - describe('__internalLoggerConfig', () => { - let cachedEnv: NodeJS.ProcessEnv; - - before(() => { - cachedEnv = process.env; - }); - - after(() => { - process.env = cachedEnv; - }); - - context('when undefined', function () { - before(() => { - process.env.MONGODB_LOG_COMMAND = SeverityLevel.EMERGENCY; - }); - - it('falls back to environment options', function () { - const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: true, - __internalLoggerConfig: undefined - }); - - expect(client.mongoLogger?.componentSeverities).to.have.property( - 'command', - SeverityLevel.EMERGENCY - ); - }); - }); - - context('when defined', function () { - it('overrides environment options', function () { - const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: true, - __internalLoggerConfig: { - MONGODB_LOG_COMMAND: SeverityLevel.ALERT - } - }); - - expect(client.mongoLogger?.componentSeverities).to.have.property( - 'command', - SeverityLevel.ALERT - ); - }); - }); - }); -}); diff --git a/test/integration/node-specific/mongo_client.test.ts b/test/integration/node-specific/mongo_client.test.ts index 823aafb7baf..17957a510d9 100644 --- a/test/integration/node-specific/mongo_client.test.ts +++ b/test/integration/node-specific/mongo_client.test.ts @@ -15,6 +15,7 @@ import { MongoServerSelectionError, ReadPreference, ServerDescription, + SeverityLevel, Topology } from '../../mongodb'; import { runLater } from '../../tools/utils'; @@ -774,4 +775,171 @@ describe('class MongoClient', function () { }); }); }); + + describe('internal options', function () { + describe('__skipPingOnConnect', () => { + beforeEach(function () { + if (process.env.AUTH !== 'auth') { + this.currentTest.skipReason = 'ping count relies on auth to be enabled'; + this.skip(); + } + }); + + const tests = [ + // only skipInitiaPing=true will have no events upon connect + { description: 'should skip ping command when set to true', value: true, expectEvents: 0 }, + { + description: 'should not skip ping command when set to false', + value: false, + expectEvents: 1 + }, + { + description: 'should not skip ping command when unset', + value: undefined, + expectEvents: 1 + } + ]; + for (const { description, value, expectEvents } of tests) { + it(description, async function () { + const options = value === undefined ? {} : { __skipPingOnConnect: value }; + const client = this.configuration.newClient({}, { ...options, monitorCommands: true }); + const events = []; + client.on('commandStarted', event => events.push(event)); + + try { + await client.connect(); + } finally { + await client.close(); + } + + expect(events).to.have.lengthOf(expectEvents); + if (expectEvents > 1) { + for (const event of events) { + expect(event).to.have.property('commandName', 'ping'); + } + } + }); + } + }); + + // TODO(NODE-5672): Release Standardized Logger + describe('__enableMongoLogger', () => { + let cachedEnv; + + before(() => { + cachedEnv = process.env; + }); + + after(() => { + process.env = cachedEnv; + }); + + context('when enabled', () => { + context('when logging is enabled for any component', () => { + before(() => { + process.env.MONGODB_LOG_COMMAND = SeverityLevel.EMERGENCY; + }); + + it('enables logging for the specified component', () => { + const client = new MongoClient('mongodb://localhost:27017', { + __enableMongoLogger: true + }); + expect(client.mongoLogger?.componentSeverities).to.have.property( + 'command', + SeverityLevel.EMERGENCY + ); + }); + }); + + context('when logging is not enabled for any component', () => { + before(() => { + process.env = {}; + }); + + it('does not create logger', () => { + const client = new MongoClient('mongodb://localhost:27017', { + __enableMongoLogger: true + }); + expect(client.mongoLogger).to.not.exist; + }); + }); + }); + + for (const featureFlagValue of [false, undefined]) { + context(`when set to ${featureFlagValue}`, () => { + context('when logging is enabled for a component', () => { + before(() => { + process.env['MONGODB_LOG_COMMAND'] = SeverityLevel.EMERGENCY; + }); + + it('does not instantiate logger', () => { + const client = new MongoClient('mongodb://localhost:27017', { + __enableMongoLogger: featureFlagValue + }); + expect(client.mongoLogger).to.not.exist; + }); + }); + + context('when logging is not enabled for any component', () => { + before(() => { + process.env = {}; + }); + + it('does not instantiate logger', () => { + const client = new MongoClient('mongodb://localhost:27017', { + __enableMongoLogger: featureFlagValue + }); + expect(client.mongoLogger).to.not.exist; + }); + }); + }); + } + }); + + describe('__internalLoggerConfig', () => { + let cachedEnv: NodeJS.ProcessEnv; + + before(() => { + cachedEnv = process.env; + }); + + after(() => { + process.env = cachedEnv; + }); + + context('when undefined', function () { + before(() => { + process.env.MONGODB_LOG_COMMAND = SeverityLevel.EMERGENCY; + }); + + it('falls back to environment options', function () { + const client = new MongoClient('mongodb://localhost:27017', { + __enableMongoLogger: true, + __internalLoggerConfig: undefined + }); + + expect(client.mongoLogger?.componentSeverities).to.have.property( + 'command', + SeverityLevel.EMERGENCY + ); + }); + }); + + context('when defined', function () { + it('overrides environment options', function () { + const client = new MongoClient('mongodb://localhost:27017', { + __enableMongoLogger: true, + __internalLoggerConfig: { + MONGODB_LOG_COMMAND: SeverityLevel.ALERT + } + }); + + expect(client.mongoLogger?.componentSeverities).to.have.property( + 'command', + SeverityLevel.ALERT + ); + }); + }); + }); + }); }); From 54e08c9cafb21c80930f35e20e20d69bc82742b2 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 19 Dec 2024 13:22:17 -0500 Subject: [PATCH 9/9] chore: feature rm --- test/integration/node-specific/mongo_client.test.ts | 8 ++++---- test/unit/sdam/server_selection.test.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/integration/node-specific/mongo_client.test.ts b/test/integration/node-specific/mongo_client.test.ts index 17957a510d9..059d9d82c2d 100644 --- a/test/integration/node-specific/mongo_client.test.ts +++ b/test/integration/node-specific/mongo_client.test.ts @@ -865,8 +865,8 @@ describe('class MongoClient', function () { }); }); - for (const featureFlagValue of [false, undefined]) { - context(`when set to ${featureFlagValue}`, () => { + for (const optionValue of [false, undefined]) { + context(`when set to ${optionValue}`, () => { context('when logging is enabled for a component', () => { before(() => { process.env['MONGODB_LOG_COMMAND'] = SeverityLevel.EMERGENCY; @@ -874,7 +874,7 @@ describe('class MongoClient', function () { it('does not instantiate logger', () => { const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: featureFlagValue + __enableMongoLogger: optionValue }); expect(client.mongoLogger).to.not.exist; }); @@ -887,7 +887,7 @@ describe('class MongoClient', function () { it('does not instantiate logger', () => { const client = new MongoClient('mongodb://localhost:27017', { - __enableMongoLogger: featureFlagValue + __enableMongoLogger: optionValue }); expect(client.mongoLogger).to.not.exist; }); diff --git a/test/unit/sdam/server_selection.test.ts b/test/unit/sdam/server_selection.test.ts index e2c581dfb9e..b372178479f 100644 --- a/test/unit/sdam/server_selection.test.ts +++ b/test/unit/sdam/server_selection.test.ts @@ -610,7 +610,7 @@ describe('server selection', function () { }); }); - describe('server selection logging feature flagging', function () { + describe('willLog()', function () { let mockServer; let topology; let address;