mongo 1.11.1 → 1.12.0.rc0
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/VERSION +1 -1
- data/lib/mongo/collection.rb +8 -3
- data/lib/mongo/collection_writer.rb +1 -1
- data/lib/mongo/connection/socket/unix_socket.rb +1 -1
- data/lib/mongo/cursor.rb +8 -1
- data/lib/mongo/db.rb +61 -33
- data/lib/mongo/exception.rb +57 -0
- data/lib/mongo/functional.rb +1 -0
- data/lib/mongo/functional/authentication.rb +138 -11
- data/lib/mongo/functional/read_preference.rb +31 -22
- data/lib/mongo/functional/scram.rb +555 -0
- data/lib/mongo/functional/uri_parser.rb +107 -79
- data/lib/mongo/mongo_client.rb +19 -24
- data/lib/mongo/mongo_replica_set_client.rb +2 -1
- data/test/functional/authentication_test.rb +3 -0
- data/test/functional/client_test.rb +33 -0
- data/test/functional/collection_test.rb +29 -19
- data/test/functional/db_api_test.rb +16 -1
- data/test/functional/pool_test.rb +7 -6
- data/test/functional/uri_test.rb +111 -7
- data/test/helpers/test_unit.rb +17 -3
- data/test/replica_set/client_test.rb +31 -0
- data/test/replica_set/insert_test.rb +49 -32
- data/test/replica_set/pinning_test.rb +50 -0
- data/test/replica_set/query_test.rb +1 -1
- data/test/replica_set/replication_ack_test.rb +3 -3
- data/test/shared/authentication/basic_auth_shared.rb +14 -1
- data/test/shared/authentication/gssapi_shared.rb +13 -8
- data/test/shared/authentication/scram_shared.rb +92 -0
- data/test/tools/mongo_config.rb +18 -6
- data/test/unit/client_test.rb +40 -6
- data/test/unit/connection_test.rb +15 -5
- data/test/unit/db_test.rb +1 -1
- data/test/unit/read_pref_test.rb +291 -0
- metadata +9 -6
- metadata.gz.sig +0 -0
@@ -22,7 +22,8 @@ module Mongo
|
|
22
22
|
|
23
23
|
HOST_REGEX = /([-.\w]+)|(\[[^\]]+\])/
|
24
24
|
PORT_REGEX = /(?::(\w+))?/
|
25
|
-
|
25
|
+
UNIX_SOCK_REGEX = /([\S]+.sock)/
|
26
|
+
NODE_REGEX = /((#{HOST_REGEX}#{PORT_REGEX},?)+|#{UNIX_SOCK_REGEX}{1})/
|
26
27
|
|
27
28
|
PATH_REGEX = /(?:\/([-\w]+))?/
|
28
29
|
|
@@ -41,15 +42,15 @@ module Mongo
|
|
41
42
|
|
42
43
|
OPT_ATTRS = [
|
43
44
|
:authmechanism,
|
45
|
+
:authmechanismproperties,
|
44
46
|
:authsource,
|
45
|
-
:canonicalizehostname,
|
46
47
|
:connect,
|
47
48
|
:connecttimeoutms,
|
48
49
|
:fsync,
|
49
|
-
:gssapiservicename,
|
50
50
|
:journal,
|
51
51
|
:pool_size,
|
52
52
|
:readpreference,
|
53
|
+
:readpreferencetags,
|
53
54
|
:replicaset,
|
54
55
|
:safe,
|
55
56
|
:slaveok,
|
@@ -61,89 +62,96 @@ module Mongo
|
|
61
62
|
]
|
62
63
|
|
63
64
|
OPT_VALID = {
|
64
|
-
:authmechanism
|
65
|
-
:
|
66
|
-
:
|
67
|
-
:connect
|
68
|
-
:connecttimeoutms
|
69
|
-
:fsync
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:replicaset
|
75
|
-
:safe
|
76
|
-
:slaveok
|
77
|
-
:sockettimeoutms
|
78
|
-
:ssl
|
79
|
-
:w
|
80
|
-
:wtimeout
|
81
|
-
:wtimeoutms
|
65
|
+
:authmechanism => lambda { |arg| Mongo::Authentication.validate_mechanism(arg) },
|
66
|
+
:authmechanismproperties => lambda { |arg| arg.length > 0 },
|
67
|
+
:authsource => lambda { |arg| arg.length > 0 },
|
68
|
+
:connect => lambda { |arg| [ 'direct', 'replicaset', 'true', 'false', true, false ].include?(arg) },
|
69
|
+
:connecttimeoutms => lambda { |arg| arg =~ /^\d+$/ },
|
70
|
+
:fsync => lambda { |arg| ['true', 'false'].include?(arg) },
|
71
|
+
:journal => lambda { |arg| ['true', 'false'].include?(arg) },
|
72
|
+
:pool_size => lambda { |arg| arg.to_i > 0 },
|
73
|
+
:readpreference => lambda { |arg| READ_PREFERENCES.keys.include?(arg) },
|
74
|
+
:readpreferencetags => lambda { |arg| arg.none? { |tags| tags.scan(/(\w+:\w+),?/).empty? } },
|
75
|
+
:replicaset => lambda { |arg| arg.length > 0 },
|
76
|
+
:safe => lambda { |arg| ['true', 'false'].include?(arg) },
|
77
|
+
:slaveok => lambda { |arg| ['true', 'false'].include?(arg) },
|
78
|
+
:sockettimeoutms => lambda { |arg| arg =~ /^\d+$/ },
|
79
|
+
:ssl => lambda { |arg| ['true', 'false'].include?(arg) },
|
80
|
+
:w => lambda { |arg| arg =~ /^\w+$/ },
|
81
|
+
:wtimeout => lambda { |arg| arg =~ /^\d+$/ },
|
82
|
+
:wtimeoutms => lambda { |arg| arg =~ /^\d+$/ }
|
82
83
|
}
|
83
84
|
|
84
85
|
OPT_ERR = {
|
85
|
-
:authmechanism
|
86
|
-
:
|
87
|
-
:
|
88
|
-
:connect
|
89
|
-
:connecttimeoutms
|
90
|
-
:fsync
|
91
|
-
:
|
92
|
-
:
|
93
|
-
:
|
94
|
-
:
|
95
|
-
:replicaset
|
96
|
-
:safe
|
97
|
-
:slaveok
|
98
|
-
:settimeoutms
|
99
|
-
:ssl
|
100
|
-
:w
|
101
|
-
|
102
|
-
|
103
|
-
:wtimeout
|
104
|
-
:wtimeoutms
|
86
|
+
:authmechanism => Mongo::Authentication::MECHANISM_ERROR,
|
87
|
+
:authmechanismproperties => "must meet the format requirements of the authentication mechanism's properties",
|
88
|
+
:authsource => "must be a string containing the name of the database being used for authentication",
|
89
|
+
:connect => "must be 'direct', 'replicaset', 'true', or 'false'",
|
90
|
+
:connecttimeoutms => "must be an integer specifying milliseconds",
|
91
|
+
:fsync => "must be 'true' or 'false'",
|
92
|
+
:journal => "must be 'true' or 'false'",
|
93
|
+
:pool_size => "must be an integer greater than zero",
|
94
|
+
:readpreference => "must be one of #{READ_PREFERENCES.keys.map(&:inspect).join(",")}",
|
95
|
+
:readpreferencetags => "must be a comma-separated list of one or more key:value pairs",
|
96
|
+
:replicaset => "must be a string containing the name of the replica set to connect to",
|
97
|
+
:safe => "must be 'true' or 'false'",
|
98
|
+
:slaveok => "must be 'true' or 'false'",
|
99
|
+
:settimeoutms => "must be an integer specifying milliseconds",
|
100
|
+
:ssl => "must be 'true' or 'false'",
|
101
|
+
:w => "must be an integer indicating number of nodes to replicate to or a string " +
|
102
|
+
"specifying that replication is required to the majority or nodes with a " +
|
103
|
+
"particilar getLastErrorMode.",
|
104
|
+
:wtimeout => "must be an integer specifying milliseconds",
|
105
|
+
:wtimeoutms => "must be an integer specifying milliseconds"
|
105
106
|
}
|
106
107
|
|
107
108
|
OPT_CONV = {
|
108
|
-
:authmechanism
|
109
|
-
:
|
110
|
-
:
|
111
|
-
:connect
|
112
|
-
:connecttimeoutms
|
113
|
-
:fsync
|
114
|
-
:
|
115
|
-
:
|
116
|
-
:
|
117
|
-
:
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
:
|
124
|
-
:
|
125
|
-
:
|
109
|
+
:authmechanism => lambda { |arg| arg.upcase },
|
110
|
+
:authmechanismproperties => lambda { |arg| arg },
|
111
|
+
:authsource => lambda { |arg| arg },
|
112
|
+
:connect => lambda { |arg| arg == 'false' ? false : arg }, # convert 'false' to FalseClass
|
113
|
+
:connecttimeoutms => lambda { |arg| arg.to_f / 1000 }, # stored as seconds
|
114
|
+
:fsync => lambda { |arg| arg == 'true' ? true : false },
|
115
|
+
:journal => lambda { |arg| arg == 'true' ? true : false },
|
116
|
+
:pool_size => lambda { |arg| arg.to_i },
|
117
|
+
:readpreference => lambda { |arg| READ_PREFERENCES[arg] },
|
118
|
+
:readpreferencetags => lambda { |arg| arg.map do |tags|
|
119
|
+
tags.scan(/(\w+:\w+),?/).reduce({}) do |tags, pair|
|
120
|
+
key, value = pair.first.split(":")
|
121
|
+
tags.merge!(key => value)
|
122
|
+
end
|
123
|
+
end },
|
124
|
+
:replicaset => lambda { |arg| arg },
|
125
|
+
:safe => lambda { |arg| arg == 'true' ? true : false },
|
126
|
+
:slaveok => lambda { |arg| arg == 'true' ? true : false },
|
127
|
+
:sockettimeoutms => lambda { |arg| arg.to_f / 1000 }, # stored as seconds
|
128
|
+
:ssl => lambda { |arg| arg == 'true' ? true : false },
|
129
|
+
:w => lambda { |arg| Mongo::Support.is_i?(arg) ? arg.to_i : arg.to_sym },
|
130
|
+
:wtimeout => lambda { |arg| arg.to_i },
|
131
|
+
:wtimeoutms => lambda { |arg| arg.to_i }
|
126
132
|
}
|
127
133
|
|
128
134
|
OPT_CASE_SENSITIVE = [ :authsource,
|
129
|
-
:
|
135
|
+
:authmechanismproperties,
|
130
136
|
:replicaset,
|
131
137
|
:w
|
132
138
|
]
|
133
139
|
|
140
|
+
OPT_NOT_STRING = [ :readpreferencetags ]
|
141
|
+
|
134
142
|
attr_reader :auths,
|
135
143
|
:authmechanism,
|
144
|
+
:authmechanismproperties,
|
136
145
|
:authsource,
|
137
|
-
:canonicalizehostname,
|
138
146
|
:connect,
|
139
147
|
:connecttimeoutms,
|
140
148
|
:db_name,
|
141
149
|
:fsync,
|
142
|
-
:gssapiservicename,
|
143
150
|
:journal,
|
144
151
|
:nodes,
|
145
152
|
:pool_size,
|
146
153
|
:readpreference,
|
154
|
+
:readpreferencetags,
|
147
155
|
:replicaset,
|
148
156
|
:safe,
|
149
157
|
:slaveok,
|
@@ -249,6 +257,7 @@ module Mongo
|
|
249
257
|
opts[:op_timeout] = @sockettimeoutms if @sockettimeoutms
|
250
258
|
opts[:pool_size] = @pool_size if @pool_size
|
251
259
|
opts[:read] = @readpreference if @readpreference
|
260
|
+
opts[:tag_sets] = @readpreferencetags if @readpreferencetags
|
252
261
|
|
253
262
|
if @slaveok && !@readpreference
|
254
263
|
unless replicaset?
|
@@ -287,20 +296,24 @@ module Mongo
|
|
287
296
|
|
288
297
|
user_info = matches[2].split(':') if matches[2]
|
289
298
|
host_info = matches[3].split(',')
|
290
|
-
@db_name = matches[
|
299
|
+
@db_name = matches[9]
|
291
300
|
|
292
|
-
host_info.
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
301
|
+
if host_info.first.end_with?('.sock')
|
302
|
+
@nodes << [ host_info.first ]
|
303
|
+
else
|
304
|
+
host_info.each do |host|
|
305
|
+
if host[0,1] == '['
|
306
|
+
host, port = host.split(']:') << MongoClient::DEFAULT_PORT
|
307
|
+
host = host.end_with?(']') ? host[1...-1] : host[1..-1]
|
308
|
+
else
|
309
|
+
host, port = host.split(':') << MongoClient::DEFAULT_PORT
|
310
|
+
end
|
311
|
+
unless port.to_s =~ /^\d+$/
|
312
|
+
raise MongoArgumentError,
|
313
|
+
"Invalid port #{port}; port must be specified as digits."
|
314
|
+
end
|
315
|
+
@nodes << [host, port.to_i]
|
302
316
|
end
|
303
|
-
@nodes << [host, port.to_i]
|
304
317
|
end
|
305
318
|
|
306
319
|
if @nodes.empty?
|
@@ -330,10 +343,10 @@ module Mongo
|
|
330
343
|
:username => URI.unescape(username),
|
331
344
|
:password => password ? URI.unescape(password) : nil,
|
332
345
|
:source => @authsource,
|
333
|
-
:mechanism => @authmechanism
|
346
|
+
:mechanism => @authmechanism,
|
347
|
+
:extra => @authmechanismproperties || {}
|
334
348
|
})
|
335
|
-
|
336
|
-
auth[:extra].merge!(:gssapi_service_name => @gssapiservicename) if @gssapiservicename
|
349
|
+
|
337
350
|
@auths << auth
|
338
351
|
end
|
339
352
|
end
|
@@ -353,9 +366,13 @@ module Mongo
|
|
353
366
|
end
|
354
367
|
|
355
368
|
opts = CGI.parse(string_opts).inject({}) do |memo, (key, value)|
|
356
|
-
value = value.first
|
357
369
|
key_sym = key.downcase.to_sym
|
358
|
-
|
370
|
+
if OPT_NOT_STRING.include?(key_sym)
|
371
|
+
memo[key_sym] = value
|
372
|
+
else
|
373
|
+
value = value.first
|
374
|
+
memo[key_sym] = OPT_CASE_SENSITIVE.include?(key_sym) ? value.strip : value.strip.downcase
|
375
|
+
end
|
359
376
|
memo
|
360
377
|
end
|
361
378
|
|
@@ -369,6 +386,17 @@ module Mongo
|
|
369
386
|
raise MongoArgumentError, "Invalid value #{value.inspect} for #{key}: #{OPT_ERR[key]}"
|
370
387
|
end
|
371
388
|
end
|
389
|
+
|
390
|
+
if @authmechanismproperties
|
391
|
+
@authmechanismproperties = @authmechanismproperties.split(',').reduce({}) do |prop, pair|
|
392
|
+
key, value = pair.split(':')
|
393
|
+
if ["true", "false"].include?(value.downcase)
|
394
|
+
value = value.downcase == "true"
|
395
|
+
end
|
396
|
+
prop[key.downcase.to_sym] = value
|
397
|
+
prop
|
398
|
+
end
|
399
|
+
end
|
372
400
|
end
|
373
401
|
|
374
402
|
def validate_connect
|
data/lib/mongo/mongo_client.rb
CHANGED
@@ -25,7 +25,8 @@ module Mongo
|
|
25
25
|
RELEASE_2_4_AND_BEFORE = 0 # Everything before we started tracking.
|
26
26
|
AGG_RETURNS_CURSORS = 1 # The aggregation command may now be requested to return cursors.
|
27
27
|
BATCH_COMMANDS = 2 # insert, update, and delete batch command
|
28
|
-
|
28
|
+
MONGODB_2_8 = 3 # listCollections and listIndexes commands, SCRAM-SHA-1 auth mechanism
|
29
|
+
MAX_WIRE_VERSION = MONGODB_2_8 # supported by this client implementation
|
29
30
|
MIN_WIRE_VERSION = RELEASE_2_4_AND_BEFORE # supported by this client implementation
|
30
31
|
|
31
32
|
# Server command headroom
|
@@ -41,6 +42,7 @@ module Mongo
|
|
41
42
|
DEFAULT_HOST = 'localhost'
|
42
43
|
DEFAULT_PORT = 27017
|
43
44
|
DEFAULT_DB_NAME = 'test'
|
45
|
+
DEFAULT_OP_TIMEOUT = 20
|
44
46
|
GENERIC_OPTS = [:auths, :logger, :connect, :db_name]
|
45
47
|
TIMEOUT_OPTS = [:timeout, :op_timeout, :connect_timeout]
|
46
48
|
SSL_OPTS = [:ssl, :ssl_key, :ssl_cert, :ssl_verify, :ssl_ca_cert, :ssl_key_pass_phrase]
|
@@ -125,8 +127,8 @@ module Mongo
|
|
125
127
|
# @option opts [Float] :pool_timeout (5.0) When all of the self.connections a pool are checked out,
|
126
128
|
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
127
129
|
# Note: this setting is relevant only for multi-threaded applications.
|
128
|
-
# @option opts [Float] :op_timeout (
|
129
|
-
#
|
130
|
+
# @option opts [Float] :op_timeout (DEFAULT_OP_TIMEOUT) The number of seconds to wait for a read operation to time out.
|
131
|
+
# Set to DEFAULT_OP_TIMEOUT (20) by default. A value of nil may be specified explicitly.
|
130
132
|
# @option opts [Float] :connect_timeout (nil) The number of seconds to wait before timing out a
|
131
133
|
# connection attempt.
|
132
134
|
#
|
@@ -332,26 +334,19 @@ module Mongo
|
|
332
334
|
# @param password [String] password (applies to 'from' db)
|
333
335
|
#
|
334
336
|
# @note This command only supports the MONGODB-CR authentication mechanism.
|
335
|
-
def copy_database(
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
nonce_cmd[:copydbgetnonce] = 1
|
348
|
-
nonce_cmd[:fromhost] = from_host
|
349
|
-
result = self['admin'].command(nonce_cmd)
|
350
|
-
oh[:nonce] = result['nonce']
|
351
|
-
oh[:username] = username
|
352
|
-
oh[:key] = Mongo::Authentication.auth_key(username, password, oh[:nonce])
|
337
|
+
def copy_database(
|
338
|
+
from,
|
339
|
+
to,
|
340
|
+
from_host = DEFAULT_HOST,
|
341
|
+
username = nil,
|
342
|
+
password = nil,
|
343
|
+
mechanism = 'SCRAM-SHA-1'
|
344
|
+
)
|
345
|
+
if wire_version_feature?(MONGODB_2_8) && mechanism == 'SCRAM-SHA-1'
|
346
|
+
copy_db_scram(username, password, from_host, from, to)
|
347
|
+
else
|
348
|
+
copy_db_mongodb_cr(username, password, from_host, from, to)
|
353
349
|
end
|
354
|
-
self['admin'].command(oh)
|
355
350
|
end
|
356
351
|
|
357
352
|
# Checks if a server is alive. This command will return immediately
|
@@ -446,7 +441,7 @@ module Mongo
|
|
446
441
|
ping
|
447
442
|
true
|
448
443
|
|
449
|
-
rescue ConnectionFailure
|
444
|
+
rescue ConnectionFailure, OperationTimeout
|
450
445
|
false
|
451
446
|
end
|
452
447
|
|
@@ -634,7 +629,7 @@ module Mongo
|
|
634
629
|
@pool_timeout = opts.delete(:pool_timeout) || opts.delete(:timeout) || 5.0
|
635
630
|
|
636
631
|
# Timeout on socket read operation.
|
637
|
-
@op_timeout = opts.delete(:op_timeout)
|
632
|
+
@op_timeout = opts.key?(:op_timeout) ? opts.delete(:op_timeout) : DEFAULT_OP_TIMEOUT
|
638
633
|
|
639
634
|
# Timeout on socket connect.
|
640
635
|
@connect_timeout = opts.delete(:connect_timeout) || 30
|
@@ -85,7 +85,8 @@ module Mongo
|
|
85
85
|
# @option opts [Float] :pool_timeout (5.0) When all of the connections a pool are checked out,
|
86
86
|
# this is the number of seconds to wait for a new connection to be released before throwing an exception.
|
87
87
|
# Note: this setting is relevant only for multi-threaded applications.
|
88
|
-
# @option opts [Float] :op_timeout (
|
88
|
+
# @option opts [Float] :op_timeout (DEFAULT_OP_TIMEOUT) The number of seconds to wait for a read operation to time out.
|
89
|
+
# Set to DEFAULT_OP_TIMEOUT (20) by default. A value of nil may be specified explicitly.
|
89
90
|
# @option opts [Float] :connect_timeout (30) The number of seconds to wait before timing out a
|
90
91
|
# connection attempt.
|
91
92
|
# @option opts [Boolean] :ssl (false) If true, create the connection to the server using SSL.
|
@@ -17,6 +17,7 @@ require 'shared/authentication/basic_auth_shared'
|
|
17
17
|
require 'shared/authentication/sasl_plain_shared'
|
18
18
|
require 'shared/authentication/bulk_api_auth_shared'
|
19
19
|
require 'shared/authentication/gssapi_shared'
|
20
|
+
require 'shared/authentication/scram_shared'
|
20
21
|
|
21
22
|
|
22
23
|
class AuthenticationTest < Test::Unit::TestCase
|
@@ -25,9 +26,11 @@ class AuthenticationTest < Test::Unit::TestCase
|
|
25
26
|
include SASLPlainTests
|
26
27
|
include BulkAPIAuthTests
|
27
28
|
include GSSAPITests
|
29
|
+
include SCRAMTests
|
28
30
|
|
29
31
|
def setup
|
30
32
|
@client = standard_connection
|
33
|
+
omit("auth not enabled on mongod") unless auth_enabled?(@client)
|
31
34
|
@admin = @client['admin']
|
32
35
|
@version = @client.server_version
|
33
36
|
@db = @client['ruby-test']
|
@@ -74,6 +74,27 @@ class ClientTest < Test::Unit::TestCase
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
def test_unix_sock
|
78
|
+
# There's an issue with unix sockets on JRuby with 32-bit libc
|
79
|
+
# https://jira.codehaus.org/browse/JRUBY-7183
|
80
|
+
return if RUBY_PLATFORM =~ /java/
|
81
|
+
begin
|
82
|
+
assert MongoClient.new("/tmp/mongodb-#{TEST_PORT}.sock")
|
83
|
+
rescue Errno::EAFNOSUPPORT
|
84
|
+
# System doesn't support UNIX sockets
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_initialize_with_auths
|
89
|
+
auth = { :username => TEST_USER,
|
90
|
+
:password => TEST_USER_PWD,
|
91
|
+
:db_name => TEST_DB,
|
92
|
+
:source => TEST_DB}
|
93
|
+
|
94
|
+
client = MongoClient.new(:auths => Set.new([auth]))
|
95
|
+
assert client['test']['test'].find.to_a
|
96
|
+
end
|
97
|
+
|
77
98
|
def test_connection_uri
|
78
99
|
con = MongoClient.from_uri("mongodb://#{host_port}")
|
79
100
|
assert_equal mongo_host, con.primary_pool.host
|
@@ -430,6 +451,18 @@ class ClientTest < Test::Unit::TestCase
|
|
430
451
|
assert !conn.active?
|
431
452
|
end
|
432
453
|
|
454
|
+
def test_operation_timeout_with_active
|
455
|
+
conn = standard_connection
|
456
|
+
assert conn.active?
|
457
|
+
assert_equal Mongo::MongoClient::DEFAULT_OP_TIMEOUT, conn.op_timeout
|
458
|
+
|
459
|
+
pool = conn.primary_pool
|
460
|
+
socket = pool.instance_variable_get(:@thread_ids_to_sockets)[Thread.current.object_id]
|
461
|
+
|
462
|
+
socket.stubs(:read).raises(Mongo::OperationTimeout)
|
463
|
+
assert_equal false, conn.active?
|
464
|
+
end
|
465
|
+
|
433
466
|
context "Saved authentications" do
|
434
467
|
setup do
|
435
468
|
@client = Mongo::MongoClient.new
|
@@ -18,6 +18,7 @@ require 'test_helper'
|
|
18
18
|
class CollectionTest < Test::Unit::TestCase
|
19
19
|
|
20
20
|
LIMITED_MAX_BSON_SIZE = 1024
|
21
|
+
LIMITED_BSON_SIZE_WITH_HEADROOM = LIMITED_MAX_BSON_SIZE + MongoClient::APPEND_HEADROOM
|
21
22
|
LIMITED_MAX_MESSAGE_SIZE = 3 * LIMITED_MAX_BSON_SIZE
|
22
23
|
LIMITED_TEST_HEADROOM = 50
|
23
24
|
LIMITED_VALID_VALUE_SIZE = LIMITED_MAX_BSON_SIZE - LIMITED_TEST_HEADROOM
|
@@ -29,6 +30,7 @@ class CollectionTest < Test::Unit::TestCase
|
|
29
30
|
@test = @db.collection("test")
|
30
31
|
@version = @client.server_version
|
31
32
|
@test.remove
|
33
|
+
@ismaster = @client['admin'].command(:isMaster => 1)
|
32
34
|
end
|
33
35
|
|
34
36
|
@@wv0 = Mongo::MongoClient::RELEASE_2_4_AND_BEFORE
|
@@ -669,21 +671,22 @@ class CollectionTest < Test::Unit::TestCase
|
|
669
671
|
|
670
672
|
def limited_collection
|
671
673
|
conn = standard_connection(:connect => false)
|
674
|
+
is_master = @ismaster.merge('maxBsonObjectSize' => LIMITED_MAX_BSON_SIZE,
|
675
|
+
'maxMessageSizeBytes' => LIMITED_MAX_BSON_SIZE)
|
672
676
|
admin_db = Object.new
|
673
|
-
admin_db.expects(:command).returns(
|
674
|
-
|
675
|
-
'ismaster' => 1,
|
676
|
-
'maxBsonObjectSize' => LIMITED_MAX_BSON_SIZE,
|
677
|
-
'maxMessageSizeBytes' => LIMITED_MAX_MESSAGE_SIZE
|
678
|
-
})
|
679
|
-
conn.expects(:[]).with('admin').returns(admin_db)
|
677
|
+
admin_db.expects(:command).returns(is_master)
|
678
|
+
conn.expects(:[]).with(TEST_DB).returns(admin_db)
|
680
679
|
conn.connect
|
681
680
|
return conn.db(TEST_DB)["test"]
|
682
681
|
end
|
683
682
|
|
684
683
|
def test_non_operation_failure_halts_insertion_with_continue_on_error
|
685
684
|
coll = limited_collection
|
686
|
-
|
685
|
+
if @client.wire_version_feature?(MongoClient::BATCH_COMMANDS)
|
686
|
+
coll.db.stubs(:command).raises(OperationTimeout).times(1)
|
687
|
+
else
|
688
|
+
coll.db.connection.stubs(:send_message_with_gle).raises(OperationTimeout).times(1)
|
689
|
+
end
|
687
690
|
docs = []
|
688
691
|
10.times do
|
689
692
|
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
@@ -738,6 +741,7 @@ class CollectionTest < Test::Unit::TestCase
|
|
738
741
|
end
|
739
742
|
|
740
743
|
def test_chunking_batch_insert_with_continue_on_error
|
744
|
+
coll = limited_collection
|
741
745
|
docs = []
|
742
746
|
4.times do
|
743
747
|
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
@@ -748,9 +752,9 @@ class CollectionTest < Test::Unit::TestCase
|
|
748
752
|
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
749
753
|
end
|
750
754
|
assert_raise OperationFailure do
|
751
|
-
|
755
|
+
coll.insert(docs, :continue_on_error => true)
|
752
756
|
end
|
753
|
-
assert
|
757
|
+
assert coll.count >= 6, "write commands need headroom for doc wrapping overhead - count:#{coll.count}"
|
754
758
|
end
|
755
759
|
|
756
760
|
def test_chunking_batch_insert_without_continue_on_error
|
@@ -779,49 +783,49 @@ class CollectionTest < Test::Unit::TestCase
|
|
779
783
|
|
780
784
|
def test_maximum_document_size
|
781
785
|
assert_raise InvalidDocument do
|
782
|
-
limited_collection.insert({'foo' => 'a' *
|
786
|
+
limited_collection.insert({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
|
783
787
|
end
|
784
788
|
end
|
785
789
|
|
786
790
|
def test_maximum_save_size
|
787
791
|
assert limited_collection.save({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
|
788
792
|
assert_raise InvalidDocument do
|
789
|
-
limited_collection.save({'foo' => 'a' *
|
793
|
+
limited_collection.save({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
|
790
794
|
end
|
791
795
|
end
|
792
796
|
|
793
797
|
def test_maximum_remove_size
|
794
798
|
assert limited_collection.remove({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
|
795
799
|
assert_raise InvalidDocument do
|
796
|
-
limited_collection.remove({'foo' => 'a' *
|
800
|
+
limited_collection.remove({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
|
797
801
|
end
|
798
802
|
end
|
799
803
|
|
800
804
|
def test_maximum_update_size
|
801
805
|
assert_raise InvalidDocument do
|
802
806
|
limited_collection.update(
|
803
|
-
{'foo' => 'a' *
|
807
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
|
804
808
|
{'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
805
809
|
)
|
806
810
|
end
|
807
811
|
|
808
812
|
assert_raise InvalidDocument do
|
809
813
|
limited_collection.update(
|
810
|
-
{'foo' => 'a' *
|
814
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
|
811
815
|
{'foo' => 'a' * LIMITED_MAX_BSON_SIZE}
|
812
816
|
)
|
813
817
|
end
|
814
818
|
|
815
819
|
assert_raise InvalidDocument do
|
816
820
|
limited_collection.update(
|
817
|
-
{'foo' => 'a' *
|
818
|
-
{'foo' => 'a' *
|
821
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
|
822
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM}
|
819
823
|
)
|
820
824
|
end
|
821
825
|
|
822
826
|
assert limited_collection.update(
|
823
|
-
{'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
|
824
|
-
{'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
827
|
+
{'foo' => 'a' * (LIMITED_VALID_VALUE_SIZE/2)},
|
828
|
+
{'foo' => 'a' * (LIMITED_VALID_VALUE_SIZE/2)}
|
825
829
|
)
|
826
830
|
end
|
827
831
|
|
@@ -1323,6 +1327,12 @@ class CollectionTest < Test::Unit::TestCase
|
|
1323
1327
|
assert_equal desired_results, results
|
1324
1328
|
end
|
1325
1329
|
|
1330
|
+
def test_aggregate_command_using_sym
|
1331
|
+
return unless @version > '2.1.1'
|
1332
|
+
cmd = BSON::OrderedHash[:aggregate, @test.name, :pipeline, [{'$match' => {:_id => true}}]]
|
1333
|
+
assert @db.command(cmd)
|
1334
|
+
end
|
1335
|
+
|
1326
1336
|
def test_aggregate_pipeline_multiple_operators
|
1327
1337
|
return unless @version > '2.1.1'
|
1328
1338
|
setup_aggregate_data
|