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
@@ -315,10 +315,25 @@ class DBAPITest < Test::Unit::TestCase
|
|
315
315
|
cursor = @db.collections_info
|
316
316
|
rows = cursor.to_a
|
317
317
|
assert rows.length >= 1
|
318
|
-
|
318
|
+
if @client.server_version < '2.7.6'
|
319
|
+
row = rows.detect { |r| r['name'] == @coll_full_name }
|
320
|
+
else
|
321
|
+
row = rows.detect { |r| r['name'] == @coll.name }
|
322
|
+
end
|
319
323
|
assert_not_nil row
|
320
324
|
end
|
321
325
|
|
326
|
+
def test_collections_info_with_name
|
327
|
+
cursor = @db.collections_info(@coll.name)
|
328
|
+
info = cursor.to_a
|
329
|
+
assert_equal 1, info.length
|
330
|
+
if @client.server_version < '2.7.6'
|
331
|
+
assert_equal "#{@db.name}.#{@coll.name}", info.first['name']
|
332
|
+
else
|
333
|
+
assert_equal @coll.name, info.first['name']
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
322
337
|
def test_collection_options
|
323
338
|
@db.drop_collection('foobar')
|
324
339
|
@db.strict = true
|
@@ -43,19 +43,22 @@ class PoolTest < Test::Unit::TestCase
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def test_pool_affinity_max_size
|
46
|
+
client = standard_connection({:pool_size => 15, :pool_timeout => 5,
|
47
|
+
:op_timeout => nil})
|
48
|
+
coll = client[TEST_DB]['pool_test']
|
46
49
|
docs = []
|
47
50
|
8000.times {|x| docs << {:value => x}}
|
48
|
-
|
51
|
+
coll.insert(docs)
|
49
52
|
|
50
53
|
threads = []
|
51
54
|
threads << Thread.new do
|
52
|
-
|
55
|
+
coll.find({"value" => {"$lt" => 100}}).each {|e| e}
|
53
56
|
Thread.pass
|
54
57
|
sleep(0.125)
|
55
|
-
|
58
|
+
coll.find({"value" => {"$gt" => 100}}).each {|e| e}
|
56
59
|
end
|
57
60
|
threads << Thread.new do
|
58
|
-
|
61
|
+
coll.find({'$where' => "function() {for(i=0;i<500;i++) {this.value};}"}).each {|e| e}
|
59
62
|
end
|
60
63
|
threads.each(&:join)
|
61
64
|
end
|
@@ -83,7 +86,6 @@ class PoolTest < Test::Unit::TestCase
|
|
83
86
|
:username => TEST_USER,
|
84
87
|
:password => TEST_USER_PWD,
|
85
88
|
:source => TEST_DB,
|
86
|
-
:mechanism => Mongo::Authentication::DEFAULT_MECHANISM,
|
87
89
|
:extra => {}
|
88
90
|
}
|
89
91
|
client.auths << creds
|
@@ -111,7 +113,6 @@ class PoolTest < Test::Unit::TestCase
|
|
111
113
|
:username => TEST_USER,
|
112
114
|
:password => TEST_USER_PWD,
|
113
115
|
:source => TEST_DB,
|
114
|
-
:mechanism => Mongo::Authentication::DEFAULT_MECHANISM,
|
115
116
|
:extra => {}
|
116
117
|
}
|
117
118
|
client.auths << creds
|
data/test/functional/uri_test.rb
CHANGED
@@ -31,6 +31,30 @@ class URITest < Test::Unit::TestCase
|
|
31
31
|
assert_equal 27018, parser.nodes[0][1]
|
32
32
|
end
|
33
33
|
|
34
|
+
def test_unix_socket
|
35
|
+
parser = Mongo::URIParser.new('mongodb:///tmp/mongod.sock')
|
36
|
+
assert_equal 1, parser.nodes.length
|
37
|
+
assert_equal '/tmp/mongod.sock', parser.nodes[0][0]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_unix_socket_with_user
|
41
|
+
parser = Mongo::URIParser.new('mongodb://bob:secret.word@/tmp/mongod.sock')
|
42
|
+
assert_equal 1, parser.nodes.length
|
43
|
+
assert_equal '/tmp/mongod.sock', parser.nodes[0][0]
|
44
|
+
assert_equal "bob", parser.auths.first[:username]
|
45
|
+
assert_equal "secret.word", parser.auths.first[:password]
|
46
|
+
assert_equal 'admin', parser.auths.first[:source]
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_unix_socket_with_db
|
50
|
+
parser = Mongo::URIParser.new('mongodb://bob:secret.word@/tmp/mongod.sock/some_db')
|
51
|
+
assert_equal 1, parser.nodes.length
|
52
|
+
assert_equal '/tmp/mongod.sock', parser.nodes[0][0]
|
53
|
+
assert_equal 'bob', parser.auths.first[:username]
|
54
|
+
assert_equal 'secret.word', parser.auths.first[:password]
|
55
|
+
assert_equal 'some_db', parser.auths.first[:source]
|
56
|
+
end
|
57
|
+
|
34
58
|
def test_ipv6_format
|
35
59
|
parser = Mongo::URIParser.new('mongodb://[::1]:27018')
|
36
60
|
assert_equal 1, parser.nodes.length
|
@@ -89,6 +113,23 @@ class URITest < Test::Unit::TestCase
|
|
89
113
|
end
|
90
114
|
end
|
91
115
|
|
116
|
+
def test_username_without_password_unix_socket
|
117
|
+
parser = Mongo::URIParser.new('mongodb://bob:@/tmp/mongod.sock?authMechanism=GSSAPI')
|
118
|
+
assert_equal "bob", parser.auths.first[:username]
|
119
|
+
assert_equal nil, parser.auths.first[:password]
|
120
|
+
|
121
|
+
parser = Mongo::URIParser.new('mongodb://bob@/tmp/mongod.sock?authMechanism=GSSAPI')
|
122
|
+
assert_equal nil, parser.auths.first[:password]
|
123
|
+
|
124
|
+
assert_raise_error MongoArgumentError do
|
125
|
+
Mongo::URIParser.new('mongodb://bob:@/tmp/mongod.sock')
|
126
|
+
end
|
127
|
+
|
128
|
+
assert_raise_error MongoArgumentError do
|
129
|
+
Mongo::URIParser.new('mongodb://bob@/tmp/mongod.sock')
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
92
133
|
def test_complex_passwords
|
93
134
|
parser = Mongo::URIParser.new('mongodb://bob:secret.word@a.example.com:27018/test')
|
94
135
|
assert_equal "bob", parser.auths.first[:username]
|
@@ -215,6 +256,11 @@ class URITest < Test::Unit::TestCase
|
|
215
256
|
assert_equal :primary, parser.readpreference
|
216
257
|
end
|
217
258
|
|
259
|
+
def test_read_preference_option_primary_unix_sock
|
260
|
+
parser = Mongo::URIParser.new("mongodb:///tmp/mongod.sock?readPreference=primary")
|
261
|
+
assert_equal :primary, parser.readpreference
|
262
|
+
end
|
263
|
+
|
218
264
|
def test_read_preference_option_primary_preferred
|
219
265
|
parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=primaryPreferred")
|
220
266
|
assert_equal :primary_preferred, parser.readpreference
|
@@ -256,6 +302,34 @@ class URITest < Test::Unit::TestCase
|
|
256
302
|
assert_equal :nearest, parser.connection_options[:read]
|
257
303
|
end
|
258
304
|
|
305
|
+
def test_read_preference_tags
|
306
|
+
parser = Mongo::URIParser.new("mongodb://localhost:27017?replicaset=test&" +
|
307
|
+
"readPreferenceTags=dc:ny,rack:1")
|
308
|
+
expected_tags = [{ 'dc' => 'ny', 'rack' => '1' }]
|
309
|
+
assert_equal expected_tags, parser.connection_options[:tag_sets]
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_read_preference_tags_multiple
|
313
|
+
parser = Mongo::URIParser.new("mongodb://localhost:27017?replicaset=test&" +
|
314
|
+
"readPreferenceTags=dc:ny,rack:1&readPreferenceTags=dc:bos")
|
315
|
+
expected_tags = [{'dc' => 'ny', 'rack' => '1'}, { 'dc' => 'bos' }]
|
316
|
+
assert_equal expected_tags, parser.connection_options[:tag_sets]
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_invalid_read_preference_tags
|
320
|
+
assert_raise_error MongoArgumentError do
|
321
|
+
Mongo::URIParser.new("mongodb://localhost:27017?replicaset=test&" +
|
322
|
+
"readPreferenceTags=dc")
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_invalid_read_preference_tags_multiple
|
327
|
+
assert_raise_error MongoArgumentError do
|
328
|
+
Mongo::URIParser.new("mongodb://localhost:27017?replicaset=test&" +
|
329
|
+
"readPreferenceTags=dc:nyc&readPreferenceTags=dc")
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
259
333
|
def test_connection_when_sharded_with_no_options
|
260
334
|
parser = Mongo::URIParser.new("mongodb://localhost:27017,localhost:27018")
|
261
335
|
client = parser.connection({}, false, true)
|
@@ -288,11 +362,41 @@ class URITest < Test::Unit::TestCase
|
|
288
362
|
parser = Mongo::URIParser.new("mongodb://user@localhost?authMechanism=MONGODB-X509")
|
289
363
|
assert_equal 'MONGODB-X509', parser.authmechanism
|
290
364
|
|
291
|
-
assert_raise_error MongoArgumentError
|
365
|
+
assert_raise_error MongoArgumentError do
|
292
366
|
Mongo::URIParser.new("mongodb://user@localhost?authMechanism=INVALID")
|
293
367
|
end
|
294
368
|
end
|
295
369
|
|
370
|
+
def test_auth_mechanism_properties
|
371
|
+
uri = "mongodb://user@localhost?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME" +
|
372
|
+
":mongodb,CANONICALIZE_HOST_NAME:true"
|
373
|
+
parser = Mongo::URIParser.new(uri)
|
374
|
+
properties = {:service_name => "mongodb", :canonicalize_host_name => true}
|
375
|
+
assert_equal properties, parser.authmechanismproperties
|
376
|
+
assert_equal 'GSSAPI', parser.authmechanism
|
377
|
+
|
378
|
+
uri = "mongodb://user@localhost?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME" +
|
379
|
+
":MongoDB,CANONICALIZE_HOST_NAME:false,SERVICE_REALM:test"
|
380
|
+
parser = Mongo::URIParser.new(uri)
|
381
|
+
properties = {:service_name => "MongoDB", :canonicalize_host_name => false, :service_realm => "test"}
|
382
|
+
assert_equal properties, parser.authmechanismproperties
|
383
|
+
assert_equal 'GSSAPI', parser.authmechanism
|
384
|
+
end
|
385
|
+
|
386
|
+
def test_invalid_auth_mechanism_properties
|
387
|
+
uri = "mongodb://user@localhost?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME" +
|
388
|
+
":mongodb,INVALID_PROPERTY:true"
|
389
|
+
assert_raise_error MongoArgumentError do
|
390
|
+
parser = Mongo::URIParser.new(uri)
|
391
|
+
end
|
392
|
+
|
393
|
+
uri = "mongodb://user@localhost?authMechanism=PLAIN&authMechanismProperties="+
|
394
|
+
"SERVICE_NAME:mongodb"
|
395
|
+
assert_raise_error MongoArgumentError do
|
396
|
+
parser = Mongo::URIParser.new(uri)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
296
400
|
def test_sasl_plain
|
297
401
|
parser = Mongo::URIParser.new("mongodb://user:pass@localhost?authMechanism=PLAIN")
|
298
402
|
assert_equal 'PLAIN', parser.auths.first[:mechanism]
|
@@ -319,22 +423,22 @@ class URITest < Test::Unit::TestCase
|
|
319
423
|
|
320
424
|
|
321
425
|
uri = "mongodb://foo%2Fbar%40example.net@localhost?authMechanism=GSSAPI;" +
|
322
|
-
"
|
426
|
+
"authMechanismProperties=SERVICE_NAME:mongodb,SERVICE_REALM:example," +
|
427
|
+
"CANONICALIZE_HOST_NAME:true"
|
323
428
|
parser = Mongo::URIParser.new(uri)
|
324
429
|
assert_equal 'GSSAPI', parser.auths.first[:mechanism]
|
325
430
|
assert_equal 'foo/bar@example.net', parser.auths.first[:username]
|
326
|
-
assert_equal 'mongodb', parser.auths.first[:extra][:
|
431
|
+
assert_equal 'mongodb', parser.auths.first[:extra][:service_name]
|
327
432
|
assert_equal true, parser.auths.first[:extra][:canonicalize_host_name]
|
433
|
+
assert_equal 'example', parser.auths.first[:extra][:service_realm]
|
328
434
|
end
|
329
435
|
|
330
436
|
def test_opts_case_sensitivity
|
331
|
-
# options
|
332
|
-
uri = "mongodb://localhost?
|
333
|
-
"authSource=FooBar;" +
|
437
|
+
# options authsource, replicaset, w should be case sensitive
|
438
|
+
uri = "mongodb://localhost?authSource=FooBar;" +
|
334
439
|
"replicaSet=Foo;" +
|
335
440
|
"w=Majority"
|
336
441
|
parser = Mongo::URIParser.new(uri)
|
337
|
-
assert_equal 'MongoDB', parser.gssapiservicename
|
338
442
|
assert_equal 'FooBar', parser.authsource
|
339
443
|
assert_equal 'Foo', parser.replicaset
|
340
444
|
assert_equal :Majority, parser.w
|
data/test/helpers/test_unit.rb
CHANGED
@@ -61,7 +61,7 @@ class Test::Unit::TestCase
|
|
61
61
|
|
62
62
|
uri = "mongodb://#{TEST_USER}:#{TEST_USER_PWD}@" +
|
63
63
|
"#{cluster_instance.members_uri}"
|
64
|
-
uri += "?replicaset=#{@rs.repl_set_name}" if cluster_instance.replica_set?
|
64
|
+
uri += "?replicaset=#{@rs.repl_set_name}&sockettimeoutms=60000" if cluster_instance.replica_set?
|
65
65
|
instance_variable_set("@uri", uri)
|
66
66
|
end
|
67
67
|
|
@@ -147,6 +147,7 @@ class Test::Unit::TestCase
|
|
147
147
|
begin
|
148
148
|
step_down_command = BSON::OrderedHash.new
|
149
149
|
step_down_command[:replSetStepDown] = 30
|
150
|
+
step_down_command[:force] = true
|
150
151
|
member['admin'].command(step_down_command)
|
151
152
|
rescue Mongo::OperationFailure => e
|
152
153
|
retry unless (Time.now - start) > timeout
|
@@ -176,6 +177,13 @@ class Test::Unit::TestCase
|
|
176
177
|
Object.new
|
177
178
|
end
|
178
179
|
|
180
|
+
def mock_pool(tags={}, ping_time=15)
|
181
|
+
mock('pool').tap do |pool|
|
182
|
+
pool.stubs(:tags).returns(tags)
|
183
|
+
pool.stubs(:ping_time).returns(ping_time)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
179
187
|
def assert_raise_error(klass, message=nil)
|
180
188
|
begin
|
181
189
|
yield
|
@@ -247,11 +255,17 @@ class Test::Unit::TestCase
|
|
247
255
|
def with_default_journaling(client, &block)
|
248
256
|
authenticate_client(client)
|
249
257
|
cmd_line_args = client['admin'].command({ :getCmdLineOpts => 1 })['parsed']
|
250
|
-
unless client.server_version < "2.0" || cmd_line_args.include?('nojournal')
|
258
|
+
unless client.server_version < "2.0" || cmd_line_args.include?('nojournal') ||
|
259
|
+
using_heap1_storage_engine?(cmd_line_args)
|
251
260
|
yield
|
252
261
|
end
|
253
262
|
end
|
254
263
|
|
264
|
+
def using_heap1_storage_engine?(cmd_line_args)
|
265
|
+
cmd_line_args.include?('storage') &&
|
266
|
+
cmd_line_args['storage']['engine'] == 'heap1'
|
267
|
+
end
|
268
|
+
|
255
269
|
def with_no_replication(client, &block)
|
256
270
|
if client.class == MongoClient
|
257
271
|
yield
|
@@ -384,7 +398,7 @@ class Test::Unit::TestCase
|
|
384
398
|
client = Mongo::MongoClient.new(TEST_HOST, TEST_PORT)
|
385
399
|
db = client[TEST_DB]
|
386
400
|
begin
|
387
|
-
db.authenticate(TEST_USER, TEST_USER_PWD)
|
401
|
+
db.authenticate(TEST_USER, TEST_USER_PWD, nil, 'admin')
|
388
402
|
rescue Mongo::AuthenticationError => ex
|
389
403
|
roles = [ 'dbAdminAnyDatabase',
|
390
404
|
'userAdminAnyDatabase',
|
@@ -216,6 +216,24 @@ class ReplicaSetClientTest < Test::Unit::TestCase
|
|
216
216
|
end
|
217
217
|
end
|
218
218
|
|
219
|
+
def test_read_pref_primary_with_tags
|
220
|
+
parser = Mongo::URIParser.new("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}" +
|
221
|
+
"?replicaset=#{@rs.repl_set_name}&readPreference=primary&" +
|
222
|
+
"readPreferenceTags=dc:ny,rack:1")
|
223
|
+
assert_raise_error Mongo::MongoArgumentError do
|
224
|
+
parser.connection.read_pool
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_read_pref_with_tags
|
229
|
+
parser = Mongo::URIParser.new("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}" +
|
230
|
+
"?replicaset=#{@rs.repl_set_name}&" +
|
231
|
+
"readPreferenceTags=dc:ny,rack:1")
|
232
|
+
assert_raise_error Mongo::MongoArgumentError do
|
233
|
+
parser.connection.read_pool
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
219
237
|
def test_connect_with_connection_string
|
220
238
|
@client = MongoClient.from_uri("mongodb://#{@rs.replicas[0].host_port},#{@rs.replicas[1].host_port}?replicaset=#{@rs.repl_set_name}")
|
221
239
|
assert !@client.nil?
|
@@ -344,4 +362,17 @@ class ReplicaSetClientTest < Test::Unit::TestCase
|
|
344
362
|
)
|
345
363
|
assert_equal true, collection.find_one({ 'a' => id }, :read => :primary)['processed']
|
346
364
|
end
|
365
|
+
|
366
|
+
def test_op_timeout_option
|
367
|
+
client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :connect => false,
|
368
|
+
:op_timeout => nil)
|
369
|
+
assert_equal nil, client.op_timeout
|
370
|
+
|
371
|
+
client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :connect => false,
|
372
|
+
:op_timeout => 50)
|
373
|
+
assert_equal 50, client.op_timeout
|
374
|
+
|
375
|
+
client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :connect => false)
|
376
|
+
assert_equal Mongo::MongoClient::DEFAULT_OP_TIMEOUT, client.op_timeout
|
377
|
+
end
|
347
378
|
end
|
@@ -68,47 +68,64 @@ class ReplicaSetInsertTest < Test::Unit::TestCase
|
|
68
68
|
end
|
69
69
|
|
70
70
|
should "handle error with deferred write concern error - spec Merging Results" do
|
71
|
-
|
71
|
+
if @client.wire_version_feature?(MongoClient::MONGODB_2_8)
|
72
72
|
@coll.remove
|
73
73
|
@coll.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
74
74
|
bulk = @coll.initialize_ordered_bulk_op
|
75
75
|
bulk.insert({:a => 1})
|
76
76
|
bulk.find({:a => 2}).upsert.update({'$set' => {:a => 2}})
|
77
77
|
bulk.insert({:a => 1})
|
78
|
+
secondary = MongoClient.new(@rs.secondaries.first.host, @rs.secondaries.first.port)
|
79
|
+
cmd = BSON::OrderedHash[:configureFailPoint, 'rsSyncApplyStop', :mode, 'alwaysOn']
|
80
|
+
secondary['admin'].command(cmd)
|
78
81
|
ex = assert_raise BulkWriteError do
|
79
|
-
bulk.execute({:w =>
|
82
|
+
bulk.execute({:w => @rs.servers.size, :wtimeout => 1})
|
83
|
+
end
|
84
|
+
cmd = BSON::OrderedHash[:configureFailPoint, 'rsSyncApplyStop', :mode, 'off']
|
85
|
+
secondary['admin'].command(cmd)
|
86
|
+
else
|
87
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
88
|
+
@coll.remove
|
89
|
+
@coll.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
90
|
+
bulk = @coll.initialize_ordered_bulk_op
|
91
|
+
bulk.insert({:a => 1})
|
92
|
+
bulk.find({:a => 2}).upsert.update({'$set' => {:a => 2}})
|
93
|
+
bulk.insert({:a => 1})
|
94
|
+
ex = assert_raise BulkWriteError do
|
95
|
+
bulk.execute({:w => 5, :wtimeout => 1})
|
96
|
+
end
|
80
97
|
end
|
81
|
-
result = ex.result
|
82
|
-
assert_match_document(
|
83
|
-
{
|
84
|
-
"ok" => 1,
|
85
|
-
"n" => 2,
|
86
|
-
"writeErrors" => [
|
87
|
-
{
|
88
|
-
"index" => 2,
|
89
|
-
"code" => 11000,
|
90
|
-
"errmsg" => /duplicate key error/,
|
91
|
-
}
|
92
|
-
],
|
93
|
-
"writeConcernError" => [
|
94
|
-
{
|
95
|
-
"errmsg" => /waiting for replication timed out|timed out waiting for slaves|timeout/,
|
96
|
-
"code" => 64,
|
97
|
-
"errInfo" => {"wtimeout" => true},
|
98
|
-
"index" => 0
|
99
|
-
},
|
100
|
-
{
|
101
|
-
"errmsg" => /waiting for replication timed out|timed out waiting for slaves|timeout/,
|
102
|
-
"code" => 64,
|
103
|
-
"errInfo" => {"wtimeout" => true},
|
104
|
-
"index" => 1
|
105
|
-
}
|
106
|
-
],
|
107
|
-
"code" => 65,
|
108
|
-
"errmsg" => "batch item errors occurred",
|
109
|
-
"nInserted" => 1
|
110
|
-
}, result, "wire_version:#{wire_version}")
|
111
98
|
end
|
99
|
+
result = ex.result
|
100
|
+
assert_match_document(
|
101
|
+
{
|
102
|
+
"ok" => 1,
|
103
|
+
"n" => 2,
|
104
|
+
"writeErrors" => [
|
105
|
+
{
|
106
|
+
"index" => 2,
|
107
|
+
"code" => 11000,
|
108
|
+
"errmsg" => /duplicate key error/,
|
109
|
+
}
|
110
|
+
],
|
111
|
+
"writeConcernError" => [
|
112
|
+
{
|
113
|
+
"errmsg" => /waiting for replication timed out|timed out waiting for slaves|timeout/,
|
114
|
+
"code" => 64,
|
115
|
+
"errInfo" => {"wtimeout" => true},
|
116
|
+
"index" => 0
|
117
|
+
},
|
118
|
+
{
|
119
|
+
"errmsg" => /waiting for replication timed out|timed out waiting for slaves|timeout/,
|
120
|
+
"code" => 64,
|
121
|
+
"errInfo" => {"wtimeout" => true},
|
122
|
+
"index" => 1
|
123
|
+
}
|
124
|
+
],
|
125
|
+
"code" => 65,
|
126
|
+
"errmsg" => "batch item errors occurred",
|
127
|
+
"nInserted" => 1
|
128
|
+
}, result)
|
112
129
|
assert_equal 2, @coll.find.to_a.size
|
113
130
|
end
|
114
131
|
|
@@ -52,4 +52,54 @@ class ReplicaSetPinningTest < Test::Unit::TestCase
|
|
52
52
|
end
|
53
53
|
threads.each(&:join)
|
54
54
|
end
|
55
|
+
|
56
|
+
def test_aggregation_cursor_pinning
|
57
|
+
return unless @client.server_version >= '2.5.1'
|
58
|
+
@coll.drop
|
59
|
+
|
60
|
+
[10, 1000].each do |size|
|
61
|
+
@coll.drop
|
62
|
+
size.times {|i| @coll.insert({ :_id => i }) }
|
63
|
+
expected_sum = size.times.reduce(:+)
|
64
|
+
|
65
|
+
cursor = @coll.aggregate(
|
66
|
+
[{ :$project => {:_id => '$_id'}} ],
|
67
|
+
:cursor => { :batchSize => 1 }
|
68
|
+
)
|
69
|
+
|
70
|
+
assert_equal Mongo::Cursor, cursor.class
|
71
|
+
|
72
|
+
cursor_sum = cursor.reduce(0) do |sum, doc|
|
73
|
+
sum += doc['_id']
|
74
|
+
end
|
75
|
+
|
76
|
+
assert_equal expected_sum, cursor_sum
|
77
|
+
end
|
78
|
+
@coll.drop
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_parallel_scan_pinning
|
82
|
+
return unless @client.server_version >= '2.5.5'
|
83
|
+
@coll.drop
|
84
|
+
|
85
|
+
8000.times { |i| @coll.insert({ :_id => i }) }
|
86
|
+
|
87
|
+
lock = Mutex.new
|
88
|
+
doc_ids = Set.new
|
89
|
+
threads = []
|
90
|
+
cursors = @coll.parallel_scan(3)
|
91
|
+
cursors.each_with_index do |cursor, i|
|
92
|
+
threads << Thread.new do
|
93
|
+
docs = cursor.to_a
|
94
|
+
lock.synchronize do
|
95
|
+
docs.each do |doc|
|
96
|
+
doc_ids << doc['_id']
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
threads.each(&:join)
|
102
|
+
assert_equal 8000, doc_ids.count
|
103
|
+
@coll.drop
|
104
|
+
end
|
55
105
|
end
|