diff --git a/lib/mongo/server/pending_connection.rb b/lib/mongo/server/pending_connection.rb index 3bb53f4bec..1981e32812 100644 --- a/lib/mongo/server/pending_connection.rb +++ b/lib/mongo/server/pending_connection.rb @@ -110,6 +110,24 @@ def handshake_and_authenticate! private + # Sends the hello command to the server, then receive and deserialize + # the response. + # + # This method is extracted to be mocked in the tests. + # + # @param [ Protocol::Message ] Command that should be sent to a server + # for handshake purposes. + # + # @return [ Mongo::Protocol::Reply ] Deserialized server response. + def get_handshake_response(hello_command) + @server.round_trip_time_averager.measure do + add_server_diagnostics do + socket.write(hello_command.serialize.to_s) + Protocol::Message.deserialize(socket, Protocol::Message::MAX_MESSAGE_SIZE) + end + end + end + # @param [ BSON::Document | nil ] speculative_auth_doc The document to # provide in speculativeAuthenticate field of handshake command. # @@ -131,12 +149,7 @@ def handshake!(speculative_auth_doc: nil) doc = nil @server.handle_handshake_failure! do begin - response = @server.round_trip_time_averager.measure do - add_server_diagnostics do - socket.write(hello_command.serialize.to_s) - Protocol::Message.deserialize(socket, Protocol::Message::MAX_MESSAGE_SIZE) - end - end + response = get_handshake_response(hello_command) result = Operation::Result.new([response]) result.validate! doc = result.documents.first diff --git a/spec/mongo/server/connection_spec.rb b/spec/mongo/server/connection_spec.rb index a1acf2f69c..3d584ae090 100644 --- a/spec/mongo/server/connection_spec.rb +++ b/spec/mongo/server/connection_spec.rb @@ -583,6 +583,28 @@ class ConnectionSpecTestException < Exception; end end end + context 'when the server returns unknown saslSupportedMechs' do + min_server_version '4.0' + + let(:connection) do + described_class.new(server, server.options.merge(connection_pool: pool)) + end + + before do + expect_any_instance_of(Mongo::Server::PendingConnection).to receive(:get_handshake_response).and_wrap_original do |original_method, *args| + original_method.call(*args).tap do |result| + if result.documents.first.fetch('saslSupportedMechs', nil).is_a?(Array) + result.documents.first['saslSupportedMechs'].append('unknownMechanism') + end + end + end + end + + it 'does not raise an error' do + expect { connection.connect! }.not_to raise_error + end + end + end describe '#disconnect!' do