mongo 1.11.1 → 1.12.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|