From fa337ae07238ee1c9b33020449897c7c77a686ba Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov Date: Fri, 14 Nov 2025 14:43:10 +0100 Subject: [PATCH 1/2] RUBY-3722 Properly handle SocketError --- lib/mongo/address.rb | 10 ++++++++-- lib/mongo/socket.rb | 2 +- spec/lite_spec_helper.rb | 2 +- spec/mongo/address_spec.rb | 11 +++++++++++ spec/mongo/socket_spec.rb | 8 ++++++++ 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/lib/mongo/address.rb b/lib/mongo/address.rb index e349ee0619..4d0d2cfd2a 100644 --- a/lib/mongo/address.rb +++ b/lib/mongo/address.rb @@ -237,7 +237,7 @@ def socket(socket_timeout, opts = {}) # (multiple identical items in the returned array). It does not make # sense to try to connect to the same address more than once, thus # eliminate duplicates here. - infos = ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM) + infos = getaddrinfo(host, family) results = infos.map do |info| [info[4], info[3]] end.uniq @@ -276,6 +276,12 @@ def to_s private + # This is a simple wrapper around Socket.getaddrinfo added to + # make testing easier. + def getaddrinfo(host, family) + ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM) + end + def parse_host_port address = seed.downcase case address @@ -305,7 +311,7 @@ def map_exceptions(csot) else raise e end - rescue IOError, SystemCallError => e + rescue IOError, SystemCallError, ::SocketError => e raise Error::SocketError, "#{e.class}: #{e} (for #{self})" rescue OpenSSL::SSL::SSLError => e raise Error::SocketError, "#{e.class}: #{e} (for #{self})" diff --git a/lib/mongo/socket.rb b/lib/mongo/socket.rb index 6d25780a30..881aad33c1 100644 --- a/lib/mongo/socket.rb +++ b/lib/mongo/socket.rb @@ -609,7 +609,7 @@ def map_exceptions yield rescue Errno::ETIMEDOUT => e raise Error::SocketTimeoutError, "#{e.class}: #{e} (for #{human_address})" - rescue IOError, SystemCallError => e + rescue IOError, SystemCallError, ::SocketError => e raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})" rescue OpenSSL::SSL::SSLError => e raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})" diff --git a/spec/lite_spec_helper.rb b/spec/lite_spec_helper.rb index 486d9c4235..be219ee9d1 100644 --- a/spec/lite_spec_helper.rb +++ b/spec/lite_spec_helper.rb @@ -97,7 +97,7 @@ module Mrss require 'mrss/session_registry' require 'support/local_resource_registry' -if SpecConfig.instance.mri? && !SpecConfig.instance.windows? +if SpecConfig.instance.mri? && (SpecConfig.instance.linux? || SpecConfig.instance.macos?) require 'timeout_interrupt' else require 'timeout' diff --git a/spec/mongo/address_spec.rb b/spec/mongo/address_spec.rb index d637f6eb9c..a25656dd2a 100644 --- a/spec/mongo/address_spec.rb +++ b/spec/mongo/address_spec.rb @@ -319,6 +319,17 @@ end end end + context 'when a SocketError occurs' do + before do + allow(address).to receive(:getaddrinfo).and_raise(::SocketError) + end + + it 'raises a Mongo::Error::SocketError' do + expect { + address.socket(0.0) + }.to raise_error(Mongo::Error::SocketError) + end + end end describe '#to_s' do diff --git a/spec/mongo/socket_spec.rb b/spec/mongo/socket_spec.rb index b8c9f1f12e..c23301190b 100644 --- a/spec/mongo/socket_spec.rb +++ b/spec/mongo/socket_spec.rb @@ -53,6 +53,14 @@ end end.to raise_error(Mongo::Error::SocketError, 'OpenSSL::SSL::SSLError: Test error (for fake-address)') end + + it 'maps SocketError and preserves message' do + expect do + socket.send(:map_exceptions) do + raise SocketError.new('Test error') + end + end.to raise_error(Mongo::Error::SocketError, 'SocketError: Test error (for fake-address)') + end end describe '#read' do From 367446191d59ebe95e9e0f451138ca47cc90761b Mon Sep 17 00:00:00 2001 From: Dmitry Rybakov Date: Fri, 14 Nov 2025 16:47:16 +0100 Subject: [PATCH 2/2] Adjust spec --- spec/mongo/server/monitor/connection_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/mongo/server/monitor/connection_spec.rb b/spec/mongo/server/monitor/connection_spec.rb index 8d4bf9591d..8c87d0191c 100644 --- a/spec/mongo/server/monitor/connection_spec.rb +++ b/spec/mongo/server/monitor/connection_spec.rb @@ -153,7 +153,7 @@ expect(Socket).to receive(:getaddrinfo).and_raise(SocketError.new('Test exception')) lambda do connection.connect! - end.should raise_error(SocketError, 'Test exception') + end.should raise_error(Mongo::Error::SocketError, /SocketError: Test exception/) end end end