mongo 2.11.3 → 2.11.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/mongo/address.rb +53 -37
- data/lib/mongo/server/connection.rb +1 -2
- data/lib/mongo/server/monitor/connection.rb +1 -2
- data/lib/mongo/socket.rb +10 -1
- data/lib/mongo/version.rb +1 -1
- data/spec/integration/bson_symbol_spec.rb +34 -0
- data/spec/integration/connection_spec.rb +57 -9
- data/spec/integration/retryable_errors_spec.rb +2 -2
- data/spec/mongo/address_spec.rb +19 -13
- data/spec/mongo/auth/scram/conversation_spec.rb +2 -0
- data/spec/mongo/collection_spec.rb +2 -2
- data/spec/mongo/server/connection_spec.rb +6 -6
- data/spec/mongo/server/monitor/connection_spec.rb +6 -6
- data/spec/mongo/socket/ssl_spec.rb +132 -98
- data/spec/mongo/socket/tcp_spec.rb +1 -9
- data/spec/support/cluster_tools.rb +5 -3
- data/spec/support/lite_constraints.rb +8 -0
- metadata +632 -630
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d3363520c62689e2f649389acd84f68b46dba99a62d82c174c77414f66e055dd
|
4
|
+
data.tar.gz: 7b1a54bcc8657047ec15b61cdf39588965fc9328d0ac56aa294f7891ef7fb3e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 546bfab9a6042f6194f87efc8f19fa92ee9828040d1f34a98045e243cce6f056837e4144856a37803f964cf345724ccfdeb6eb2d407f265b4a02e7a14622f0a1
|
7
|
+
data.tar.gz: 9eb09ae2c44b3cee7cd9c082af7702b0acd4b56674a6c17b3959c05f654987b3b34f6d87c8d74d9863f312addc01a8de090899a879847d014fa0e7c9baa217d6
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/mongo/address.rb
CHANGED
@@ -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
|
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
|
-
#
|
144
|
-
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
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
|
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
|
-
|
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
|
data/lib/mongo/socket.rb
CHANGED
@@ -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
|
data/lib/mongo/version.rb
CHANGED
@@ -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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
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.
|
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.
|
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
|
data/spec/mongo/address_spec.rb
CHANGED
@@ -249,11 +249,7 @@ describe Mongo::Address do
|
|
249
249
|
end
|
250
250
|
end
|
251
251
|
|
252
|
-
context 'when creating a socket
|
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
|
@@ -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.
|
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.
|
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 '
|
1124
|
-
expect(connection.address.
|
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 '
|
1143
|
-
expect(connection.address.
|
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.
|
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.
|
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 '
|
102
|
-
expect(connection.address.
|
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 '
|
117
|
-
expect(connection.address.
|
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
|