diff --git a/src/cmap/connection.ts b/src/cmap/connection.ts index 7c204d09dd..f5446ae931 100644 --- a/src/cmap/connection.ts +++ b/src/cmap/connection.ts @@ -90,7 +90,6 @@ export interface CommandOptions extends BSONSerializeOptions { /** Session to use for the operation */ session?: ClientSession; documentsReturnedIn?: string; - noResponse?: boolean; omitMaxTimeMS?: boolean; // TODO(NODE-2802): Currently the CommandOptions take a property willRetryWrite which is a hint @@ -467,7 +466,7 @@ export class Connection extends TypedEventEmitter { signal: options.signal }); - if (options.noResponse || message.moreToCome) { + if (message.moreToCome) { yield MongoDBResponse.empty; return; } @@ -567,11 +566,7 @@ export class Connection extends TypedEventEmitter { new CommandSucceededEvent( this, message, - options.noResponse - ? undefined - : message.moreToCome - ? { ok: 1 } - : (object ??= document.toObject(bsonOptions)), + message.moreToCome ? { ok: 1 } : (object ??= document.toObject(bsonOptions)), started, this.description.serverConnectionId ) diff --git a/src/operations/command.ts b/src/operations/command.ts index ab0bf1e1d9..da499fa685 100644 --- a/src/operations/command.ts +++ b/src/operations/command.ts @@ -56,11 +56,6 @@ export interface CommandOperationOptions // Admin command overrides. dbName?: string; authdb?: string; - /** - * @deprecated - * This option is deprecated and will be removed in an upcoming major version. - */ - noResponse?: boolean; /** * Used when the command needs to grant access to the underlying namespaces for time series collections. diff --git a/src/operations/end_sessions.ts b/src/operations/end_sessions.ts index 7340d8b03f..564dd596ba 100644 --- a/src/operations/end_sessions.ts +++ b/src/operations/end_sessions.ts @@ -3,15 +3,18 @@ import { type Connection, type ServerCommandOptions, type ServerSessionId, - type TimeoutContext + type TimeoutContext, + type WriteConcern } from '..'; import { type Document } from '../bson'; import { MongoDBResponse } from '../cmap/wire_protocol/responses'; +import { CommandOperation } from '../operations/command'; import { ReadPreference } from '../read_preference'; import { MongoDBNamespace } from '../utils'; -import { AbstractOperation } from './operation'; +import { Aspect, defineAspects } from './operation'; -export class EndSessionsOperation extends AbstractOperation { +export class EndSessionsOperation extends CommandOperation { + override writeConcern: WriteConcern = { w: 0 }; override ns = MongoDBNamespace.fromString('admin.$cmd'); override SERVER_COMMAND_RESPONSE_TYPE = MongoDBResponse; @@ -22,21 +25,20 @@ export class EndSessionsOperation extends AbstractOperation { this.sessions = sessions; } - override buildCommand(_connection: Connection, _session?: ClientSession): Document { + override buildCommandDocument(_connection: Connection, _session?: ClientSession): Document { return { endSessions: this.sessions }; } - override buildOptions(timeoutContext: TimeoutContext): ServerCommandOptions { return { timeoutContext, - readPreference: ReadPreference.primaryPreferred, - noResponse: true + readPreference: ReadPreference.primaryPreferred }; } - override get commandName(): string { return 'endSessions'; } } + +defineAspects(EndSessionsOperation, Aspect.WRITE_OPERATION); diff --git a/test/integration/connection-monitoring-and-pooling/connection.test.ts b/test/integration/connection-monitoring-and-pooling/connection.test.ts index 20272b128a..80be489a26 100644 --- a/test/integration/connection-monitoring-and-pooling/connection.test.ts +++ b/test/integration/connection-monitoring-and-pooling/connection.test.ts @@ -301,6 +301,14 @@ describe('Connection', function () { req.reply({ ok: 1 }); }, 800); }) + .addMessageHandler('endSessions', req => { + // TODO(NODE-6287): remove support for QP_QUERY from the mock server + // The mock server doesn't understand OP_MSG. So, MongoClient.close()'s use of the OP_MSG flag `moreToCome: true` + // on endSessions isn't relevant, and this test hangs unless we have a handler for `endSessions`. + // In practice, this isn't going to happen because we don't use OP_QUERY anywhere except for the initial + // handshake. + req.reply({ ok: 1 }); + }) .addMessageHandler('hello', req => { req.reply(Object.assign({}, mock.HELLO)); }) diff --git a/test/integration/node-specific/mongo_client.test.ts b/test/integration/node-specific/mongo_client.test.ts index f380d41e65..e8578d17b9 100644 --- a/test/integration/node-specific/mongo_client.test.ts +++ b/test/integration/node-specific/mongo_client.test.ts @@ -5,7 +5,6 @@ import * as sinon from 'sinon'; import { type Collection, - type CommandFailedEvent, type CommandStartedEvent, type CommandSucceededEvent, Db, @@ -862,23 +861,33 @@ describe('class MongoClient', function () { expect(result2).to.have.property('ok', 1); }); - it('sends endSessions with noResponse set', async () => { + it('sends endSessions with w: 0 set', async () => { const session = client.startSession(); // make a session to be ended await client.db('test').command({ ping: 1 }, { session }); await session.endSession(); const startedEvents: CommandStartedEvent[] = []; - const endEvents: Array = []; + const endEvents: Array = []; client.on('commandStarted', event => startedEvents.push(event)); client.on('commandSucceeded', event => endEvents.push(event)); - client.on('commandFailed', event => endEvents.push(event)); await client.close(); expect(startedEvents).to.have.lengthOf(1); - expect(startedEvents[0]).to.have.property('commandName', 'endSessions'); + const [ + { + command: { endSessions, writeConcern } + } + ] = startedEvents; + expect(endSessions).to.exist; + expect(writeConcern).to.deep.equal({ w: 0 }); expect(endEvents).to.have.lengthOf(1); - expect(endEvents[0]).to.have.property('reply', undefined); // noReponse: true + + const [{ reply }] = endEvents; + + // when unacknowledged writes are used, the driver uses `{ ok: 1 }` as a placeholder + // `reply` in CommandSucceededEvents + expect(reply).to.deep.equal({ ok: 1 }); }); describe('when server selection would return no servers', () => { diff --git a/test/unit/cmap/connection.test.ts b/test/unit/cmap/connection.test.ts index bab1422a89..779a320872 100644 --- a/test/unit/cmap/connection.test.ts +++ b/test/unit/cmap/connection.test.ts @@ -35,29 +35,6 @@ describe('new Connection()', function () { before(() => mock.createServer().then(s => (server = s))); - it('supports fire-and-forget messages', async function () { - server.setMessageHandler(request => { - const doc = request.document; - if (isHello(doc)) { - request.reply(mock.HELLO); - } - - // black hole all other requests - }); - - const options = { - ...connectionOptionsDefaults, - connectionType: Connection, - hostAddress: server.hostAddress(), - authProviders: new MongoClientAuthProviders() - }; - - const conn = await connect(options); - const readSpy = sinon.spy(conn, 'readMany'); - await conn.command(ns('$admin.cmd'), { ping: 1 }, { noResponse: true }); - expect(readSpy).to.not.have.been.called; - }); - it('destroys streams which time out', async function () { server.setMessageHandler(request => { const doc = request.document;