mongo 1.10.0-java

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 (116) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +190 -0
  5. data/README.md +149 -0
  6. data/Rakefile +31 -0
  7. data/VERSION +1 -0
  8. data/bin/mongo_console +43 -0
  9. data/ext/jsasl/target/jsasl.jar +0 -0
  10. data/lib/mongo.rb +90 -0
  11. data/lib/mongo/bulk_write_collection_view.rb +380 -0
  12. data/lib/mongo/collection.rb +1164 -0
  13. data/lib/mongo/collection_writer.rb +364 -0
  14. data/lib/mongo/connection.rb +19 -0
  15. data/lib/mongo/connection/node.rb +239 -0
  16. data/lib/mongo/connection/pool.rb +347 -0
  17. data/lib/mongo/connection/pool_manager.rb +325 -0
  18. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  21. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  22. data/lib/mongo/connection/socket/tcp_socket.rb +86 -0
  23. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  24. data/lib/mongo/cursor.rb +719 -0
  25. data/lib/mongo/db.rb +735 -0
  26. data/lib/mongo/exception.rb +88 -0
  27. data/lib/mongo/functional.rb +21 -0
  28. data/lib/mongo/functional/authentication.rb +318 -0
  29. data/lib/mongo/functional/logging.rb +85 -0
  30. data/lib/mongo/functional/read_preference.rb +174 -0
  31. data/lib/mongo/functional/sasl_java.rb +48 -0
  32. data/lib/mongo/functional/uri_parser.rb +374 -0
  33. data/lib/mongo/functional/write_concern.rb +66 -0
  34. data/lib/mongo/gridfs.rb +18 -0
  35. data/lib/mongo/gridfs/grid.rb +112 -0
  36. data/lib/mongo/gridfs/grid_ext.rb +53 -0
  37. data/lib/mongo/gridfs/grid_file_system.rb +163 -0
  38. data/lib/mongo/gridfs/grid_io.rb +484 -0
  39. data/lib/mongo/legacy.rb +140 -0
  40. data/lib/mongo/mongo_client.rb +702 -0
  41. data/lib/mongo/mongo_replica_set_client.rb +523 -0
  42. data/lib/mongo/mongo_sharded_client.rb +159 -0
  43. data/lib/mongo/networking.rb +370 -0
  44. data/lib/mongo/utils.rb +19 -0
  45. data/lib/mongo/utils/conversions.rb +110 -0
  46. data/lib/mongo/utils/core_ext.rb +70 -0
  47. data/lib/mongo/utils/server_version.rb +69 -0
  48. data/lib/mongo/utils/support.rb +80 -0
  49. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  50. data/mongo.gemspec +36 -0
  51. data/test/functional/authentication_test.rb +35 -0
  52. data/test/functional/bulk_api_stress_test.rb +133 -0
  53. data/test/functional/bulk_write_collection_view_test.rb +1129 -0
  54. data/test/functional/client_test.rb +565 -0
  55. data/test/functional/collection_test.rb +2073 -0
  56. data/test/functional/collection_writer_test.rb +83 -0
  57. data/test/functional/conversions_test.rb +163 -0
  58. data/test/functional/cursor_fail_test.rb +63 -0
  59. data/test/functional/cursor_message_test.rb +57 -0
  60. data/test/functional/cursor_test.rb +625 -0
  61. data/test/functional/db_api_test.rb +819 -0
  62. data/test/functional/db_connection_test.rb +27 -0
  63. data/test/functional/db_test.rb +344 -0
  64. data/test/functional/grid_file_system_test.rb +285 -0
  65. data/test/functional/grid_io_test.rb +252 -0
  66. data/test/functional/grid_test.rb +273 -0
  67. data/test/functional/pool_test.rb +62 -0
  68. data/test/functional/safe_test.rb +98 -0
  69. data/test/functional/ssl_test.rb +29 -0
  70. data/test/functional/support_test.rb +62 -0
  71. data/test/functional/timeout_test.rb +58 -0
  72. data/test/functional/uri_test.rb +330 -0
  73. data/test/functional/write_concern_test.rb +118 -0
  74. data/test/helpers/general.rb +50 -0
  75. data/test/helpers/test_unit.rb +317 -0
  76. data/test/replica_set/authentication_test.rb +35 -0
  77. data/test/replica_set/basic_test.rb +174 -0
  78. data/test/replica_set/client_test.rb +341 -0
  79. data/test/replica_set/complex_connect_test.rb +77 -0
  80. data/test/replica_set/connection_test.rb +138 -0
  81. data/test/replica_set/count_test.rb +64 -0
  82. data/test/replica_set/cursor_test.rb +212 -0
  83. data/test/replica_set/insert_test.rb +140 -0
  84. data/test/replica_set/max_values_test.rb +145 -0
  85. data/test/replica_set/pinning_test.rb +55 -0
  86. data/test/replica_set/query_test.rb +73 -0
  87. data/test/replica_set/read_preference_test.rb +214 -0
  88. data/test/replica_set/refresh_test.rb +175 -0
  89. data/test/replica_set/replication_ack_test.rb +94 -0
  90. data/test/replica_set/ssl_test.rb +32 -0
  91. data/test/sharded_cluster/basic_test.rb +197 -0
  92. data/test/shared/authentication/basic_auth_shared.rb +286 -0
  93. data/test/shared/authentication/bulk_api_auth_shared.rb +259 -0
  94. data/test/shared/authentication/gssapi_shared.rb +164 -0
  95. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  96. data/test/shared/ssl_shared.rb +235 -0
  97. data/test/test_helper.rb +56 -0
  98. data/test/threading/basic_test.rb +120 -0
  99. data/test/tools/mongo_config.rb +608 -0
  100. data/test/tools/mongo_config_test.rb +160 -0
  101. data/test/unit/client_test.rb +347 -0
  102. data/test/unit/collection_test.rb +166 -0
  103. data/test/unit/connection_test.rb +325 -0
  104. data/test/unit/cursor_test.rb +299 -0
  105. data/test/unit/db_test.rb +136 -0
  106. data/test/unit/grid_test.rb +76 -0
  107. data/test/unit/mongo_sharded_client_test.rb +48 -0
  108. data/test/unit/node_test.rb +93 -0
  109. data/test/unit/pool_manager_test.rb +142 -0
  110. data/test/unit/read_pref_test.rb +115 -0
  111. data/test/unit/read_test.rb +159 -0
  112. data/test/unit/safe_test.rb +158 -0
  113. data/test/unit/sharding_pool_manager_test.rb +84 -0
  114. data/test/unit/write_concern_test.rb +175 -0
  115. metadata +260 -0
  116. 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
@@ -0,0 +1,1129 @@
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
+ require 'json'
17
+
18
+ module Mongo
19
+ class Collection
20
+ public :batch_write
21
+ end
22
+
23
+ class BulkWriteCollectionView
24
+ public :update_doc?, :replace_doc?, :nil_tally, :merge_result
25
+
26
+ # for reference and future server direction
27
+ def generate_batch_commands(groups, write_concern)
28
+ groups.collect do |op_type, documents|
29
+ {
30
+ op_type => @collection.name,
31
+ Mongo::CollectionWriter::WRITE_COMMAND_ARG_KEY[op_type] => documents,
32
+ :ordered => @options[:ordered],
33
+ :writeConcern => write_concern
34
+ }
35
+ end
36
+ end
37
+ end
38
+
39
+ class MongoDBError
40
+ def inspect
41
+ "#{self.class.name}.new(#{message.inspect},#{error_code.inspect},#{result.inspect})"
42
+ end
43
+ end
44
+ end
45
+
46
+ module BSON
47
+ class InvalidDocument
48
+ def inspect
49
+ "#{self.class.name}.new(#{message.inspect})"
50
+ end
51
+ end
52
+ end
53
+
54
+ class BulkWriteCollectionViewTest < Test::Unit::TestCase
55
+ @@client ||= standard_connection(:op_timeout => 10)
56
+ @@db = @@client.db(TEST_DB)
57
+ @@test = @@db.collection("test")
58
+ @@version = @@client.server_version
59
+
60
+ DATABASE_NAME = 'ruby_test_bulk_write_collection_view'
61
+ COLLECTION_NAME = 'test'
62
+ DUPLICATE_KEY_ERROR_CODE_SET = [11000, 11001, 12582, 16460].to_set
63
+
64
+ def assert_bulk_op_pushed(expected, view)
65
+ assert_equal expected, view.ops.last
66
+ end
67
+
68
+ def assert_is_bulk_write_collection_view(view)
69
+ assert_equal Mongo::BulkWriteCollectionView, view.class
70
+ end
71
+
72
+ def assert_bulk_exception(expected, message = '')
73
+ ex = assert_raise BulkWriteError, message do
74
+ pp yield
75
+ end
76
+ assert_equal(Mongo::ErrorCode::MULTIPLE_ERRORS_OCCURRED, ex.error_code, message)
77
+ assert_match_document(expected, ex.result, message)
78
+ end
79
+
80
+ def default_setup
81
+ @client = MongoClient.new
82
+ @db = @client[DATABASE_NAME]
83
+ @collection = @db[COLLECTION_NAME]
84
+ @collection.drop
85
+ @bulk = @collection.initialize_ordered_bulk_op
86
+ @q = {:a => 1}
87
+ @u = {"$inc" => {:x => 1}}
88
+ @r = {:b => 2}
89
+ end
90
+
91
+ def sort_docs(docs)
92
+ docs.sort{|a,b| [a.keys, a.values] <=> [b.keys, b.values]}
93
+ end
94
+
95
+ def generate_sized_doc(size)
96
+ doc = {"_id" => BSON::ObjectId.new, "x" => "y"}
97
+ serialize_doc = BSON::BSON_CODER.serialize(doc, false, false, size)
98
+ doc = {"_id" => BSON::ObjectId.new, "x" => "y" * (1 + size - serialize_doc.size)}
99
+ assert_equal size, BSON::BSON_CODER.serialize(doc, false, false, size).size
100
+ doc
101
+ end
102
+
103
+ context "Bulk API Collection" do
104
+ setup do
105
+ default_setup
106
+ end
107
+
108
+ should "inspect" do
109
+ assert_equal String, @bulk.inspect.class
110
+ end
111
+
112
+ should "check first key is operation for #update_doc?" do
113
+ assert_not_nil @bulk.update_doc?({"$inc" => {:x => 1}})
114
+ assert_false @bulk.update_doc?({})
115
+ assert_nil @bulk.update_doc?({:x => 1})
116
+ end
117
+
118
+ should "check no top-level key is operation for #replace_doc?" do
119
+ assert_true @bulk.replace_doc?({:x => 1})
120
+ assert_true @bulk.replace_doc?({})
121
+ assert_false @bulk.replace_doc?({"$inc" => {:x => 1}})
122
+ assert_false @bulk.replace_doc?({:a => 1, "$inc" => {:x => 1}})
123
+ end
124
+
125
+ should "generate_batch_commands" do
126
+ groups = [
127
+ [:insert, [{:n => 0}]],
128
+ [:update, [{:n => 1}, {:n => 2}]],
129
+ [:delete, [{:n => 3}]],
130
+ [:insert, [{:n => 5}, {:n => 6}, {:n => 7}]],
131
+ [:update, [{:n => 8}]],
132
+ [:delete, [{:n => 9}, {:n => 10}]]
133
+ ]
134
+ write_concern = {:w => 1}
135
+ result = @bulk.generate_batch_commands(groups, write_concern)
136
+ expected = [
137
+ {:insert => COLLECTION_NAME, :documents => [{:n => 0}], :ordered => true, :writeConcern => {:w => 1}},
138
+ {:update => COLLECTION_NAME, :updates => [{:n => 1}, {:n => 2}], :ordered => true, :writeConcern => {:w => 1}},
139
+ {:delete => COLLECTION_NAME, :deletes => [{:n => 3}], :ordered => true, :writeConcern => {:w => 1}},
140
+ {:insert => COLLECTION_NAME, :documents => [{:n => 5}, {:n => 6}, {:n => 7}], :ordered => true, :writeConcern => {:w => 1}},
141
+ {:update => COLLECTION_NAME, :updates => [{:n => 8}], :ordered => true, :writeConcern => {:w => 1}},
142
+ {:delete => COLLECTION_NAME, :deletes => [{:n => 9}, {:n => 10}], :ordered => true, :writeConcern => {:w => 1}}
143
+ ]
144
+ assert_equal expected, result
145
+ end
146
+
147
+ should "Initialize an unordered bulk op - spec Bulk Operation Builder" do
148
+ @bulk = @collection.initialize_unordered_bulk_op
149
+ assert_is_bulk_write_collection_view(@bulk)
150
+ assert_equal @collection, @bulk.collection
151
+ assert_equal false, @bulk.options[:ordered]
152
+ end
153
+
154
+ should "Initialize an ordered bulk op - spec Bulk Operation Builder" do
155
+ assert_is_bulk_write_collection_view(@bulk)
156
+ assert_equal @collection, @bulk.collection
157
+ assert_equal true, @bulk.options[:ordered]
158
+ end
159
+ end
160
+
161
+ def big_example(bulk)
162
+ bulk.insert({:a => 1})
163
+ bulk.insert({:a => 2})
164
+ bulk.insert({:a => 3})
165
+ bulk.insert({:a => 4})
166
+ bulk.insert({:a => 5})
167
+ # Update one document matching the selector
168
+ bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
169
+ # Update all documents matching the selector
170
+ bulk.find({:a => 2}).update({"$inc" => {:x => 2}})
171
+ # Replace entire document (update with whole doc replace)
172
+ bulk.find({:a => 3}).replace_one({:x => 3})
173
+ # Update one document matching the selector or upsert
174
+ bulk.find({:a => 1}).upsert.update_one({"$inc" => {:x => 1}})
175
+ # Update all documents matching the selector or upsert
176
+ bulk.find({:a => 2}).upsert.update({"$inc" => {:x => 2}})
177
+ # Replaces a single document matching the selector or upsert
178
+ bulk.find({:a => 3}).upsert.replace_one({:x => 3})
179
+ # Remove a single document matching the selector
180
+ bulk.find({:a => 4}).remove_one()
181
+ # Remove all documents matching the selector
182
+ bulk.find({:a => 5}).remove()
183
+ # Insert a document
184
+ bulk.insert({:x => 4})
185
+ end
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
+
195
+ context "Bulk API CollectionView" do
196
+ setup do
197
+ default_setup
198
+ end
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
+
234
+ should "set :q and return view for #find" do
235
+ result = @bulk.find(@q)
236
+ assert_is_bulk_write_collection_view(result)
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])
242
+ end
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
+
253
+ should "set :upsert for #upsert" do
254
+ result = @bulk.find(@q).upsert
255
+ assert_is_bulk_write_collection_view(result)
256
+ assert_true result.op_args[:upsert]
257
+ end
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
+
295
+ should "check arg for update, set :update, :u, :multi, terminate and return view for #update_one" do
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
320
+ end
321
+ end
322
+
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)
339
+ end
340
+ end
341
+
342
+ # ----- REPLACE_ONE -----
343
+
344
+ should "check arg for replacement, set :update, :u, :multi, terminate and return view for #replace_one" do
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
373
+ end
374
+ end
375
+
376
+ # ----- REMOVE -----
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
401
+ end
402
+
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
407
+ result = @bulk.find(@q).remove
408
+ assert_is_bulk_write_collection_view(result)
409
+ assert_bulk_op_pushed [:delete, {:q => @q, :limit => 0}], @bulk
410
+ end
411
+
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
419
+ assert_is_bulk_write_collection_view(result)
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
467
+ end
468
+
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
472
+
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}")
488
+
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
503
+
504
+ # ----- UPSERT-UPDATE_ONE -----
505
+
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
510
+
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
527
+
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})
533
+
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
546
+
547
+ # ----- UPSERT-REPLACE_ONE -----
548
+
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
570
+
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
593
+ end
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
+
603
+ should "execute, return result and reset @ops for #execute" do
604
+ with_write_commands_and_operations(@db.connection) do |wire_version|
605
+ @collection.remove
606
+ @bulk.insert({:x => 1})
607
+ @bulk.insert({:x => 2})
608
+ write_concern = {:w => 1}
609
+ result = @bulk.execute(write_concern)
610
+ assert_equal({"ok" => 1, "n" => 2, "nInserted" => 2}, result, "wire_version:#{wire_version}")
611
+ assert_equal 2, @collection.count
612
+ assert_equal [], @bulk.ops
613
+ end
614
+ end
615
+
616
+ should "run ordered big example" do
617
+ with_write_commands_and_operations(@db.connection) do |wire_version|
618
+ @collection.remove
619
+ big_example(@bulk)
620
+ write_concern = {:w => 1} #{:w => 1. :j => 1} #nojournal for tests
621
+ result = @bulk.execute(write_concern)
622
+ assert_match_document(
623
+ {
624
+ "ok" => 1,
625
+ "n" => 14,
626
+ "nInserted" => 6,
627
+ "nMatched" => 5,
628
+ "nUpserted" => 1,
629
+ "nModified" => batch_commands?(wire_version) ? 5 : nil,
630
+ "nRemoved" => 2,
631
+ "upserted" => [
632
+ {
633
+ "index" => 10,
634
+ "_id" => BSON::ObjectId('52a1e4a4bb67fbc77e26a340')
635
+ }
636
+ ]
637
+ }, result, "wire_version:#{wire_version}")
638
+ assert_equal(batch_commands?(wire_version), result.has_key?("nModified"), "wire_version:#{wire_version}")
639
+ assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
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 })
641
+ end
642
+ end
643
+
644
+ should "run spec Ordered Bulk Operations" do
645
+ with_write_commands_and_operations(@db.connection) do |wire_version|
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}")
662
+ end
663
+ end
664
+
665
+ # ----- MIXED OPS, UNORDERED -----
666
+
667
+ should "run unordered big example" do
668
+ with_write_commands_and_operations(@db.connection) do |wire_version|
669
+ @collection.remove
670
+ @bulk = @collection.initialize_unordered_bulk_op
671
+ big_example(@bulk)
672
+ write_concern = {:w => 1} #{:w => 1. :j => 1} #nojournal for tests
673
+ result = @bulk.execute(write_concern)
674
+ assert_equal(6, result["nInserted"])
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}")
677
+ assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
678
+ end
679
+ end
680
+
681
+ should "run unordered big example with w 0" do
682
+ with_write_commands_and_operations(@db.connection) do |wire_version|
683
+ @collection.remove
684
+ @bulk = @collection.initialize_unordered_bulk_op
685
+ big_example(@bulk)
686
+ write_concern = {:w => 0}
687
+ result = @bulk.execute(write_concern)
688
+ assert_equal(true, result, "wire_version:#{wire_version}")
689
+ assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
690
+ end
691
+ end
692
+
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"]
749
+ end
750
+ end
751
+
752
+ # ----- ORDERED, WITH ERRORS -----
753
+
754
+ should "handle error for duplicate key with offset" do
755
+ with_write_commands_and_operations(@db.connection) do |wire_version|
756
+ @collection.remove
757
+ @bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
758
+ @bulk.insert({:_id => 1, :a => 1})
759
+ @bulk.insert({:_id => 1, :a => 2})
760
+ @bulk.insert({:_id => 3, :a => 3})
761
+ ex = assert_raise BulkWriteError do
762
+ @bulk.execute
763
+ end
764
+ result = ex.result
765
+ assert_match_document(
766
+ {
767
+ "ok" => 1,
768
+ "n" => 1,
769
+ "writeErrors" =>
770
+ [{
771
+ "index" => 2,
772
+ "code" => 11000,
773
+ "errmsg" => /duplicate key error/
774
+ }],
775
+ "code" => 65,
776
+ "errmsg" => "batch item errors occurred",
777
+ "nInserted" => 1,
778
+ "nMatched" => 0,
779
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
780
+ }, result, "wire_version:#{wire_version}")
781
+ end
782
+ end
783
+
784
+ should "handle error for serialization with offset" do
785
+ with_write_commands_and_operations(@db.connection) do |wire_version|
786
+ @collection.remove
787
+ assert_equal 16777216, @@client.max_bson_size
788
+ @bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
789
+ @bulk.insert({:_id => 1, :a => 1})
790
+ @bulk.insert(generate_sized_doc(@@client.max_message_size + 1))
791
+ @bulk.insert({:_id => 3, :a => 3})
792
+ ex = assert_raise BulkWriteError do
793
+ @bulk.execute
794
+ end
795
+ result = ex.result
796
+ assert_match_document(
797
+ {
798
+ "ok" => 1,
799
+ "n" => 1,
800
+ "writeErrors" =>
801
+ [{
802
+ "index" => 2,
803
+ "code" => 22,
804
+ "errmsg" => /too large/
805
+ }],
806
+ "code" => 65,
807
+ "errmsg" => "batch item errors occurred",
808
+ "nInserted" => 1,
809
+ "nMatched" => 0,
810
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
811
+ }, result, "wire_version:#{wire_version}")
812
+ end
813
+ end
814
+
815
+ should "run ordered bulk op - spec Modes of Execution" do
816
+ with_write_commands_and_operations(@db.connection) do |wire_version|
817
+ @collection.remove
818
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
819
+ @bulk.insert({:a => 1})
820
+ @bulk.insert({:a => 2})
821
+ @bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
822
+ @bulk.find({:a => 1}).remove
823
+ ex = assert_raise BulkWriteError do
824
+ @bulk.execute
825
+ end
826
+ assert_equal(2, @collection.count)
827
+ end
828
+ end
829
+
830
+ should "handle duplicate key error - spec Merging Results" do
831
+ with_write_commands_and_operations(@db.connection) do |wire_version|
832
+ @collection.remove
833
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
834
+ bulk = @collection.initialize_ordered_bulk_op
835
+ bulk.insert({:a => 1})
836
+ bulk.insert({:a => 2})
837
+ bulk.find({:a => 2}).upsert.update({'$set' => {:a => 1}})
838
+ bulk.insert({:a => 3})
839
+ ex = assert_raise BulkWriteError do
840
+ bulk.execute
841
+ end
842
+ result = ex.result
843
+ assert_match_document(
844
+ {
845
+ "ok" => 1,
846
+ "n" => 2,
847
+ "writeErrors" =>
848
+ [{
849
+ "index" => 2,
850
+ "code" => DUPLICATE_KEY_ERROR_CODE_SET,
851
+ "errmsg" => /duplicate key error/
852
+ }],
853
+ "code" => 65,
854
+ "errmsg" => "batch item errors occurred",
855
+ "nInserted" => 2,
856
+ "nMatched" => 0,
857
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
858
+ }, result, "wire_version:#{wire_version}")
859
+ end
860
+ end
861
+
862
+ should "report user index - spec Merging errors" do
863
+ with_write_commands_and_operations(@db.connection) do |wire_version|
864
+ @collection.remove
865
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
866
+ bulk = @collection.initialize_ordered_bulk_op
867
+ bulk.insert({:a => 1})
868
+ bulk.insert({:a => 2})
869
+ bulk.find({:a => 2}).update_one({'$set' => {:a => 1}});
870
+ bulk.find({:a => 4}).remove_one();
871
+ ex = assert_raise BulkWriteError do
872
+ bulk.execute({:w => 1})
873
+ end
874
+ result = ex.result
875
+ assert_match_document(
876
+ {
877
+ "ok" => 1,
878
+ "n" => 2,
879
+ "writeErrors" =>
880
+ [{
881
+ "index" => 2,
882
+ "code" => DUPLICATE_KEY_ERROR_CODE_SET,
883
+ "errmsg" => /duplicate key error/
884
+ }],
885
+ "code" => 65,
886
+ "errmsg" => "batch item errors occurred",
887
+ "nInserted" => 2,
888
+ "nMatched" => 0,
889
+ "nModified" => batch_commands?(wire_version) ? 0 : nil
890
+ }, result, "wire_version:#{wire_version}")
891
+ end
892
+ end
893
+
894
+ should "handle multiple upsert - spec Handling upserts" do
895
+ with_write_commands_and_operations(@db.connection) do |wire_version|
896
+ @collection.remove
897
+ @collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
898
+ bulk = @collection.initialize_ordered_bulk_op
899
+ bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
900
+ bulk.find({:a => 3}).upsert.update({'$set' => {:a => 4}})
901
+ result = bulk.execute
902
+ assert_match_document(
903
+ {
904
+ "ok" => 1,
905
+ "n" => 2,
906
+ "nMatched" => 0,
907
+ "nUpserted" => 2,
908
+ "nModified" => batch_commands?(wire_version) ? 0 : nil,
909
+ "upserted" => [
910
+ {"index" => 0, "_id" => BSON::ObjectId('52a1e37cbb67fbc77e26a338')},
911
+ {"index" => 1, "_id" => BSON::ObjectId('52a1e37cbb67fbc77e26a339')}
912
+ ]
913
+ }, result, "wire_version:#{wire_version}")
914
+ end
915
+ end
916
+
917
+ should "handle replication usage error" do
918
+ with_no_replication(@db.connection) do
919
+ with_write_commands_and_operations(@db.connection) do |wire_version|
920
+ @collection.remove
921
+ @bulk = @collection.initialize_ordered_bulk_op
922
+ @bulk.insert({:_id => 1, :a => 1})
923
+ write_concern = {:w => 5}
924
+ ex = assert_raise BulkWriteError do
925
+ @bulk.execute(write_concern)
926
+ end
927
+ result = ex.result
928
+ if @@version >= "2.5.5"
929
+ assert_match_document(
930
+ {
931
+ "ok" => 0,
932
+ "n" => 0,
933
+ "code" => 65,
934
+ "errmsg" => "batch item errors occurred",
935
+ "writeErrors" => [
936
+ {
937
+ "errmsg" => "cannot use 'w' > 1 when a host is not replicated",
938
+ "code" => 2,
939
+ "index" => 0}
940
+ ],
941
+ "nInserted" => 0,
942
+ }, result, "wire_version:#{wire_version}")
943
+ else
944
+ assert_match_document(
945
+ {
946
+ "ok" => 1,
947
+ "n" => 1,
948
+ "code" => 65,
949
+ "errmsg" => "batch item errors occurred",
950
+ "writeConcernError" => [
951
+ {
952
+ "errmsg" => /no replication has been enabled/,
953
+ "code" => 64,
954
+ "index" => 0
955
+ }
956
+ ],
957
+ "nInserted" => 1,
958
+ }, result, "wire_version:#{wire_version}")
959
+ end
960
+ end
961
+ end
962
+ end
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
+
1045
+ should "handle journaling error" do
1046
+ with_no_journaling(@db.connection) do
1047
+ with_write_commands_and_operations(@db.connection) do |wire_version|
1048
+ @collection.remove
1049
+ @bulk = @collection.initialize_ordered_bulk_op
1050
+ @bulk.insert({:_id => 1, :a => 1})
1051
+ write_concern = {:w => 1, :j => 1}
1052
+ ex = assert_raise BulkWriteError do
1053
+ @bulk.execute(write_concern)
1054
+ end
1055
+ result = ex.result
1056
+ if @@version >= "2.5.5"
1057
+ assert_match_document(
1058
+ {
1059
+ "ok" => 0,
1060
+ "n" => 0,
1061
+ "writeErrors" => [
1062
+ {
1063
+ "code" => 2,
1064
+ "errmsg" => "cannot use 'j' option when a host does not have journaling enabled", "index" => 0
1065
+ }
1066
+ ],
1067
+ "code" => 65,
1068
+ "errmsg" => "batch item errors occurred",
1069
+ "nInserted" => 0
1070
+ }, result, "wire_version:#{wire_version}")
1071
+ else
1072
+ assert_match_document(
1073
+ {
1074
+ "ok" => 1,
1075
+ "n" => 1,
1076
+ "writeConcernError" => [
1077
+ {
1078
+ "code" => 2,
1079
+ "errmsg" => "journaling not enabled on this server",
1080
+ "index" => 0
1081
+ }
1082
+ ],
1083
+ "code" => 65,
1084
+ "errmsg" => "batch item errors occurred",
1085
+ "nInserted" => 1
1086
+ }, result, "wire_version:#{wire_version}")
1087
+ end
1088
+ end
1089
+ end
1090
+ end
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
1129
+ end