mongo 1.10.0.rc0 → 1.10.0.rc1

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.
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