mongo 1.10.0.rc0 → 1.10.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/VERSION +1 -1
  5. data/lib/mongo/bulk_write_collection_view.rb +31 -3
  6. data/lib/mongo/collection.rb +69 -25
  7. data/lib/mongo/collection_writer.rb +3 -2
  8. data/lib/mongo/connection/node.rb +5 -0
  9. data/lib/mongo/cursor.rb +4 -1
  10. data/lib/mongo/db.rb +23 -41
  11. data/lib/mongo/functional.rb +2 -0
  12. data/lib/mongo/functional/authentication.rb +18 -3
  13. data/lib/mongo/functional/sasl_java.rb +48 -0
  14. data/lib/mongo/functional/uri_parser.rb +62 -50
  15. data/lib/mongo/mongo_client.rb +24 -9
  16. data/lib/mongo/mongo_replica_set_client.rb +16 -5
  17. data/lib/mongo/networking.rb +3 -3
  18. data/lib/mongo/utils/conversions.rb +2 -1
  19. data/test/functional/authentication_test.rb +6 -1
  20. data/test/functional/bulk_api_stress_test.rb +133 -0
  21. data/test/functional/bulk_write_collection_view_test.rb +573 -226
  22. data/test/functional/client_test.rb +3 -1
  23. data/test/functional/collection_test.rb +336 -17
  24. data/test/functional/conversions_test.rb +32 -0
  25. data/test/functional/cursor_test.rb +3 -3
  26. data/test/functional/db_api_test.rb +2 -2
  27. data/test/functional/db_test.rb +24 -0
  28. data/test/functional/uri_test.rb +49 -32
  29. data/test/helpers/test_unit.rb +8 -0
  30. data/test/replica_set/authentication_test.rb +5 -1
  31. data/test/replica_set/client_test.rb +5 -4
  32. data/test/replica_set/max_values_test.rb +6 -0
  33. data/test/shared/authentication/basic_auth_shared.rb +101 -30
  34. data/test/shared/authentication/bulk_api_auth_shared.rb +259 -0
  35. data/test/shared/authentication/gssapi_shared.rb +164 -0
  36. data/test/shared/ssl_shared.rb +49 -27
  37. data/test/unit/client_test.rb +4 -2
  38. data/test/unit/connection_test.rb +4 -2
  39. data/test/unit/cursor_test.rb +12 -0
  40. data/test/unit/db_test.rb +6 -0
  41. metadata +27 -20
  42. metadata.gz.sig +0 -0
@@ -0,0 +1,133 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License")
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'test_helper'
16
+
17
+ class BulkApiStressTest < Test::Unit::TestCase
18
+
19
+ # Generate a large string of 'size' MB (estimated
20
+ # by a string of 'size' * 1024 * 1024 characters).
21
+ def generate_large_string(size)
22
+ s = "a" * (size * 1024 * 1024)
23
+ end
24
+
25
+ def setup
26
+ @client = standard_connection
27
+ @db = @client[TEST_DB]
28
+ @coll = @db["bulk-api-stress-tests"]
29
+ @coll.remove
30
+ end
31
+
32
+ def test_ordered_batch_large_inserts
33
+ bulk = @coll.initialize_ordered_bulk_op
34
+ s = generate_large_string(4)
35
+
36
+ for i in 0..5
37
+ bulk.insert({:_id => i, :msg => s})
38
+ end
39
+ bulk.insert({:_id => 3}) # error
40
+ bulk.insert({:_id => 100})
41
+
42
+ ex = assert_raise BulkWriteError do
43
+ bulk.execute
44
+ end
45
+
46
+ error_details = ex.result
47
+ assert_equal 6, error_details["nInserted"]
48
+ assert_equal 1, error_details["writeErrors"].length
49
+ error = error_details["writeErrors"][0]
50
+ assert_equal 11000, error["code"] # duplicate key error
51
+ assert error["errmsg"].kind_of? String
52
+ assert_equal 6, error["index"]
53
+ assert_equal 6, @coll.count()
54
+ end
55
+
56
+ def test_unordered_batch_large_inserts
57
+ bulk = @coll.initialize_unordered_bulk_op
58
+ s = generate_large_string(4)
59
+
60
+ for i in 0..5
61
+ bulk.insert({:_id => i, :msg => s})
62
+ end
63
+ bulk.insert({:_id => 3}) # error
64
+ bulk.insert({:_id => 100})
65
+
66
+ ex = assert_raise BulkWriteError do
67
+ bulk.execute
68
+ end
69
+
70
+ error_details = ex.result
71
+ assert_equal 7, error_details["nInserted"]
72
+ assert_equal 1, error_details["writeErrors"].length
73
+ error = error_details["writeErrors"][0]
74
+ assert_equal 11000, error["code"] # duplicate key error
75
+ assert error["errmsg"].kind_of? String
76
+ assert_equal 6, error["index"]
77
+ assert_equal 7, @coll.count()
78
+ end
79
+
80
+ def test_large_single_insert
81
+ bulk = @coll.initialize_unordered_bulk_op
82
+ s = generate_large_string(17)
83
+ bulk.insert({:a => s})
84
+ # RUBY-730:
85
+ # ex = assert_raise BulkWriteError do
86
+ # bulk.execute
87
+ # end
88
+ end
89
+
90
+ def test_ordered_batch_large_batch
91
+ bulk = @coll.initialize_ordered_bulk_op
92
+
93
+ bulk.insert({:_id => 1600})
94
+ for i in 0..2000
95
+ bulk.insert({:_id => i})
96
+ end
97
+
98
+ ex = assert_raise BulkWriteError do
99
+ bulk.execute
100
+ end
101
+
102
+ error_details = ex.result
103
+ assert_equal 1601, error_details["nInserted"]
104
+ assert_equal 1, error_details["writeErrors"].length
105
+ error = error_details["writeErrors"][0]
106
+ assert_equal 11000, error["code"] # duplicate key error
107
+ assert error["errmsg"].kind_of? String
108
+ assert_equal 1601, error["index"]
109
+ assert_equal 1601, @coll.count()
110
+ end
111
+
112
+ def test_unordered_batch_large_batch
113
+ bulk = @coll.initialize_unordered_bulk_op
114
+
115
+ bulk.insert({:_id => 1600})
116
+ for i in 0..2000
117
+ bulk.insert({:_id => i})
118
+ end
119
+
120
+ ex = assert_raise BulkWriteError do
121
+ bulk.execute
122
+ end
123
+
124
+ error_details = ex.result
125
+ assert_equal 2001, error_details["nInserted"]
126
+ assert_equal 1, error_details["writeErrors"].length
127
+ error = error_details["writeErrors"][0]
128
+ assert_equal 11000, error["code"] # duplicate key error
129
+ assert error["errmsg"].kind_of? String
130
+ assert_equal 1601, error["index"]
131
+ assert_equal 2001, @coll.count()
132
+ end
133
+ end
@@ -21,7 +21,7 @@ module Mongo
21
21
  end
22
22
 
23
23
  class BulkWriteCollectionView
24
- public :update_doc?, :replace_doc?, :merge_result
24
+ public :update_doc?, :replace_doc?, :nil_tally, :merge_result
25
25
 
26
26
  # for reference and future server direction
27
27
  def generate_batch_commands(groups, write_concern)
@@ -184,105 +184,422 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
184
184
  bulk.insert({:x => 4})
185
185
  end
186
186
 
187
+ def nil_tally_responses(responses, key)
188
+ result = {}
189
+ responses.each do |response|
190
+ @bulk.nil_tally(result, key, response[key])
191
+ end
192
+ result
193
+ end
194
+
187
195
  context "Bulk API CollectionView" do
188
196
  setup do
189
197
  default_setup
190
198
  end
191
199
 
200
+ # ----- INSERT -----
201
+
202
+ should "set :insert, :documents, terminate and return view for #insert" do
203
+ with_write_commands_and_operations(@db.connection) do |wire_version|
204
+ @collection.remove
205
+ document = {:a => 5}
206
+ result = @bulk.insert(document)
207
+ assert_is_bulk_write_collection_view(result)
208
+ assert_bulk_op_pushed [:insert, {:d => document}], @bulk
209
+ result = @bulk.execute
210
+ assert_match_document(
211
+ {
212
+ "ok" => 1,
213
+ "n" => 1,
214
+ "nInserted" => 1
215
+ }, result, "wire_version:#{wire_version}")
216
+ assert_equal 1, @collection.count
217
+ end
218
+ end
219
+
220
+ should "error out on $-prefixed keys with #insert" do
221
+ assert_raise BulkWriteError do
222
+ @bulk.insert({ "$key" => 1 })
223
+ @bulk.execute
224
+ end
225
+ end
226
+
227
+ should "attempt to run #insert with find() and succeed, ignoring find()" do
228
+ @bulk.find({}).insert({})
229
+ @bulk.execute
230
+ end
231
+
232
+ # ----- FIND -----
233
+
192
234
  should "set :q and return view for #find" do
193
235
  result = @bulk.find(@q)
194
236
  assert_is_bulk_write_collection_view(result)
195
237
  assert_equal @q, @bulk.op_args[:q]
238
+ @bulk.find({})
239
+ assert_equal({}, @bulk.op_args[:q])
240
+ @bulk.find(:a => 1)
241
+ assert_equal({:a => 1}, @bulk.op_args[:q])
196
242
  end
197
243
 
244
+ should "raise an exception for empty #find" do
245
+ assert_raise MongoArgumentError do
246
+ @bulk.find({})
247
+ @bulk.execute
248
+ end
249
+ end
250
+
251
+ # ----- UPDATE -----
252
+
198
253
  should "set :upsert for #upsert" do
199
254
  result = @bulk.find(@q).upsert
200
255
  assert_is_bulk_write_collection_view(result)
201
256
  assert_true result.op_args[:upsert]
202
257
  end
203
258
 
259
+ should "check arg for update, set :update, :u, :multi, terminate and return view for #update" do
260
+ with_write_commands_and_operations(@db.connection) do |wire_version|
261
+ @collection.remove
262
+ @collection.insert({:a => 1, :b => 1})
263
+ @collection.insert({:a => 2, :b => 1})
264
+ @collection.insert({:a => 2, :b => 1})
265
+ bulk = @collection.initialize_ordered_bulk_op
266
+
267
+ u = {"$inc" => {:b => 1}}
268
+ q = {:a => 2}
269
+
270
+ assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
271
+ bulk.update(u)
272
+ end
273
+ assert_raise_error(MongoArgumentError, "document must start with an operator") do
274
+ bulk.find(q).update(q)
275
+ end
276
+
277
+ result = bulk.find({:a => 2}).update(u)
278
+ assert_is_bulk_write_collection_view(result)
279
+ assert_bulk_op_pushed [:update, {:q => q, :u => u, :multi => true}], bulk
280
+
281
+ result = bulk.execute
282
+ assert_match_document(
283
+ {
284
+ "ok" => 1,
285
+ "n" => 2,
286
+ "nMatched" => 2,
287
+ "nModified" => batch_commands?(wire_version) ? 2 : nil,
288
+ }, result, "wire_version:#{wire_version}")
289
+ assert_equal 1, @collection.find({:b => 1}).count
290
+ end
291
+ end
292
+
293
+ # ----- UPDATE_ONE -----
294
+
204
295
  should "check arg for update, set :update, :u, :multi, terminate and return view for #update_one" do
205
- assert_raise MongoArgumentError do
206
- @bulk.find(@q).update_one(@r)
296
+ with_write_commands_and_operations(@db.connection) do |wire_version|
297
+ @collection.remove
298
+ @collection.insert({:a => 1})
299
+ @collection.insert({:a => 1, :b => 2})
300
+ bulk = @collection.initialize_ordered_bulk_op
301
+
302
+ assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
303
+ bulk.update_one(@u)
304
+ end
305
+ assert_raise_error(MongoArgumentError, "document must start with an operator") do
306
+ bulk.find(@q).update_one(@r)
307
+ end
308
+ result = bulk.find(@q).update_one(@u)
309
+ assert_is_bulk_write_collection_view(result)
310
+ assert_bulk_op_pushed [:update, {:q => @q, :u => @u, :multi => false}], bulk
311
+ result = bulk.execute
312
+ assert_match_document(
313
+ {
314
+ "ok" => 1,
315
+ "n" => 1,
316
+ "nMatched" => 1,
317
+ "nModified" => batch_commands?(wire_version) ? 1 : nil,
318
+ }, result, "wire_version:#{wire_version}")
319
+ assert_equal 2, @collection.count
207
320
  end
208
- result = @bulk.find(@q).update_one(@u)
209
- assert_is_bulk_write_collection_view(result)
210
- assert_bulk_op_pushed [:update, {:q => @q, :u => @u, :multi => false}], @bulk
211
321
  end
212
322
 
213
- should "check arg for update, set :update, :u, :multi, terminate and return view for #update" do
214
- assert_raise MongoArgumentError do
215
- @bulk.find(@q).replace_one(@u)
323
+ should "error-out in server when $-prefixed key is passed to #update_one" do
324
+ assert_raise BulkWriteError do
325
+ oh = BSON::OrderedHash.new
326
+ oh["$key"] = 1
327
+ oh[:a] = 1
328
+ @bulk.find(@q).update(oh)
329
+ @bulk.execute
330
+ end
331
+ end
332
+
333
+ should "error-out in driver when first field passed to #update_one is not operator" do
334
+ assert_raise_error(MongoArgumentError, "document must start with an operator") do
335
+ oh = BSON::OrderedHash.new
336
+ oh[:a] = 1
337
+ oh["$key"] = 1
338
+ @bulk.find(@q).update(oh)
216
339
  end
217
- result = @bulk.find(@q).update(@u)
218
- assert_is_bulk_write_collection_view(result)
219
- assert_bulk_op_pushed [:update, {:q => @q, :u => @u, :multi => true}], @bulk
220
340
  end
221
341
 
342
+ # ----- REPLACE_ONE -----
343
+
222
344
  should "check arg for replacement, set :update, :u, :multi, terminate and return view for #replace_one" do
223
- assert_raise MongoArgumentError do
224
- @bulk.find(@q).replace_one(@u)
345
+ with_write_commands_and_operations(@db.connection) do |wire_version|
346
+ @collection.remove
347
+ @collection.insert({:a => 1})
348
+ @collection.insert({:a => 1})
349
+ bulk = @collection.initialize_ordered_bulk_op
350
+ q = {:a => 1}
351
+ r = {:a => 2}
352
+
353
+ assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
354
+ bulk.replace_one(q)
355
+ end
356
+ assert_raise_error(MongoArgumentError, "document must not contain any operators") do
357
+ bulk.find(q).replace_one(@u)
358
+ end
359
+
360
+ result = bulk.find(q).replace_one(r)
361
+ assert_is_bulk_write_collection_view(result)
362
+ assert_bulk_op_pushed [:update, {:q => q, :u => r, :multi => false}], bulk
363
+
364
+ result = bulk.execute
365
+ assert_match_document(
366
+ {
367
+ "ok" => 1,
368
+ "n" => 1,
369
+ "nMatched" => 1,
370
+ "nModified" => batch_commands?(wire_version) ? 1 : nil,
371
+ }, result, "wire_version:#{wire_version}")
372
+ assert_equal 1, @collection.find(q).count
225
373
  end
226
- result = @bulk.find(@q).replace_one(@r)
227
- assert_is_bulk_write_collection_view(result)
228
- assert_bulk_op_pushed [:update, {:q => @q, :u => @r, :multi => false}], @bulk
229
374
  end
230
375
 
231
- should "set :remove, :q, :limit, terminate and return view for #remove_one" do
232
- result = @bulk.find(@q).remove_one
233
- assert_is_bulk_write_collection_view(result)
234
- assert_bulk_op_pushed [:delete, {:q => @q, :limit => 1}], @bulk
376
+ # ----- REMOVE -----
235
377
 
378
+ should "remove all documents when empty selector is passed to #remove" do
379
+ with_write_commands_and_operations(@db.connection) do |wire_version|
380
+ @collection.insert({:a => 1})
381
+ @collection.insert({:a => 2})
382
+ @bulk.find({}).remove
383
+ result = @bulk.execute
384
+ assert_equal 0, @collection.count
385
+ end
386
+ end
387
+
388
+ should "#remove only documents that match selector" do
389
+ with_write_commands_and_operations(@db.connection) do |wire_version|
390
+ @collection.remove
391
+ @collection.insert({:a => 1})
392
+ @collection.insert({:a => 2})
393
+ @bulk.find({:a => 1}).remove
394
+ result = @bulk.execute
395
+ assert_equal 1, @collection.count
396
+ # should fail if we re-execute
397
+ assert_raise_error(MongoArgumentError, "batch is empty") do
398
+ @bulk.execute
399
+ end
400
+ end
236
401
  end
237
402
 
238
403
  should "set :remove, :q, :limit, terminate and return view for #remove" do
404
+ assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
405
+ @bulk.remove
406
+ end
239
407
  result = @bulk.find(@q).remove
240
408
  assert_is_bulk_write_collection_view(result)
241
409
  assert_bulk_op_pushed [:delete, {:q => @q, :limit => 0}], @bulk
242
410
  end
243
411
 
244
- should "set :insert, :documents, terminate and return view for #insert" do
245
- document = {:a => 5}
246
- result = @bulk.insert(document)
412
+ # ----- REMOVE_ONE -----
413
+
414
+ should "set :remove, :q, :limit, terminate and return view for #remove_one" do
415
+ assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
416
+ @bulk.remove_one
417
+ end
418
+ result = @bulk.find(@q).remove_one
247
419
  assert_is_bulk_write_collection_view(result)
248
- assert_bulk_op_pushed [:insert, {:d => document}], @bulk
420
+ assert_bulk_op_pushed [:delete, {:q => @q, :limit => 1}], @bulk
421
+ end
422
+
423
+ should "remove only one of several matching documents for #remove_one" do
424
+ with_write_commands_and_operations(@db.connection) do |wire_version|
425
+ @collection.remove
426
+ @collection.insert({:a => 1, :b => 1})
427
+ @collection.insert({:a => 1, :b => 2})
428
+ @bulk.find({:a => 1}).remove_one
429
+ result = @bulk.execute
430
+ assert_match_document(
431
+ {
432
+ "ok" => 1,
433
+ "n" => 1,
434
+ "nRemoved" => 1,
435
+ "nModified" => nil,
436
+ }, result, "wire_version:#{wire_version}")
437
+ assert_equal 1, @collection.count
438
+ end
439
+ end
440
+
441
+ # ----- UPSERT-UPDATE -----
442
+
443
+ should "handle single upsert - spec Handling upserts" do # chose array always for upserted value
444
+ with_write_commands_and_operations(@db.connection) do |wire_version|
445
+ @collection.remove
446
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
447
+ bulk = @collection.initialize_ordered_bulk_op
448
+
449
+ assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
450
+ @bulk.upsert.update({"$set" => {:a => 1}})
451
+ end
452
+
453
+ bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
454
+ result = bulk.execute
455
+ assert_match_document(
456
+ {
457
+ "ok" => 1,
458
+ "n" => 1,
459
+ "nMatched" => 0,
460
+ "nUpserted" => 1,
461
+ "nModified" => batch_commands?(wire_version) ? 0 : nil,
462
+ "upserted" => [
463
+ {"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 0}
464
+ ]
465
+ }, result, "wire_version:#{wire_version}")
466
+ end
249
467
  end
250
468
 
251
- should "provide spec Operations Possible On Bulk Instance" do
252
- @bulk = @collection.initialize_ordered_bulk_op
469
+ should "run #upsert.update without affecting non-upsert updates" do
470
+ with_write_commands_and_operations(@db.connection) do |wire_version|
471
+ @collection.remove
253
472
 
254
- # Update one document matching the selector
255
- @bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
473
+ bulk = @collection.initialize_unordered_bulk_op
474
+ bulk.find({:a => 1}).update({"$set" => {:x => 1}})
475
+ bulk.find({:a => 2}).upsert.update({"$set" => {:x => 2}})
476
+ result = bulk.execute
477
+ assert_match_document(
478
+ {
479
+ "ok" => 1,
480
+ "n" => 1,
481
+ "nMatched" => 0,
482
+ "nModified" => batch_commands?(wire_version) ? 0 : nil,
483
+ "nUpserted" => 1,
484
+ "upserted" => [
485
+ {"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
486
+ ]
487
+ }, result, "wire_version:#{wire_version}")
256
488
 
257
- # Update all documents matching the selector
258
- @bulk.find({:a => 2}).update({"$inc" => {:x => 2}})
489
+ # Repeat the batch and nMatched = 1, nUpserted = 0
490
+ bulk2 = @collection.initialize_unordered_bulk_op
491
+ bulk2.find({:a => 1}).update({"$set" => {:x => 1}})
492
+ bulk2.find({:a => 2}).upsert.update({"$set" => {:x => 2}})
493
+ result2 = bulk2.execute
494
+ assert_match_document(
495
+ {
496
+ "ok" => 1,
497
+ "n" => 1,
498
+ "nMatched" => 1,
499
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
500
+ }, result2, "wire_version:#{wire_version}")
501
+ end
502
+ end
259
503
 
260
- # Replace entire document (update with whole doc replace)
261
- @bulk.find({:a => 3}).replace_one({:x => 3})
504
+ # ----- UPSERT-UPDATE_ONE -----
262
505
 
263
- # Update one document matching the selector or upsert
264
- @bulk.find({:a => 1}).upsert.update_one({"$inc" => {:x => 1}})
506
+ should "#upsert a document without affecting non-upsert update_ones" do
507
+ with_write_commands_and_operations(@db.connection) do |wire_version|
508
+ @collection.remove
509
+ bulk = @collection.initialize_unordered_bulk_op
265
510
 
266
- # Update all documents matching the selector or upsert
267
- @bulk.find({:a => 2}).upsert.update({"$inc" => {:x => 2}})
511
+ bulk.find({:a => 1}).update_one({"$set" => {:x => 1}})
512
+ bulk.find({:a => 2}).upsert.update_one({"$set" => {:x => 2}})
513
+ result = bulk.execute
514
+ assert_match_document(
515
+ {
516
+ "ok" => 1,
517
+ "n" => 1,
518
+ "nMatched" => 0,
519
+ "nUpserted" => 1,
520
+ "nModified" => batch_commands?(wire_version) ? 0 : nil,
521
+ "upserted" => [
522
+ {"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
523
+ ]
524
+ }, result, "wire_version:#{wire_version}")
525
+ end
526
+ end
268
527
 
269
- # Replaces a single document matching the selector or upsert
270
- @bulk.find({:a => 3}).upsert.replace_one({:x => 3})
528
+ should "only update one matching document with #upsert-update_one" do
529
+ with_write_commands_and_operations(@db.connection) do |wire_version|
530
+ @collection.remove
531
+ @collection.insert({:a => 1})
532
+ @collection.insert({:a => 1})
271
533
 
272
- # Remove a single document matching the selector
273
- @bulk.find({:a => 4}).remove_one
534
+ bulk = @collection.initialize_unordered_bulk_op
535
+ bulk.find({:a => 1}).update_one({"$set" => {:x => 1}})
536
+ result = bulk.execute
537
+ assert_match_document(
538
+ {
539
+ "ok" => 1,
540
+ "n" => 1,
541
+ "nMatched" => 1,
542
+ "nModified" => batch_commands?(wire_version) ? 1 : nil,
543
+ }, result, "wire_version:#{wire_version}")
544
+ end
545
+ end
274
546
 
275
- # Remove all documents matching the selector
276
- @bulk.find({:a => 5}).remove
547
+ # ----- UPSERT-REPLACE_ONE -----
277
548
 
278
- # Insert a document
279
- @bulk.insert({:x => 4})
549
+ should "not affect non-upsert replace_ones in same batch as #upsert-replace_one" do
550
+ with_write_commands_and_operations(@db.connection) do |wire_version|
551
+ @collection.remove
552
+ bulk = @collection.initialize_unordered_bulk_op
553
+ bulk.find({:a => 1}).replace_one({:x => 1})
554
+ bulk.find({:a => 2}).upsert.replace_one({:x => 2})
555
+ result = bulk.execute
556
+ assert_match_document(
557
+ {
558
+ "ok" => 1,
559
+ "n" => 1,
560
+ "nMatched" => 0,
561
+ "nUpserted" => 1,
562
+ "nModified" => batch_commands?(wire_version) ? 0 : nil,
563
+ "upserted" => [
564
+ {"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
565
+ ]
566
+ }, result, "wire_version:#{wire_version}")
567
+ assert_equal 1, @collection.count
568
+ end
569
+ end
280
570
 
281
- # Execute the bulk operation, with an optional writeConcern overwriting the default w:1
282
- write_concern = {:w => 1} #{:w => 1. :j => 1} #nojournal for tests
283
- #@bulk.execute(write_concern)
571
+ should "only replace one matching document with #upsert-replace_one" do
572
+ with_write_commands_and_operations(@db.connection) do |wire_version|
573
+ @collection.remove
574
+ @collection.insert({:a => 1})
575
+ @collection.insert({:a => 1})
576
+ bulk = @collection.initialize_unordered_bulk_op
577
+ bulk.find({:a => 1}).replace_one({:x => 1})
578
+ bulk.find({:a => 2}).upsert.replace_one({:x => 2})
579
+ result = bulk.execute
580
+ assert_match_document(
581
+ {
582
+ "ok" => 1,
583
+ "n" => 2,
584
+ "nMatched" => 1,
585
+ "nUpserted" => 1,
586
+ "nModified" => batch_commands?(wire_version) ? 1 : nil,
587
+ "upserted" => [
588
+ {"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
589
+ ]
590
+ }, result, "wire_version:#{wire_version}")
591
+ assert_equal 3, @collection.count
592
+ end
284
593
  end
285
594
 
595
+ should "tally given all numbers or return nil for #nil_tally" do
596
+ assert_equal({"nM" => 6}, nil_tally_responses([{"nM" => 1}, {"nM" => 2}, {"nM" => 3}], "nM"))
597
+ assert_equal({"nM" => nil}, nil_tally_responses([{"nM" => 1}, { }, {"nM" => 3}], "nM"))
598
+ assert_equal({"nM" => nil}, nil_tally_responses([{"nM" => 1}, {"nM" => nil}, {"nM" => 3}], "nM"))
599
+ end
600
+
601
+ # ----- MIXED OPS, ORDERED -----
602
+
286
603
  should "execute, return result and reset @ops for #execute" do
287
604
  with_write_commands_and_operations(@db.connection) do |wire_version|
288
605
  @collection.remove
@@ -309,7 +626,7 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
309
626
  "nInserted" => 6,
310
627
  "nMatched" => 5,
311
628
  "nUpserted" => 1,
312
- "nModified" => 5,
629
+ "nModified" => batch_commands?(wire_version) ? 5 : nil,
313
630
  "nRemoved" => 2,
314
631
  "upserted" => [
315
632
  {
@@ -318,31 +635,45 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
318
635
  }
319
636
  ]
320
637
  }, result, "wire_version:#{wire_version}")
638
+ assert_equal(batch_commands?(wire_version), result.has_key?("nModified"), "wire_version:#{wire_version}")
321
639
  assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
322
640
  assert_equal [{"a"=>1, "x"=>2}, {"a"=>2, "x"=>4}, {"x"=>3}, {"x"=>3}, {"x"=>4}], sort_docs(@collection.find.to_a.collect { |doc| doc.delete("_id"); doc })
323
641
  end
324
642
  end
325
643
 
326
- should "run ordered big example with w 0" do
644
+ should "run spec Ordered Bulk Operations" do
327
645
  with_write_commands_and_operations(@db.connection) do |wire_version|
328
- @collection.remove
329
- big_example(@bulk)
330
- write_concern = {:w => 0}
331
- result = @bulk.execute(write_concern)
332
- assert_equal(true, result, "wire_version:#{wire_version}")
333
- assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
334
- assert_equal [{"a"=>1, "x"=>2}, {"a"=>2, "x"=>4}, {"x"=>3}, {"x"=>3}, {"x"=>4}], sort_docs(@collection.find.to_a.collect { |doc| doc.delete("_id"); doc })
646
+ @bulk.insert({:a => 1})
647
+ @bulk.insert({:a => 2})
648
+ @bulk.insert({:a => 3})
649
+ @bulk.find({:a => 2}).upsert.update({'$set' => {:a => 4}})
650
+ @bulk.find({:a => 1}).remove_one
651
+ @bulk.insert({:a => 5})
652
+ result = @bulk.execute({:w => 1})
653
+ assert_match_document(
654
+ {
655
+ "ok" => 1,
656
+ "n" => 6,
657
+ "nInserted" => 4,
658
+ "nMatched" => 1,
659
+ "nModified" => batch_commands?(wire_version) ? 1 : nil,
660
+ "nRemoved" => 1,
661
+ }, result, "wire_version:#{wire_version}")
335
662
  end
336
663
  end
337
664
 
665
+ # ----- MIXED OPS, UNORDERED -----
666
+
338
667
  should "run unordered big example" do
339
668
  with_write_commands_and_operations(@db.connection) do |wire_version|
340
669
  @collection.remove
341
670
  @bulk = @collection.initialize_unordered_bulk_op
342
671
  big_example(@bulk)
343
672
  write_concern = {:w => 1} #{:w => 1. :j => 1} #nojournal for tests
344
- result = @bulk.execute(write_concern) # unordered varies, don't use assert_match_document
673
+ result = @bulk.execute(write_concern)
674
+ assert_equal(6, result["nInserted"])
345
675
  assert_true(result["n"] > 0, "wire_version:#{wire_version}")
676
+ assert_equal(batch_commands?(wire_version), result.has_key?("nModified"), "wire_version:#{wire_version}")
346
677
  assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
347
678
  end
348
679
  end
@@ -353,29 +684,73 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
353
684
  @bulk = @collection.initialize_unordered_bulk_op
354
685
  big_example(@bulk)
355
686
  write_concern = {:w => 0}
356
- result = @bulk.execute(write_concern) # unordered varies, don't use assert_match_document
687
+ result = @bulk.execute(write_concern)
357
688
  assert_equal(true, result, "wire_version:#{wire_version}")
358
689
  assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
359
690
  end
360
691
  end
361
692
 
362
- should "run unordered bulk operations in one batch per write-type" do
363
- with_write_commands(@db.connection) do
364
- @collection.expects(:batch_write).at_most(3).returns([[], [], [], []])
365
- bulk = @collection.initialize_unordered_bulk_op
366
- bulk.insert({:_id => 1, :a => 1})
367
- bulk.find({:_id => 1, :a => 1}).update({"$inc" => {:x => 1}})
368
- bulk.find({:_id => 1, :a => 1}).remove
369
- bulk.insert({:_id => 2, :a => 2})
370
- bulk.find({:_id => 2, :a => 2}).update({"$inc" => {:x => 2}})
371
- bulk.find({:_id => 2, :a => 2}).remove
372
- bulk.insert({:_id => 3, :a => 3})
373
- bulk.find({:_id => 3, :a => 3}).update({"$inc" => {:x => 3}})
374
- bulk.find({:_id => 3, :a => 3}).remove
375
- result = bulk.execute # unordered varies, don't use assert_match_document
693
+ should "run unordered bulk operations in one batch per write-type" do
694
+ with_write_commands(@db.connection) do
695
+ @collection.expects(:batch_write).at_most(3).returns([[], [], [], []])
696
+ bulk = @collection.initialize_unordered_bulk_op
697
+ bulk.insert({:_id => 1, :a => 1})
698
+ bulk.find({:_id => 1, :a => 1}).update({"$inc" => {:x => 1}})
699
+ bulk.find({:_id => 1, :a => 1}).remove
700
+ bulk.insert({:_id => 2, :a => 2})
701
+ bulk.find({:_id => 2, :a => 2}).update({"$inc" => {:x => 2}})
702
+ bulk.find({:_id => 2, :a => 2}).remove
703
+ bulk.insert({:_id => 3, :a => 3})
704
+ bulk.find({:_id => 3, :a => 3}).update({"$inc" => {:x => 3}})
705
+ bulk.find({:_id => 3, :a => 3}).remove
706
+ result = bulk.execute # unordered varies, don't use assert_match_document
707
+ end
708
+ end
709
+
710
+ should "run spec Unordered Bulk Operations" do
711
+ with_write_commands_and_operations(@db.connection) do |wire_version|
712
+ bulk = @collection.initialize_unordered_bulk_op
713
+ bulk.insert({:_id => 1})
714
+ bulk.find({:_id => 2}).update_one({'$inc' => { :x => 1 }})
715
+ bulk.find({:_id => 3}).remove_one
716
+ bulk.insert({:_id => 4})
717
+ bulk.find({:_id => 5}).update_one({'$inc' => { :x => 1 }})
718
+ bulk.find({:_id => 6}).remove_one
719
+ result = nil
720
+ begin
721
+ result = bulk.execute
722
+ rescue => ex
723
+ result = ex.result
724
+ end
725
+ # for write commands internally the driver will execute 3. One each for the inserts, updates and removes.
726
+ end
727
+ end
728
+
729
+ # ----- EMPTY BATCH -----
730
+
731
+ should "handle empty bulk op" do
732
+ with_write_commands_and_operations(@db.connection) do |wire_version|
733
+ assert_raise_error(MongoArgumentError, Mongo::BulkWriteCollectionView::EMPTY_BATCH_MSG) do
734
+ @bulk.execute
735
+ end
736
+ end
737
+ end
738
+
739
+ should "handle insert of overly large document" do
740
+ large_doc = {"a" => "y"*(2*@client.max_message_size)}
741
+ with_write_commands_and_operations(@db.connection) do |wire_version|
742
+ ex = assert_raise Mongo::BulkWriteError do
743
+ @collection.remove
744
+ bulk = @collection.initialize_unordered_bulk_op
745
+ bulk.insert(large_doc)
746
+ puts "bulk.execute:#{bulk.execute.inspect}"
747
+ end
748
+ assert_equal 22, ex.result["writeErrors"].first["code"]
376
749
  end
377
750
  end
378
751
 
752
+ # ----- ORDERED, WITH ERRORS -----
753
+
379
754
  should "handle error for duplicate key with offset" do
380
755
  with_write_commands_and_operations(@db.connection) do |wire_version|
381
756
  @collection.remove
@@ -401,28 +776,11 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
401
776
  "errmsg" => "batch item errors occurred",
402
777
  "nInserted" => 1,
403
778
  "nMatched" => 0,
404
- "nModified" => 0
779
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
405
780
  }, result, "wire_version:#{wire_version}")
406
781
  end
407
782
  end
408
783
 
409
- should "handle error for unordered multiple duplicate key with offset" do
410
- with_write_commands_and_operations(@db.connection) do |wire_version|
411
- @collection.remove
412
- @bulk = @collection.initialize_unordered_bulk_op
413
- @bulk.find({:a => 1}).remove
414
- @bulk.insert({:_id => 1, :a => 1})
415
- @bulk.insert({:_id => 1, :a => 2})
416
- @bulk.insert({:_id => 3, :a => 3})
417
- @bulk.insert({:_id => 3, :a => 3})
418
- ex = assert_raise BulkWriteError do
419
- @bulk.execute
420
- end
421
- result = ex.result # unordered varies, don't use assert_bulk_exception
422
- assert_not_nil(result["writeErrors"], "wire_version:#{wire_version}")
423
- end
424
- end
425
-
426
784
  should "handle error for serialization with offset" do
427
785
  with_write_commands_and_operations(@db.connection) do |wire_version|
428
786
  @collection.remove
@@ -449,12 +807,12 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
449
807
  "errmsg" => "batch item errors occurred",
450
808
  "nInserted" => 1,
451
809
  "nMatched" => 0,
452
- "nModified" => 0
810
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
453
811
  }, result, "wire_version:#{wire_version}")
454
812
  end
455
813
  end
456
814
 
457
- should "run ordered bulk op - spec Modes of Execution" do # spec fix pending
815
+ should "run ordered bulk op - spec Modes of Execution" do
458
816
  with_write_commands_and_operations(@db.connection) do |wire_version|
459
817
  @collection.remove
460
818
  @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
@@ -469,66 +827,7 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
469
827
  end
470
828
  end
471
829
 
472
- should "run unordered bulk op - spec Modes of Execution" do # spec fix pending
473
- with_write_commands_and_operations(@db.connection) do |wire_version|
474
- @collection.remove
475
- @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
476
- bulk = @collection.initialize_unordered_bulk_op
477
- bulk.insert({:a => 1})
478
- bulk.insert({:a => 2})
479
- bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
480
- bulk.find({:a => 3}).remove
481
- bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
482
- ex = assert_raise BulkWriteError do
483
- bulk.execute
484
- end
485
- result = ex.result
486
- assert(result["writeErrors"].size > 1, "wire_version:#{wire_version}")
487
- end
488
- end
489
-
490
- should "run spec Ordered Bulk Operations" do # spec fix pending
491
- with_write_commands_and_operations(@db.connection) do |wire_version|
492
- @bulk.insert({:a => 1})
493
- @bulk.insert({:a => 2})
494
- @bulk.insert({:a => 3})
495
- @bulk.find({:a => 2}).upsert.update({'$set' => {:a => 4}})
496
- @bulk.find({:a => 1}).remove_one
497
- @bulk.insert({:a => 5})
498
- result = @bulk.execute({:w => 1})
499
- assert_match_document(
500
- {
501
- "ok" => 1,
502
- "n" => 6,
503
- "nInserted" => 4,
504
- "nMatched" => 1,
505
- "nModified" => 1,
506
- "nRemoved" => 1,
507
- }, result, "wire_version:#{wire_version}")
508
- # for write commands there will be in sequence insert, update, remove, insert
509
- end
510
- end
511
-
512
- should "run spec Unordered Bulk Operations" do
513
- with_write_commands_and_operations(@db.connection) do |wire_version|
514
- bulk = @collection.initialize_unordered_bulk_op
515
- bulk.insert({:_id => 1})
516
- bulk.find({:_id => 2}).update_one({'$inc' => { :x => 1 }})
517
- bulk.find({:_id => 3}).remove_one
518
- bulk.insert({:_id => 4})
519
- bulk.find({:_id => 5}).update_one({'$inc' => { :x => 1 }})
520
- bulk.find({:_id => 6}).remove_one
521
- result = nil
522
- begin
523
- result = bulk.execute
524
- rescue => ex
525
- result = ex.result
526
- end
527
- # for write commands internally the driver will execute 3. One each for the inserts, updates and removes.
528
- end
529
- end
530
-
531
- should "handle duplicate key error - spec Merging Results" do # spec fix pending
830
+ should "handle duplicate key error - spec Merging Results" do
532
831
  with_write_commands_and_operations(@db.connection) do |wire_version|
533
832
  @collection.remove
534
833
  @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
@@ -555,37 +854,11 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
555
854
  "errmsg" => "batch item errors occurred",
556
855
  "nInserted" => 2,
557
856
  "nMatched" => 0,
558
- "nModified" => 0
857
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
559
858
  }, result, "wire_version:#{wire_version}")
560
859
  end
561
860
  end
562
861
 
563
- # should "handle error with deferred write concern error - spec Merging Results" do
564
- # end # see test/replica_set/insert_test.rb
565
-
566
- should "handle unordered errors - spec Merging Results" do # spec fix pending
567
- with_write_commands_and_operations(@db.connection) do |wire_version|
568
- @collection.remove
569
- @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
570
- bulk = @collection.initialize_unordered_bulk_op
571
- bulk.insert({:a => 1})
572
- bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
573
- bulk.insert({:a => 2})
574
- ex = assert_raise BulkWriteError do
575
- bulk.execute
576
- end
577
- result = ex.result # unordered varies, don't use assert_bulk_exception
578
- assert_equal(1, result['ok'], "wire_version:#{wire_version}")
579
- assert_equal(2, result['n'], "wire_version:#{wire_version}")
580
- err_details = result['writeErrors']
581
- assert_equal([2,nil,1][wire_version], err_details.first['index'], "wire_version:#{wire_version}")
582
- assert_match(/duplicate key error/, err_details.first['errmsg'], "wire_version:#{wire_version}")
583
- end
584
- end
585
-
586
- # should "handle unordered errors with deferred write concern error - spec Merging Results" do # TODO - spec review
587
- # end # see test/replica_set/insert_test.rb
588
-
589
862
  should "report user index - spec Merging errors" do
590
863
  with_write_commands_and_operations(@db.connection) do |wire_version|
591
864
  @collection.remove
@@ -613,28 +886,7 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
613
886
  "errmsg" => "batch item errors occurred",
614
887
  "nInserted" => 2,
615
888
  "nMatched" => 0,
616
- "nModified" => 0
617
- }, result, "wire_version:#{wire_version}")
618
- end
619
- end
620
-
621
- should "handle single upsert - spec Handling upserts" do # chose array always for upserted value
622
- with_write_commands_and_operations(@db.connection) do |wire_version|
623
- @collection.remove
624
- @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
625
- bulk = @collection.initialize_ordered_bulk_op
626
- bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
627
- result = bulk.execute
628
- assert_match_document(
629
- {
630
- "ok" => 1,
631
- "n" => 1,
632
- "nMatched" => 0,
633
- "nUpserted" => 1,
634
- "nModified" => 0,
635
- "upserted" => [
636
- {"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 0}
637
- ]
889
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
638
890
  }, result, "wire_version:#{wire_version}")
639
891
  end
640
892
  end
@@ -653,7 +905,7 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
653
905
  "n" => 2,
654
906
  "nMatched" => 0,
655
907
  "nUpserted" => 2,
656
- "nModified" => 0,
908
+ "nModified" => batch_commands?(wire_version) ? 0 : nil,
657
909
  "upserted" => [
658
910
  {"index" => 0, "_id" => BSON::ObjectId('52a1e37cbb67fbc77e26a338')},
659
911
  {"index" => 1, "_id" => BSON::ObjectId('52a1e37cbb67fbc77e26a339')}
@@ -662,28 +914,6 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
662
914
  end
663
915
  end
664
916
 
665
- should "handle multiple errors for unordered bulk write" do
666
- with_write_commands_and_operations(@db.connection) do |wire_version|
667
- @collection.remove
668
- @bulk = @collection.initialize_unordered_bulk_op
669
- @bulk.insert({:_id => 1, :a => 1})
670
- @bulk.insert({:_id => 1, :a => 2})
671
- @bulk.insert(generate_sized_doc(@@client.max_message_size + 1))
672
- @bulk.insert({:_id => 3, :a => 3})
673
- @bulk.find({:a => 4}).upsert.replace_one({:x => 3})
674
- ex = assert_raise BulkWriteError do
675
- @bulk.execute
676
- end
677
- result = ex.result # unordered varies, don't use assert_bulk_exception
678
- assert_equal(1, result['ok'], "wire_version:#{wire_version}")
679
- assert_equal(3, result['n'], "wire_version:#{wire_version}")
680
- err_details = result['writeErrors']
681
- assert_match(/duplicate key error/, err_details.find { |e| e['code']==11000 }['errmsg'], "wire_version:#{wire_version}")
682
- assert_match(/too large/, err_details.find { |e| e['index']==2 }['errmsg'], "wire_version:#{wire_version}")
683
- assert_not_nil(result['upserted'].find { |e| e['index']==4 }, "wire_version:#{wire_version}")
684
- end
685
- end
686
-
687
917
  should "handle replication usage error" do
688
918
  with_no_replication(@db.connection) do
689
919
  with_write_commands_and_operations(@db.connection) do |wire_version|
@@ -731,6 +961,87 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
731
961
  end
732
962
  end
733
963
 
964
+ # ----- UNORDERED, WITH ERRORS -----
965
+
966
+ should "handle error for unordered multiple duplicate key with offset" do
967
+ with_write_commands_and_operations(@db.connection) do |wire_version|
968
+ @collection.remove
969
+ @bulk = @collection.initialize_unordered_bulk_op
970
+ @bulk.find({:a => 1}).remove
971
+ @bulk.insert({:_id => 1, :a => 1})
972
+ @bulk.insert({:_id => 1, :a => 2})
973
+ @bulk.insert({:_id => 3, :a => 3})
974
+ @bulk.insert({:_id => 3, :a => 3})
975
+ ex = assert_raise BulkWriteError do
976
+ @bulk.execute
977
+ end
978
+ result = ex.result
979
+ assert_true (0 < result["nInserted"] && result["nInserted"] < 3)
980
+ assert_not_nil(result["writeErrors"], "wire_version:#{wire_version}")
981
+ end
982
+ end
983
+
984
+ should "run unordered bulk op - spec Modes of Execution" do
985
+ with_write_commands_and_operations(@db.connection) do |wire_version|
986
+ @collection.remove
987
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
988
+ bulk = @collection.initialize_unordered_bulk_op
989
+ bulk.insert({:a => 1})
990
+ bulk.insert({:a => 2})
991
+ bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
992
+ bulk.find({:a => 3}).remove
993
+ bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
994
+ ex = assert_raise BulkWriteError do
995
+ bulk.execute
996
+ end
997
+ result = ex.result
998
+ assert(result["writeErrors"].size > 1, "wire_version:#{wire_version}")
999
+ end
1000
+ end
1001
+
1002
+ should "handle unordered errors - spec Merging Results" do
1003
+ with_write_commands_and_operations(@db.connection) do |wire_version|
1004
+ @collection.remove
1005
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
1006
+ bulk = @collection.initialize_unordered_bulk_op
1007
+ bulk.insert({:a => 1})
1008
+ bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
1009
+ bulk.insert({:a => 2})
1010
+ ex = assert_raise BulkWriteError do
1011
+ bulk.execute
1012
+ end
1013
+ result = ex.result # unordered varies, don't use assert_bulk_exception
1014
+ assert_equal(1, result['ok'], "wire_version:#{wire_version}")
1015
+ assert_equal(2, result['n'], "wire_version:#{wire_version}")
1016
+ err_details = result['writeErrors']
1017
+ assert_match(/duplicate key error/, err_details.first['errmsg'], "wire_version:#{wire_version}")
1018
+ end
1019
+ end
1020
+
1021
+ should "handle multiple errors for unordered bulk write" do
1022
+ with_write_commands_and_operations(@db.connection) do |wire_version|
1023
+ @collection.remove
1024
+ @bulk = @collection.initialize_unordered_bulk_op
1025
+ @bulk.insert({:_id => 1, :a => 1})
1026
+ @bulk.insert({:_id => 1, :a => 2})
1027
+ @bulk.insert(generate_sized_doc(@@client.max_message_size + 1))
1028
+ @bulk.insert({:_id => 3, :a => 3})
1029
+ @bulk.find({:a => 4}).upsert.replace_one({:x => 3})
1030
+ ex = assert_raise BulkWriteError do
1031
+ @bulk.execute
1032
+ end
1033
+ result = ex.result # unordered varies, don't use assert_bulk_exception
1034
+ assert_equal(1, result['ok'], "wire_version:#{wire_version}")
1035
+ assert_equal(3, result['n'], "wire_version:#{wire_version}")
1036
+ err_details = result['writeErrors']
1037
+ assert_match(/duplicate key error/, err_details.find { |e| e['code']==11000 }['errmsg'], "wire_version:#{wire_version}")
1038
+ assert_match(/too large/, err_details.find { |e| e['index']==2 }['errmsg'], "wire_version:#{wire_version}")
1039
+ assert_not_nil(result['upserted'].find { |e| e['index']==4 }, "wire_version:#{wire_version}")
1040
+ end
1041
+ end
1042
+
1043
+ # ----- NO_JOURNAL -----
1044
+
734
1045
  should "handle journaling error" do
735
1046
  with_no_journaling(@db.connection) do
736
1047
  with_write_commands_and_operations(@db.connection) do |wire_version|
@@ -777,6 +1088,42 @@ class BulkWriteCollectionViewTest < Test::Unit::TestCase
777
1088
  end
778
1089
  end
779
1090
  end
780
- end
781
1091
 
1092
+ # ----- W = 0 -----
1093
+
1094
+ should "run ordered big example with w 0" do
1095
+ with_write_commands_and_operations(@db.connection) do |wire_version|
1096
+ @collection.remove
1097
+ big_example(@bulk)
1098
+ result = @bulk.execute({:w => 0})
1099
+ assert_equal(true, result, "wire_version:#{wire_version}")
1100
+ assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
1101
+ assert_equal [{"a"=>1, "x"=>2}, {"a"=>2, "x"=>4}, {"x"=>3}, {"x"=>3}, {"x"=>4}], sort_docs(@collection.find.to_a.collect { |doc| doc.delete("_id"); doc })
1102
+ end
1103
+ end
1104
+
1105
+ should "running with w 0 should not report write errors" do
1106
+ with_write_commands_and_operations(@db.connection) do
1107
+ @bulk.insert({:_id => 1, :a => 1 })
1108
+ @bulk.insert({:_id => 1, :a => 2 })
1109
+ @bulk.execute({:w => 0}) # should raise no duplicate key error
1110
+ end
1111
+ end
1112
+
1113
+ # ----- W > 0 WITH STANDALONE -----
1114
+
1115
+ should "disallow w > 0 against a standalone" do
1116
+ with_write_commands_and_operations(@db.connection) do |wire_version|
1117
+ @collection.remove
1118
+ @bulk.insert({:_id => 1, :a => 1 })
1119
+ @bulk.insert({:_id => 2, :a => 1 })
1120
+ @bulk.insert({:_id => 3, :a => 1 })
1121
+ assert_raise_error BulkWriteError do
1122
+ @bulk.execute({:w => 2})
1123
+ end
1124
+ assert (@collection.count == batch_commands?(wire_version) ? 0 : 1)
1125
+ end
1126
+ end
1127
+
1128
+ end
782
1129
  end