mongo 2.11.3 → 2.11.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1ec5495bf06a11fa0003454eb892099bc1a86da8ef1694fc25990c18d2f64ba
4
- data.tar.gz: b07b2a3f5b71e89e66d6117253e1c85e4c6c90b8a8bb2f17cee24a8b47b9dad8
3
+ metadata.gz: d3363520c62689e2f649389acd84f68b46dba99a62d82c174c77414f66e055dd
4
+ data.tar.gz: 7b1a54bcc8657047ec15b61cdf39588965fc9328d0ac56aa294f7891ef7fb3e2
5
5
  SHA512:
6
- metadata.gz: 6e88a5e7d0a2bd2917c4ba887d38786229fd9f64e2056b894ccd3289983b52f7aa8b293d77c46df4412d1fb01faed8bb41bfe93fa08e5085a8ec88fe22aaed34
7
- data.tar.gz: fe47a5b889ff2b9449475e040d6e189bc984158e5c6b0cfab055dcce83d7efb090ec129eb5afee5cfed7a4b30ddda6bcc0d60e1b8720ff96f188548f28a75460
6
+ metadata.gz: 546bfab9a6042f6194f87efc8f19fa92ee9828040d1f34a98045e243cce6f056837e4144856a37803f964cf345724ccfdeb6eb2d407f265b4a02e7a14622f0a1
7
+ data.tar.gz: 9eb09ae2c44b3cee7cd9c082af7702b0acd4b56674a6c17b3959c05f654987b3b34f6d87c8d74d9863f312addc01a8de090899a879847d014fa0e7c9baa217d6
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -66,6 +66,8 @@ module Mongo
66
66
  # @param [ String ] seed The provided address.
67
67
  # @param [ Hash ] options The address options.
68
68
  #
69
+ # @option options [ Float ] :connect_timeout Connect timeout.
70
+ #
69
71
  # @since 2.0.0
70
72
  def initialize(seed, options = {})
71
73
  if seed.nil?
@@ -85,6 +87,9 @@ module Mongo
85
87
  # @return [ Integer ] port The port.
86
88
  attr_reader :port
87
89
 
90
+ # @api private
91
+ attr_reader :options
92
+
88
93
  # Check equality of the address to another.
89
94
  #
90
95
  # @example Check address equality.
@@ -138,13 +143,30 @@ module Mongo
138
143
  "#<Mongo::Address:0x#{object_id} address=#{to_s}>"
139
144
  end
140
145
 
141
- # Get a socket for the provided address, given the options.
146
+ # Get a socket for the address stored in this object, given the options.
147
+ #
148
+ # If the address stored in this object looks like a Unix path, this method
149
+ # returns a Unix domain socket for this path.
142
150
  #
143
- # The address the socket connects to is determined by the algorithm described in the
144
- # #intialize_resolver! documentation. Each time this method is called, #initialize_resolver!
145
- # will be called, meaning that a new hostname lookup will occur. This is done so that any
146
- # changes to which addresses the hostname resolves to will be picked up even if a socket has
147
- # been connected to it before.
151
+ # Otherwise, this method attempts to resolve the address stored in
152
+ # this object to IPv4 and IPv6 addresses using +Socket#getaddrinfo+, then
153
+ # connects to the resulting addresses and returns the socket of the first
154
+ # successful connection. The order in which address families (IPv4/IPV6)
155
+ # are tried is the same order in which the addresses are returned by
156
+ # +getaddrinfo+, and is determined by the host system.
157
+ #
158
+ # Name resolution is performed on each +socket+ call. This is done so that
159
+ # any changes to which addresses the host names used as seeds or in
160
+ # server configuration resolve to are immediately noticed by the driver,
161
+ # even if a socket has been connected to the affected host name/address
162
+ # before. However, note that DNS TTL values may still affect when a change
163
+ # to a host address is noticed by the driver.
164
+ #
165
+ # This method propagates any exceptions raised during DNS resolution and
166
+ # subsequent connection attempts. In case of a host name resolving to
167
+ # multiple IP addresses, the error raised by the last attempt is propagated
168
+ # to the caller. This method does not map exceptions to Mongo::Error
169
+ # subclasses, and may raise any subclass of Exception.
148
170
  #
149
171
  # @example Get a socket.
150
172
  # address.socket(5, :ssl => true)
@@ -155,11 +177,34 @@ module Mongo
155
177
  #
156
178
  # @option options [ Float ] :connect_timeout Connect timeout.
157
179
  #
158
- # @return [ Mongo::Socket::SSL, Mongo::Socket::TCP, Mongo::Socket::Unix ] The socket.
180
+ # @return [ Mongo::Socket::SSL | Mongo::Socket::TCP | Mongo::Socket::Unix ]
181
+ # The socket.
182
+ #
183
+ # @raise [ Exception ] If network connection failed.
159
184
  #
160
185
  # @since 2.0.0
161
186
  def socket(socket_timeout, ssl_options = {}, options = {})
162
- create_resolver(ssl_options).socket(socket_timeout, ssl_options, options)
187
+ if seed.downcase =~ Unix::MATCH
188
+ specific_address = Unix.new(seed.downcase)
189
+ return specific_address.socket(socket_timeout, ssl_options, options)
190
+ end
191
+
192
+ options = {
193
+ connect_timeout: Server::CONNECT_TIMEOUT,
194
+ }.update(options)
195
+
196
+ family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
197
+ error = nil
198
+ ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).each do |info|
199
+ begin
200
+ specific_address = FAMILY_MAP[info[4]].new(info[3], port, host)
201
+ socket = specific_address.socket(socket_timeout, ssl_options, options)
202
+ return socket
203
+ rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
204
+ error = e
205
+ end
206
+ end
207
+ raise error
163
208
  end
164
209
 
165
210
  # Get the address as a string.
@@ -182,37 +227,8 @@ module Mongo
182
227
  end
183
228
  end
184
229
 
185
- # @api private
186
- def connect_timeout
187
- @connect_timeout ||= @options[:connect_timeout] || Server::CONNECT_TIMEOUT
188
- end
189
-
190
230
  private
191
231
 
192
- # To determine which address the socket will connect to, the driver will
193
- # attempt to connect to each IP address returned by Socket::getaddrinfo in
194
- # sequence. Once a successful connection is made, a resolver with that
195
- # IP address specified is returned. If no successful connection is
196
- # made, the error made by the last connection attempt is raised.
197
- def create_resolver(ssl_options)
198
- return Unix.new(seed.downcase) if seed.downcase =~ Unix::MATCH
199
-
200
- family = (host == LOCALHOST) ? ::Socket::AF_INET : ::Socket::AF_UNSPEC
201
- error = nil
202
- ::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).each do |info|
203
- begin
204
- specific_address = FAMILY_MAP[info[4]].new(info[3], port, host)
205
- socket = specific_address.socket(
206
- connect_timeout, ssl_options, connect_timeout: connect_timeout)
207
- socket.close
208
- return specific_address
209
- rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
210
- error = e
211
- end
212
- end
213
- raise error
214
- end
215
-
216
232
  def parse_host_port
217
233
  address = seed.downcase
218
234
  case address
@@ -187,8 +187,7 @@ module Mongo
187
187
 
188
188
  # Separate method to permit easier mocking in the test suite.
189
189
  def do_connect
190
- socket = address.socket(socket_timeout, ssl_options,
191
- connect_timeout: address.connect_timeout)
190
+ socket = address.socket(socket_timeout, ssl_options, address.options)
192
191
 
193
192
  begin
194
193
  handshake!(socket)
@@ -162,8 +162,7 @@ module Mongo
162
162
  # @since 2.0.0
163
163
  def connect!
164
164
  unless @socket
165
- socket = address.socket(socket_timeout, ssl_options,
166
- connect_timeout: address.connect_timeout)
165
+ socket = address.socket(socket_timeout, ssl_options, address.options)
167
166
  handshake!(socket)
168
167
  @socket = socket
169
168
  end
@@ -63,7 +63,16 @@ module Mongo
63
63
  def alive?
64
64
  sock_arr = [ @socket ]
65
65
  if Kernel::select(sock_arr, nil, sock_arr, 0)
66
- eof?
66
+ # The eof? call is supposed to return immediately since select
67
+ # indicated the socket is readable. However, if @socket is an SSL
68
+ # socket, eof? can block anyway - see RUBY-2140.
69
+ begin
70
+ Timeout.timeout(0.1) do
71
+ eof?
72
+ end
73
+ rescue ::Timeout::Error
74
+ true
75
+ end
67
76
  else
68
77
  true
69
78
  end
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.11.3'.freeze
20
+ VERSION = '2.11.4'.freeze
21
21
  end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Symbol encoding to BSON' do
4
+ let(:value) { :foo }
5
+
6
+ let(:hash) do
7
+ {'foo' => value}
8
+ end
9
+
10
+ let(:serialized) do
11
+ hash.to_bson.to_s
12
+ end
13
+
14
+ let(:expected) do
15
+ "\x12\x00\x00\x00\x0Efoo\x00\x04\x00\x00\x00foo\x00\x00".force_encoding('binary')
16
+ end
17
+
18
+ it 'encodes symbol to BSON symbol' do
19
+ serialized.should == expected
20
+ end
21
+
22
+ it 'round-trips symbol values' do
23
+ buffer = BSON::ByteBuffer.new(serialized)
24
+ Hash.from_bson(buffer).should == hash
25
+ end
26
+
27
+ it 'round-trips symbol values using the same byte buffer' do
28
+ if BSON::Environment.jruby?
29
+ pending 'https://jira.mongodb.org/browse/RUBY-2128'
30
+ end
31
+
32
+ Hash.from_bson(hash.to_bson).should == hash
33
+ end
34
+ end
@@ -12,17 +12,18 @@ describe 'Connections' do
12
12
  let(:server) { client.cluster.servers.first }
13
13
 
14
14
  describe '#connect!' do
15
- # On JRuby 9.2.7.0, this line:
16
- # expect_any_instance_of(Mongo::Socket).to receive(:write).and_raise(exception)
17
- # ... appears to produce a moment in which Mongo::Socket#write is undefined
18
- # entirely, resulting in this failure:
19
- # RSpec::Expectations::ExpectationNotMetError: expected Mongo::Error::SocketError, got #<NameError: undefined method `write' for class `Mongo::Socket'>
20
- fails_on_jruby
15
+
16
+ let(:connection) do
17
+ Mongo::Server::Connection.new(server, server.options)
18
+ end
21
19
 
22
20
  context 'network error during handshake' do
23
- let(:connection) do
24
- Mongo::Server::Connection.new(server, server.options)
25
- end
21
+ # On JRuby 9.2.7.0, this line:
22
+ # expect_any_instance_of(Mongo::Socket).to receive(:write).and_raise(exception)
23
+ # ... appears to produce a moment in which Mongo::Socket#write is undefined
24
+ # entirely, resulting in this failure:
25
+ # RSpec::Expectations::ExpectationNotMetError: expected Mongo::Error::SocketError, got #<NameError: undefined method `write' for class `Mongo::Socket'>
26
+ fails_on_jruby
26
27
 
27
28
  let(:exception) { Mongo::Error::SocketError }
28
29
 
@@ -120,6 +121,53 @@ describe 'Connections' do
120
121
  expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::ReplicaSetNoPrimary)
121
122
  end
122
123
  end
124
+
125
+ describe 'number of sockets created' do
126
+
127
+ before do
128
+ server
129
+ end
130
+
131
+ shared_examples_for 'is 1 per connection' do
132
+ it 'is 1 per connection' do
133
+ # Instantiating a connection object should not create any sockets
134
+ RSpec::Mocks.with_temporary_scope do
135
+ expect(socket_cls).not_to receive(:new)
136
+
137
+ connection
138
+ end
139
+
140
+ # When the connection connects, exactly one socket should be created
141
+ # (and subsequently connected)
142
+ RSpec::Mocks.with_temporary_scope do
143
+ expect(socket_cls).to receive(:new).and_call_original
144
+
145
+ connection.connect!
146
+ end
147
+ end
148
+ end
149
+
150
+ let(:socket_cls) { ::Socket }
151
+
152
+ it_behaves_like 'is 1 per connection'
153
+
154
+ context 'connection to Unix domain socket' do
155
+ # Server does not allow Unix socket connections when TLS is enabled
156
+ require_no_tls
157
+
158
+ let(:port) { SpecConfig.instance.any_port }
159
+
160
+ let(:client) do
161
+ new_local_client(["/tmp/mongodb-#{port}.sock"], connect: :direct).tap do |client|
162
+ stop_monitoring(client)
163
+ end
164
+ end
165
+
166
+ let(:socket_cls) { ::UNIXSocket }
167
+
168
+ it_behaves_like 'is 1 per connection'
169
+ end
170
+ end
123
171
  end
124
172
 
125
173
  describe 'wire protocol version range update' do
@@ -24,7 +24,7 @@ describe 'Failing retryable operations' do
24
24
  end
25
25
 
26
26
  after do
27
- ClusterTools.instance.direct_client_for_each_server do |client|
27
+ ClusterTools.instance.direct_client_for_each_data_bearing_server do |client|
28
28
  client.use(:admin).database.command(clear_fail_point_command)
29
29
  end
30
30
  end
@@ -62,7 +62,7 @@ describe 'Failing retryable operations' do
62
62
  server.monitor.stop!
63
63
  end
64
64
 
65
- ClusterTools.instance.direct_client_for_each_server do |client|
65
+ ClusterTools.instance.direct_client_for_each_data_bearing_server do |client|
66
66
  client.use(:admin).database.command(fail_point_command)
67
67
  end
68
68
  end
@@ -249,11 +249,7 @@ describe Mongo::Address do
249
249
  end
250
250
  end
251
251
 
252
- context 'when creating a socket using the resolver' do
253
-
254
- before do
255
- address.send(:create_resolver, SpecConfig.instance.ssl_options)
256
- end
252
+ context 'when creating a socket' do
257
253
 
258
254
  it 'uses the host, not the IP address' do
259
255
  expect(address.socket(0.0).host).to eq(socket_address_or_host)
@@ -285,6 +281,24 @@ describe Mongo::Address do
285
281
  end
286
282
  end
287
283
  end
284
+
285
+ describe ':connect_timeout option' do
286
+ clean_slate
287
+
288
+ let(:address) { Mongo::Address.new('127.0.0.1') }
289
+
290
+ it 'defaults to 10' do
291
+ RSpec::Mocks.with_temporary_scope do
292
+ resolved_address = double('address')
293
+ # This test's expectation
294
+ expect(resolved_address).to receive(:socket).with(0, {}, connect_timeout: 10)
295
+
296
+ expect(Mongo::Address::IPv4).to receive(:new).and_return(resolved_address)
297
+
298
+ address.socket(0)
299
+ end
300
+ end
301
+ end
288
302
  end
289
303
 
290
304
  describe '#to_s' do
@@ -320,12 +334,4 @@ describe Mongo::Address do
320
334
  end
321
335
  end
322
336
  end
323
-
324
- describe '#connect_timeout' do
325
- let(:address) { Mongo::Address.new('127.0.0.1') }
326
-
327
- it 'defaults to 10' do
328
- expect(address.send(:connect_timeout)).to eq(10)
329
- end
330
- end
331
337
  end
@@ -35,6 +35,8 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
35
35
  end
36
36
 
37
37
  describe '#start' do
38
+ # Test uses global assertions
39
+ clean_slate
38
40
 
39
41
  let(:query) do
40
42
  conversation.start(nil)
@@ -278,9 +278,9 @@ describe Mongo::Collection do
278
278
  require_topology :replica_set
279
279
 
280
280
  let(:client_options) do
281
- {
281
+ SpecConfig.instance.auth_options.merge(
282
282
  read: { mode: :primary_preferred },
283
- }
283
+ )
284
284
  end
285
285
 
286
286
  let(:subscriber) { EventSubscriber.new }
@@ -1080,7 +1080,7 @@ describe Mongo::Server::Connection, retry: 3 do
1080
1080
  end
1081
1081
 
1082
1082
  it 'uses the connect_timeout for the address' do
1083
- expect(connection.address.send(:connect_timeout)).to eq(3)
1083
+ expect(connection.address.options[:connect_timeout]).to eq(3)
1084
1084
  end
1085
1085
 
1086
1086
  it 'uses the socket_timeout as the socket_timeout' do
@@ -1099,7 +1099,7 @@ describe Mongo::Server::Connection, retry: 3 do
1099
1099
  end
1100
1100
 
1101
1101
  it 'uses the connect_timeout for the address' do
1102
- expect(connection.address.send(:connect_timeout)).to eq(3)
1102
+ expect(connection.address.options[:connect_timeout]).to eq(3)
1103
1103
  end
1104
1104
 
1105
1105
  it 'does not use a socket_timeout' do
@@ -1120,8 +1120,8 @@ describe Mongo::Server::Connection, retry: 3 do
1120
1120
  connection.connect!
1121
1121
  end
1122
1122
 
1123
- it 'uses the default connect_timeout for the address' do
1124
- expect(connection.address.send(:connect_timeout)).to eq(10)
1123
+ it 'does not specify connect_timeout for the address' do
1124
+ expect(connection.address.options[:connect_timeout]).to be nil
1125
1125
  end
1126
1126
 
1127
1127
  it 'uses the socket_timeout' do
@@ -1139,8 +1139,8 @@ describe Mongo::Server::Connection, retry: 3 do
1139
1139
  connection.connect!
1140
1140
  end
1141
1141
 
1142
- it 'uses the default connect_timeout for the address' do
1143
- expect(connection.address.send(:connect_timeout)).to eq(10)
1142
+ it 'does not specify connect_timeout for the address' do
1143
+ expect(connection.address.options[:connect_timeout]).to be nil
1144
1144
  end
1145
1145
 
1146
1146
  it 'does not use a socket_timeout' do
@@ -66,7 +66,7 @@ describe Mongo::Server::Monitor::Connection do
66
66
  end
67
67
 
68
68
  it 'uses the connect_timeout for the address' do
69
- expect(connection.address.send(:connect_timeout)).to eq(3)
69
+ expect(connection.address.options[:connect_timeout]).to eq(3)
70
70
  end
71
71
 
72
72
  it 'uses the connect_timeout as the socket_timeout' do
@@ -81,7 +81,7 @@ describe Mongo::Server::Monitor::Connection do
81
81
  end
82
82
 
83
83
  it 'uses the connect_timeout for the address' do
84
- expect(connection.address.send(:connect_timeout)).to eq(3)
84
+ expect(connection.address.options[:connect_timeout]).to eq(3)
85
85
  end
86
86
 
87
87
  it 'uses the connect_timeout as the socket_timeout' do
@@ -98,8 +98,8 @@ describe Mongo::Server::Monitor::Connection do
98
98
  SpecConfig.instance.test_options.merge(connect_timeout: nil, socket_timeout: 5)
99
99
  end
100
100
 
101
- it 'uses the default connect_timeout for the address' do
102
- expect(connection.address.send(:connect_timeout)).to eq(10)
101
+ it 'does not specify connect_timeout for the address' do
102
+ expect(connection.address.options[:connect_timeout]).to be nil
103
103
  end
104
104
 
105
105
  it 'uses the connect_timeout as the socket_timeout' do
@@ -113,8 +113,8 @@ describe Mongo::Server::Monitor::Connection do
113
113
  SpecConfig.instance.test_options.merge(connect_timeout: nil, socket_timeout: nil)
114
114
  end
115
115
 
116
- it 'uses the default connect_timeout for the address' do
117
- expect(connection.address.send(:connect_timeout)).to eq(10)
116
+ it 'does not specify connect_timeout for the address' do
117
+ expect(connection.address.options[:connect_timeout]).to be nil
118
118
  end
119
119
 
120
120
  it 'uses the connect_timeout as the socket_timeout' do