Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/cmap/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export async function prepareHandshakeDocument(
const { serverApi } = authContext.connection;

const handshakeDoc: HandshakeDocument = {
[serverApi?.version ? 'hello' : LEGACY_HELLO_COMMAND]: 1,
[serverApi?.version || options.loadBalanced === true ? 'hello' : LEGACY_HELLO_COMMAND]: 1,
helloOk: true,
client: options.metadata,
compression: compressors
Expand Down
13 changes: 11 additions & 2 deletions src/cmap/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
let cmd = { ...command };

const readPreference = getReadPreference(options);
const shouldUseOpMsg = supportsOpMsg(this);
const shouldUseOpMsg = supportsOpMsg(this, { loadBalanced: cmd.loadBalanced });
const session = options?.session;

let clusterTime = this.clusterTime;
Expand Down Expand Up @@ -637,8 +637,17 @@ export function hasSessionSupport(conn: Connection): boolean {
return description.logicalSessionTimeoutMinutes != null;
}

function supportsOpMsg(conn: Connection) {
/** @internal */
export function supportsOpMsg(conn: Connection, options: { loadBalanced?: boolean }) {
// If loadBalanced is true, then we MUST send the initial hello command using OP_MSG.
// Since this is the first message and hello/legacy hello hasn't been sent yet,
// conn.description will be null and we can't rely on the server check to determine if
// the server supports OP_MSG.
const description = conn.description;
if (options.loadBalanced === true && description == null) {
return true;
}

if (description == null) {
return false;
}
Expand Down
3 changes: 3 additions & 0 deletions test/unit/cmap/connect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ describe('Connect Tests', function () {
};
const handshakeDocument = await prepareHandshakeDocument(authContext);
expect(handshakeDocument).not.to.have.property('loadBalanced');
expect(handshakeDocument).to.have.property(LEGACY_HELLO_COMMAND, 1);
});
});

Expand All @@ -256,6 +257,7 @@ describe('Connect Tests', function () {
};
const handshakeDocument = await prepareHandshakeDocument(authContext);
expect(handshakeDocument).not.to.have.property('loadBalanced');
expect(handshakeDocument).to.have.property(LEGACY_HELLO_COMMAND, 1);
});
});

Expand All @@ -270,6 +272,7 @@ describe('Connect Tests', function () {
};
const handshakeDocument = await prepareHandshakeDocument(authContext);
expect(handshakeDocument).to.have.property('loadBalanced', true);
expect(handshakeDocument).to.have.property('hello', 1);
});
});
});
Expand Down
75 changes: 74 additions & 1 deletion test/unit/cmap/connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
MongoNetworkTimeoutError,
MongoRuntimeError,
ns,
type OperationDescription
type OperationDescription,
supportsOpMsg
} from '../../mongodb';
import * as mock from '../../tools/mongodb-mock/index';
import { generateOpMsgBuffer, getSymbolFrom } from '../../tools/utils';
Expand Down Expand Up @@ -894,6 +895,78 @@ describe('new Connection()', function () {
});
});

describe('.supportsOpMsg', function () {
let connection;

context('loadBalanced option is true', function () {
beforeEach(function () {
connection = {};
});

it('returns true', function () {
expect(supportsOpMsg(connection, { loadBalanced: true })).to.be.true;
});
});

context('loadBalanced is not requested and this is the first message', function () {
beforeEach(function () {
connection = {}; // The first message, therefore no description.
});

it('returns false', function () {
expect(supportsOpMsg(connection, {})).to.be.false;
});
});

context(
'the first message has been sent and maxWireVersion matches the compatible version',
function () {
beforeEach(function () {
connection = {
description: new InputStream(),
hello: { maxWireVersion: 6 }
};
});

it('returns true', function () {
expect(supportsOpMsg(connection, {})).to.be.true;
});
}
);

context(
'the first message has been sent and maxWireVersion is above the compatible version',
function () {
beforeEach(function () {
connection = {
description: new InputStream(),
hello: { maxWireVersion: 7 }
};
});

it('returns true', function () {
expect(supportsOpMsg(connection, {})).to.be.true;
});
}
);

context(
'the first message has been sent and maxWireVersion is below the compatible version',
function () {
beforeEach(function () {
connection = {
description: new InputStream(),
hello: { maxWireVersion: 5 }
};
});

it('returns false', function () {
expect(supportsOpMsg(connection, {})).to.be.false;
});
}
);
});

describe('destroy()', () => {
let connection: sinon.SinonSpiedInstance<Connection>;
let clock: sinon.SinonFakeTimers;
Expand Down