mongo 1.3.0 → 1.12.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +122 -271
- data/Rakefile +25 -209
- data/VERSION +1 -0
- data/bin/mongo_console +31 -9
- data/lib/mongo/bulk_write_collection_view.rb +387 -0
- data/lib/mongo/collection.rb +576 -269
- data/lib/mongo/collection_writer.rb +364 -0
- data/lib/mongo/connection/node.rb +249 -0
- data/lib/mongo/connection/pool.rb +340 -0
- data/lib/mongo/connection/pool_manager.rb +320 -0
- data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
- data/lib/mongo/connection/socket/socket_util.rb +37 -0
- data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
- data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
- data/lib/mongo/connection/socket/unix_socket.rb +39 -0
- data/lib/mongo/connection/socket.rb +18 -0
- data/lib/mongo/connection.rb +7 -875
- data/lib/mongo/cursor.rb +403 -117
- data/lib/mongo/db.rb +444 -243
- data/lib/mongo/exception.rb +145 -0
- data/lib/mongo/functional/authentication.rb +455 -0
- data/lib/mongo/functional/logging.rb +85 -0
- data/lib/mongo/functional/read_preference.rb +183 -0
- data/lib/mongo/functional/scram.rb +556 -0
- data/lib/mongo/functional/uri_parser.rb +409 -0
- data/lib/mongo/functional/write_concern.rb +66 -0
- data/lib/mongo/functional.rb +20 -0
- data/lib/mongo/gridfs/grid.rb +30 -24
- data/lib/mongo/gridfs/grid_ext.rb +6 -10
- data/lib/mongo/gridfs/grid_file_system.rb +38 -20
- data/lib/mongo/gridfs/grid_io.rb +84 -75
- data/lib/mongo/gridfs.rb +18 -0
- data/lib/mongo/legacy.rb +140 -0
- data/lib/mongo/mongo_client.rb +697 -0
- data/lib/mongo/mongo_replica_set_client.rb +535 -0
- data/lib/mongo/mongo_sharded_client.rb +159 -0
- data/lib/mongo/networking.rb +372 -0
- data/lib/mongo/{util → utils}/conversions.rb +29 -8
- data/lib/mongo/{util → utils}/core_ext.rb +28 -18
- data/lib/mongo/{util → utils}/server_version.rb +4 -6
- data/lib/mongo/{util → utils}/support.rb +29 -31
- data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
- data/lib/mongo/utils.rb +19 -0
- data/lib/mongo.rb +51 -50
- data/mongo.gemspec +29 -32
- data/test/functional/authentication_test.rb +39 -0
- data/test/functional/bulk_api_stress_test.rb +133 -0
- data/test/functional/bulk_write_collection_view_test.rb +1198 -0
- data/test/functional/client_test.rb +627 -0
- data/test/functional/collection_test.rb +2175 -0
- data/test/functional/collection_writer_test.rb +83 -0
- data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
- data/test/functional/cursor_fail_test.rb +57 -0
- data/test/functional/cursor_message_test.rb +56 -0
- data/test/functional/cursor_test.rb +683 -0
- data/test/functional/db_api_test.rb +835 -0
- data/test/functional/db_connection_test.rb +25 -0
- data/test/functional/db_test.rb +348 -0
- data/test/functional/grid_file_system_test.rb +285 -0
- data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
- data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
- data/test/functional/pool_test.rb +136 -0
- data/test/functional/safe_test.rb +98 -0
- data/test/functional/ssl_test.rb +29 -0
- data/test/functional/support_test.rb +62 -0
- data/test/functional/timeout_test.rb +60 -0
- data/test/functional/uri_test.rb +446 -0
- data/test/functional/write_concern_test.rb +118 -0
- data/test/helpers/general.rb +50 -0
- data/test/helpers/test_unit.rb +476 -0
- data/test/replica_set/authentication_test.rb +37 -0
- data/test/replica_set/basic_test.rb +189 -0
- data/test/replica_set/client_test.rb +393 -0
- data/test/replica_set/connection_test.rb +138 -0
- data/test/replica_set/count_test.rb +66 -0
- data/test/replica_set/cursor_test.rb +220 -0
- data/test/replica_set/insert_test.rb +157 -0
- data/test/replica_set/max_values_test.rb +151 -0
- data/test/replica_set/pinning_test.rb +105 -0
- data/test/replica_set/query_test.rb +73 -0
- data/test/replica_set/read_preference_test.rb +219 -0
- data/test/replica_set/refresh_test.rb +211 -0
- data/test/replica_set/replication_ack_test.rb +95 -0
- data/test/replica_set/ssl_test.rb +32 -0
- data/test/sharded_cluster/basic_test.rb +203 -0
- data/test/shared/authentication/basic_auth_shared.rb +260 -0
- data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
- data/test/shared/authentication/gssapi_shared.rb +176 -0
- data/test/shared/authentication/sasl_plain_shared.rb +96 -0
- data/test/shared/authentication/scram_shared.rb +92 -0
- data/test/shared/ssl_shared.rb +235 -0
- data/test/test_helper.rb +53 -94
- data/test/threading/basic_test.rb +120 -0
- data/test/tools/mongo_config.rb +708 -0
- data/test/tools/mongo_config_test.rb +160 -0
- data/test/unit/client_test.rb +381 -0
- data/test/unit/collection_test.rb +89 -53
- data/test/unit/connection_test.rb +282 -32
- data/test/unit/cursor_test.rb +206 -8
- data/test/unit/db_test.rb +55 -13
- data/test/unit/grid_test.rb +43 -16
- data/test/unit/mongo_sharded_client_test.rb +48 -0
- data/test/unit/node_test.rb +93 -0
- data/test/unit/pool_manager_test.rb +111 -0
- data/test/unit/read_pref_test.rb +406 -0
- data/test/unit/read_test.rb +159 -0
- data/test/unit/safe_test.rb +69 -36
- data/test/unit/sharding_pool_manager_test.rb +84 -0
- data/test/unit/write_concern_test.rb +175 -0
- data.tar.gz.sig +3 -0
- metadata +227 -216
- metadata.gz.sig +0 -0
- data/docs/CREDITS.md +0 -123
- data/docs/FAQ.md +0 -116
- data/docs/GridFS.md +0 -158
- data/docs/HISTORY.md +0 -244
- data/docs/RELEASES.md +0 -33
- data/docs/REPLICA_SETS.md +0 -72
- data/docs/TUTORIAL.md +0 -247
- data/docs/WRITE_CONCERN.md +0 -28
- data/lib/mongo/exceptions.rb +0 -71
- data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
- data/lib/mongo/repl_set_connection.rb +0 -342
- data/lib/mongo/test.rb +0 -20
- data/lib/mongo/util/pool.rb +0 -177
- data/lib/mongo/util/uri_parser.rb +0 -185
- data/test/async/collection_test.rb +0 -224
- data/test/async/connection_test.rb +0 -24
- data/test/async/cursor_test.rb +0 -162
- data/test/async/worker_pool_test.rb +0 -99
- data/test/auxillary/1.4_features.rb +0 -166
- data/test/auxillary/authentication_test.rb +0 -68
- data/test/auxillary/autoreconnect_test.rb +0 -41
- data/test/auxillary/fork_test.rb +0 -30
- data/test/auxillary/repl_set_auth_test.rb +0 -58
- data/test/auxillary/slave_connection_test.rb +0 -36
- data/test/auxillary/threaded_authentication_test.rb +0 -101
- data/test/bson/binary_test.rb +0 -15
- data/test/bson/bson_test.rb +0 -649
- data/test/bson/byte_buffer_test.rb +0 -208
- data/test/bson/hash_with_indifferent_access_test.rb +0 -38
- data/test/bson/json_test.rb +0 -17
- data/test/bson/object_id_test.rb +0 -154
- data/test/bson/ordered_hash_test.rb +0 -204
- data/test/bson/timestamp_test.rb +0 -24
- data/test/collection_test.rb +0 -910
- data/test/connection_test.rb +0 -309
- data/test/cursor_fail_test.rb +0 -75
- data/test/cursor_message_test.rb +0 -43
- data/test/cursor_test.rb +0 -483
- data/test/db_api_test.rb +0 -726
- data/test/db_connection_test.rb +0 -15
- data/test/db_test.rb +0 -287
- data/test/grid_file_system_test.rb +0 -243
- data/test/load/resque/load.rb +0 -21
- data/test/load/resque/processor.rb +0 -26
- data/test/load/thin/load.rb +0 -24
- data/test/load/unicorn/load.rb +0 -23
- data/test/load/unicorn/unicorn.rb +0 -29
- data/test/replica_sets/connect_test.rb +0 -94
- data/test/replica_sets/connection_string_test.rb +0 -32
- data/test/replica_sets/count_test.rb +0 -35
- data/test/replica_sets/insert_test.rb +0 -53
- data/test/replica_sets/pooled_insert_test.rb +0 -55
- data/test/replica_sets/query_secondaries.rb +0 -96
- data/test/replica_sets/query_test.rb +0 -51
- data/test/replica_sets/replication_ack_test.rb +0 -66
- data/test/replica_sets/rs_test_helper.rb +0 -27
- data/test/safe_test.rb +0 -68
- data/test/support/hash_with_indifferent_access.rb +0 -186
- data/test/support/keys.rb +0 -45
- data/test/support_test.rb +0 -18
- data/test/threading/threading_with_large_pool_test.rb +0 -90
- data/test/threading_test.rb +0 -87
- data/test/tools/auth_repl_set_manager.rb +0 -14
- data/test/tools/load.rb +0 -58
- data/test/tools/repl_set_manager.rb +0 -266
- data/test/tools/sharding_manager.rb +0 -202
- data/test/tools/test.rb +0 -4
- data/test/unit/pool_test.rb +0 -9
- data/test/unit/repl_set_connection_test.rb +0 -59
- data/test/uri_test.rb +0 -91
@@ -0,0 +1,1198 @@
|
|
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
|
+
COLLECTION_NAME = 'test'
|
56
|
+
DUPLICATE_KEY_ERROR_CODE_SET = [11000, 11001, 12582, 16460].to_set
|
57
|
+
|
58
|
+
def assert_bulk_op_pushed(expected, view)
|
59
|
+
assert_equal expected, view.ops.last
|
60
|
+
end
|
61
|
+
|
62
|
+
def assert_is_bulk_write_collection_view(view)
|
63
|
+
assert_equal Mongo::BulkWriteCollectionView, view.class
|
64
|
+
end
|
65
|
+
|
66
|
+
def assert_bulk_exception(expected, message = '')
|
67
|
+
ex = assert_raise BulkWriteError, message do
|
68
|
+
pp yield
|
69
|
+
end
|
70
|
+
assert_equal(Mongo::ErrorCode::MULTIPLE_ERRORS_OCCURRED, ex.error_code, message)
|
71
|
+
assert_match_document(expected, ex.result, message)
|
72
|
+
end
|
73
|
+
|
74
|
+
def default_setup
|
75
|
+
@client = standard_connection
|
76
|
+
@version = @client.server_version
|
77
|
+
@db = @client[TEST_DB]
|
78
|
+
@collection = @db[COLLECTION_NAME]
|
79
|
+
@collection.drop
|
80
|
+
@bulk = @collection.initialize_ordered_bulk_op
|
81
|
+
@q = {:a => 1}
|
82
|
+
@u = {"$inc" => {:x => 1}}
|
83
|
+
@r = {:b => 2}
|
84
|
+
end
|
85
|
+
|
86
|
+
def sort_docs(docs)
|
87
|
+
docs.sort{|a,b| [a.keys, a.values] <=> [b.keys, b.values]}
|
88
|
+
end
|
89
|
+
|
90
|
+
def generate_sized_doc(size)
|
91
|
+
doc = {"_id" => BSON::ObjectId.new, "x" => "y"}
|
92
|
+
serialize_doc = BSON::BSON_CODER.serialize(doc, false, false, size)
|
93
|
+
doc = {"_id" => BSON::ObjectId.new, "x" => "y" * (1 + size - serialize_doc.size)}
|
94
|
+
assert_equal size, BSON::BSON_CODER.serialize(doc, false, false, size).size
|
95
|
+
doc
|
96
|
+
end
|
97
|
+
|
98
|
+
context "Bulk API Collection" do
|
99
|
+
setup do
|
100
|
+
default_setup
|
101
|
+
end
|
102
|
+
|
103
|
+
should "inspect" do
|
104
|
+
assert_equal String, @bulk.inspect.class
|
105
|
+
end
|
106
|
+
|
107
|
+
should "check first key is operation for #update_doc?" do
|
108
|
+
assert_not_nil @bulk.update_doc?({"$inc" => {:x => 1}})
|
109
|
+
assert_false @bulk.update_doc?({})
|
110
|
+
assert_nil @bulk.update_doc?({:x => 1})
|
111
|
+
end
|
112
|
+
|
113
|
+
should "check no top-level key is operation for #replace_doc?" do
|
114
|
+
assert_true @bulk.replace_doc?({:x => 1})
|
115
|
+
assert_true @bulk.replace_doc?({})
|
116
|
+
assert_false @bulk.replace_doc?({"$inc" => {:x => 1}})
|
117
|
+
assert_false @bulk.replace_doc?({:a => 1, "$inc" => {:x => 1}})
|
118
|
+
end
|
119
|
+
|
120
|
+
should "generate_batch_commands" do
|
121
|
+
groups = [
|
122
|
+
[:insert, [{:n => 0}]],
|
123
|
+
[:update, [{:n => 1}, {:n => 2}]],
|
124
|
+
[:delete, [{:n => 3}]],
|
125
|
+
[:insert, [{:n => 5}, {:n => 6}, {:n => 7}]],
|
126
|
+
[:update, [{:n => 8}]],
|
127
|
+
[:delete, [{:n => 9}, {:n => 10}]]
|
128
|
+
]
|
129
|
+
write_concern = {:w => 1}
|
130
|
+
result = @bulk.generate_batch_commands(groups, write_concern)
|
131
|
+
expected = [
|
132
|
+
{:insert => COLLECTION_NAME, :documents => [{:n => 0}], :ordered => true, :writeConcern => {:w => 1}},
|
133
|
+
{:update => COLLECTION_NAME, :updates => [{:n => 1}, {:n => 2}], :ordered => true, :writeConcern => {:w => 1}},
|
134
|
+
{:delete => COLLECTION_NAME, :deletes => [{:n => 3}], :ordered => true, :writeConcern => {:w => 1}},
|
135
|
+
{:insert => COLLECTION_NAME, :documents => [{:n => 5}, {:n => 6}, {:n => 7}], :ordered => true, :writeConcern => {:w => 1}},
|
136
|
+
{:update => COLLECTION_NAME, :updates => [{:n => 8}], :ordered => true, :writeConcern => {:w => 1}},
|
137
|
+
{:delete => COLLECTION_NAME, :deletes => [{:n => 9}, {:n => 10}], :ordered => true, :writeConcern => {:w => 1}}
|
138
|
+
]
|
139
|
+
assert_equal expected, result
|
140
|
+
end
|
141
|
+
|
142
|
+
should "Initialize an unordered bulk op - spec Bulk Operation Builder" do
|
143
|
+
@bulk = @collection.initialize_unordered_bulk_op
|
144
|
+
assert_is_bulk_write_collection_view(@bulk)
|
145
|
+
assert_equal @collection, @bulk.collection
|
146
|
+
assert_equal false, @bulk.options[:ordered]
|
147
|
+
end
|
148
|
+
|
149
|
+
should "Initialize an ordered bulk op - spec Bulk Operation Builder" do
|
150
|
+
assert_is_bulk_write_collection_view(@bulk)
|
151
|
+
assert_equal @collection, @bulk.collection
|
152
|
+
assert_equal true, @bulk.options[:ordered]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def big_example(bulk)
|
157
|
+
bulk.insert({:a => 1})
|
158
|
+
bulk.insert({:a => 2})
|
159
|
+
bulk.insert({:a => 3})
|
160
|
+
bulk.insert({:a => 4})
|
161
|
+
bulk.insert({:a => 5})
|
162
|
+
# Update one document matching the selector
|
163
|
+
bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
|
164
|
+
# Update all documents matching the selector
|
165
|
+
bulk.find({:a => 2}).update({"$inc" => {:x => 2}})
|
166
|
+
# Replace entire document (update with whole doc replace)
|
167
|
+
bulk.find({:a => 3}).replace_one({:x => 3})
|
168
|
+
# Update one document matching the selector or upsert
|
169
|
+
bulk.find({:a => 1}).upsert.update_one({"$inc" => {:x => 1}})
|
170
|
+
# Update all documents matching the selector or upsert
|
171
|
+
bulk.find({:a => 2}).upsert.update({"$inc" => {:x => 2}})
|
172
|
+
# Replaces a single document matching the selector or upsert
|
173
|
+
bulk.find({:a => 3}).upsert.replace_one({:x => 3})
|
174
|
+
# Remove a single document matching the selector
|
175
|
+
bulk.find({:a => 4}).remove_one()
|
176
|
+
# Remove all documents matching the selector
|
177
|
+
bulk.find({:a => 5}).remove()
|
178
|
+
# Insert a document
|
179
|
+
bulk.insert({:x => 4})
|
180
|
+
end
|
181
|
+
|
182
|
+
def nil_tally_responses(responses, key)
|
183
|
+
result = {}
|
184
|
+
responses.each do |response|
|
185
|
+
@bulk.nil_tally(result, key, response[key])
|
186
|
+
end
|
187
|
+
result
|
188
|
+
end
|
189
|
+
|
190
|
+
context "Bulk API CollectionView" do
|
191
|
+
setup do
|
192
|
+
default_setup
|
193
|
+
end
|
194
|
+
|
195
|
+
# ----- INSERT -----
|
196
|
+
|
197
|
+
should "set :insert, :documents, terminate and return view for #insert" do
|
198
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
199
|
+
@collection.remove
|
200
|
+
document = {:a => 5}
|
201
|
+
result = @bulk.insert(document)
|
202
|
+
assert_is_bulk_write_collection_view(result)
|
203
|
+
assert_bulk_op_pushed [:insert, {:d => document}], @bulk
|
204
|
+
result = @bulk.execute
|
205
|
+
assert_match_document(
|
206
|
+
{
|
207
|
+
"ok" => 1,
|
208
|
+
"n" => 1,
|
209
|
+
"nInserted" => 1
|
210
|
+
}, result, "wire_version:#{wire_version}")
|
211
|
+
assert_equal 1, @collection.count
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
should "error out on $-prefixed keys with #insert" do
|
216
|
+
assert_raise BulkWriteError do
|
217
|
+
@bulk.insert({ "$key" => 1 })
|
218
|
+
@bulk.execute
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
should "attempt to run #insert with find() and succeed, ignoring find()" do
|
223
|
+
@bulk.find({}).insert({})
|
224
|
+
@bulk.execute
|
225
|
+
end
|
226
|
+
|
227
|
+
# ----- FIND -----
|
228
|
+
|
229
|
+
should "set :q and return view for #find" do
|
230
|
+
result = @bulk.find(@q)
|
231
|
+
assert_is_bulk_write_collection_view(result)
|
232
|
+
assert_equal @q, @bulk.op_args[:q]
|
233
|
+
@bulk.find({})
|
234
|
+
assert_equal({}, @bulk.op_args[:q])
|
235
|
+
@bulk.find(:a => 1)
|
236
|
+
assert_equal({:a => 1}, @bulk.op_args[:q])
|
237
|
+
end
|
238
|
+
|
239
|
+
should "raise an exception for empty #find" do
|
240
|
+
assert_raise MongoArgumentError do
|
241
|
+
@bulk.find({})
|
242
|
+
@bulk.execute
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
# ----- UPDATE -----
|
247
|
+
|
248
|
+
should "set :upsert for #upsert" do
|
249
|
+
result = @bulk.find(@q).upsert
|
250
|
+
assert_is_bulk_write_collection_view(result)
|
251
|
+
assert_true result.op_args[:upsert]
|
252
|
+
end
|
253
|
+
|
254
|
+
should "check arg for update, set :update, :u, :multi, terminate and return view for #update" do
|
255
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
256
|
+
@collection.remove
|
257
|
+
@collection.insert({:a => 1, :b => 1})
|
258
|
+
@collection.insert({:a => 2, :b => 1})
|
259
|
+
@collection.insert({:a => 2, :b => 1})
|
260
|
+
bulk = @collection.initialize_ordered_bulk_op
|
261
|
+
|
262
|
+
u = {"$inc" => {:b => 1}}
|
263
|
+
q = {:a => 2}
|
264
|
+
|
265
|
+
assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
|
266
|
+
bulk.update(u)
|
267
|
+
end
|
268
|
+
assert_raise_error(MongoArgumentError, "document must start with an operator") do
|
269
|
+
bulk.find(q).update(q)
|
270
|
+
end
|
271
|
+
|
272
|
+
result = bulk.find({:a => 2}).update(u)
|
273
|
+
assert_is_bulk_write_collection_view(result)
|
274
|
+
assert_bulk_op_pushed [:update, {:q => q, :u => u, :multi => true}], bulk
|
275
|
+
|
276
|
+
result = bulk.execute
|
277
|
+
assert_match_document(
|
278
|
+
{
|
279
|
+
"ok" => 1,
|
280
|
+
"n" => 2,
|
281
|
+
"nMatched" => 2,
|
282
|
+
"nModified" => batch_commands?(wire_version) ? 2 : nil,
|
283
|
+
}, result, "wire_version:#{wire_version}")
|
284
|
+
assert_equal 1, @collection.find({:b => 1}).count
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
# ----- UPDATE_ONE -----
|
289
|
+
|
290
|
+
should "check arg for update, set :update, :u, :multi, terminate and return view for #update_one" do
|
291
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
292
|
+
@collection.remove
|
293
|
+
@collection.insert({:a => 1})
|
294
|
+
@collection.insert({:a => 1, :b => 2})
|
295
|
+
bulk = @collection.initialize_ordered_bulk_op
|
296
|
+
|
297
|
+
assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
|
298
|
+
bulk.update_one(@u)
|
299
|
+
end
|
300
|
+
assert_raise_error(MongoArgumentError, "document must start with an operator") do
|
301
|
+
bulk.find(@q).update_one(@r)
|
302
|
+
end
|
303
|
+
result = bulk.find(@q).update_one(@u)
|
304
|
+
assert_is_bulk_write_collection_view(result)
|
305
|
+
assert_bulk_op_pushed [:update, {:q => @q, :u => @u, :multi => false}], bulk
|
306
|
+
result = bulk.execute
|
307
|
+
assert_match_document(
|
308
|
+
{
|
309
|
+
"ok" => 1,
|
310
|
+
"n" => 1,
|
311
|
+
"nMatched" => 1,
|
312
|
+
"nModified" => batch_commands?(wire_version) ? 1 : nil,
|
313
|
+
}, result, "wire_version:#{wire_version}")
|
314
|
+
assert_equal 2, @collection.count
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
should "error-out in server when $-prefixed key is passed to #update_one" do
|
319
|
+
assert_raise BulkWriteError do
|
320
|
+
oh = BSON::OrderedHash.new
|
321
|
+
oh["$key"] = 1
|
322
|
+
oh[:a] = 1
|
323
|
+
@bulk.find(@q).update(oh)
|
324
|
+
@bulk.execute
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
should "error-out in driver when first field passed to #update_one is not operator" do
|
329
|
+
assert_raise_error(MongoArgumentError, "document must start with an operator") do
|
330
|
+
oh = BSON::OrderedHash.new
|
331
|
+
oh[:a] = 1
|
332
|
+
oh["$key"] = 1
|
333
|
+
@bulk.find(@q).update(oh)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
# ----- REPLACE -----
|
338
|
+
|
339
|
+
should "raise an error when we attempt to use replace" do
|
340
|
+
assert_raise NoMethodError do
|
341
|
+
bulk = @collection.initialize_ordered_bulk_op
|
342
|
+
bulk.find({:a => 2}).replace({:a => 1})
|
343
|
+
bulk.execute
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
# ----- REPLACE_ONE -----
|
348
|
+
|
349
|
+
should "check arg for replacement, set :update, :u, :multi, terminate and return view for #replace_one" do
|
350
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
351
|
+
@collection.remove
|
352
|
+
@collection.insert({:a => 1})
|
353
|
+
@collection.insert({:a => 1})
|
354
|
+
bulk = @collection.initialize_ordered_bulk_op
|
355
|
+
q = {:a => 1}
|
356
|
+
r = {:a => 2}
|
357
|
+
|
358
|
+
assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
|
359
|
+
bulk.replace_one(q)
|
360
|
+
end
|
361
|
+
assert_raise_error(MongoArgumentError, "document must not contain any operators") do
|
362
|
+
bulk.find(q).replace_one(@u)
|
363
|
+
end
|
364
|
+
|
365
|
+
result = bulk.find(q).replace_one(r)
|
366
|
+
assert_is_bulk_write_collection_view(result)
|
367
|
+
assert_bulk_op_pushed [:update, {:q => q, :u => r, :multi => false}], bulk
|
368
|
+
|
369
|
+
result = bulk.execute
|
370
|
+
assert_match_document(
|
371
|
+
{
|
372
|
+
"ok" => 1,
|
373
|
+
"n" => 1,
|
374
|
+
"nMatched" => 1,
|
375
|
+
"nModified" => batch_commands?(wire_version) ? 1 : nil,
|
376
|
+
}, result, "wire_version:#{wire_version}")
|
377
|
+
assert_equal 1, @collection.find(q).count
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
# ----- REMOVE -----
|
382
|
+
|
383
|
+
should "remove all documents when empty selector is passed to #remove" do
|
384
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
385
|
+
@collection.insert({:a => 1})
|
386
|
+
@collection.insert({:a => 2})
|
387
|
+
@bulk.find({}).remove
|
388
|
+
result = @bulk.execute
|
389
|
+
assert_equal 0, @collection.count
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
should "#remove only documents that match selector" do
|
394
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
395
|
+
@collection.remove
|
396
|
+
@collection.insert({:a => 1})
|
397
|
+
@collection.insert({:a => 2})
|
398
|
+
@bulk.find({:a => 1}).remove
|
399
|
+
result = @bulk.execute
|
400
|
+
assert_equal 1, @collection.count
|
401
|
+
# should fail if we re-execute
|
402
|
+
assert_raise_error(MongoArgumentError, "batch is empty") do
|
403
|
+
@bulk.execute
|
404
|
+
end
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
should "set :remove, :q, :limit, terminate and return view for #remove" do
|
409
|
+
assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
|
410
|
+
@bulk.remove
|
411
|
+
end
|
412
|
+
result = @bulk.find(@q).remove
|
413
|
+
assert_is_bulk_write_collection_view(result)
|
414
|
+
assert_bulk_op_pushed [:delete, {:q => @q, :limit => 0}], @bulk
|
415
|
+
end
|
416
|
+
|
417
|
+
# ----- REMOVE_ONE -----
|
418
|
+
|
419
|
+
should "set :remove, :q, :limit, terminate and return view for #remove_one" do
|
420
|
+
assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
|
421
|
+
@bulk.remove_one
|
422
|
+
end
|
423
|
+
result = @bulk.find(@q).remove_one
|
424
|
+
assert_is_bulk_write_collection_view(result)
|
425
|
+
assert_bulk_op_pushed [:delete, {:q => @q, :limit => 1}], @bulk
|
426
|
+
end
|
427
|
+
|
428
|
+
should "remove only one of several matching documents for #remove_one" do
|
429
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
430
|
+
@collection.remove
|
431
|
+
@collection.insert({:a => 1, :b => 1})
|
432
|
+
@collection.insert({:a => 1, :b => 2})
|
433
|
+
@bulk.find({:a => 1}).remove_one
|
434
|
+
result = @bulk.execute
|
435
|
+
assert_match_document(
|
436
|
+
{
|
437
|
+
"ok" => 1,
|
438
|
+
"n" => 1,
|
439
|
+
"nRemoved" => 1,
|
440
|
+
"nModified" => nil,
|
441
|
+
}, result, "wire_version:#{wire_version}")
|
442
|
+
assert_equal 1, @collection.count
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
# ----- UPSERT-UPDATE -----
|
447
|
+
|
448
|
+
should "handle single upsert - spec Handling upserts" do # chose array always for upserted value
|
449
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
450
|
+
@collection.remove
|
451
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
452
|
+
bulk = @collection.initialize_ordered_bulk_op
|
453
|
+
|
454
|
+
assert_raise_error(MongoArgumentError, "non-nil query must be set via find") do
|
455
|
+
@bulk.upsert.update({"$set" => {:a => 1}})
|
456
|
+
end
|
457
|
+
|
458
|
+
bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
|
459
|
+
result = bulk.execute
|
460
|
+
assert_match_document(
|
461
|
+
{
|
462
|
+
"ok" => 1,
|
463
|
+
"n" => 1,
|
464
|
+
"nMatched" => 0,
|
465
|
+
"nUpserted" => 1,
|
466
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
467
|
+
"upserted" => [
|
468
|
+
{"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 0}
|
469
|
+
]
|
470
|
+
}, result, "wire_version:#{wire_version}")
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
should "run #upsert.update without affecting non-upsert updates" do
|
475
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
476
|
+
@collection.remove
|
477
|
+
|
478
|
+
bulk = @collection.initialize_unordered_bulk_op
|
479
|
+
bulk.find({:a => 1}).update({"$set" => {:x => 1}})
|
480
|
+
bulk.find({:a => 2}).upsert.update({"$set" => {:x => 2}})
|
481
|
+
result = bulk.execute
|
482
|
+
assert_match_document(
|
483
|
+
{
|
484
|
+
"ok" => 1,
|
485
|
+
"n" => 1,
|
486
|
+
"nMatched" => 0,
|
487
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
488
|
+
"nUpserted" => 1,
|
489
|
+
"upserted" => [
|
490
|
+
{"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
|
491
|
+
]
|
492
|
+
}, result, "wire_version:#{wire_version}")
|
493
|
+
|
494
|
+
# Repeat the batch and nMatched = 1, nUpserted = 0
|
495
|
+
bulk2 = @collection.initialize_unordered_bulk_op
|
496
|
+
bulk2.find({:a => 1}).update({"$set" => {:x => 1}})
|
497
|
+
bulk2.find({:a => 2}).upsert.update({"$set" => {:x => 2}})
|
498
|
+
result2 = bulk2.execute
|
499
|
+
assert_match_document(
|
500
|
+
{
|
501
|
+
"ok" => 1,
|
502
|
+
"n" => 1,
|
503
|
+
"nMatched" => 1,
|
504
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil
|
505
|
+
}, result2, "wire_version:#{wire_version}")
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
should "count nUpserted correctly when _id is not an ObjectId (upsert-update)" do
|
510
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
511
|
+
@collection.remove
|
512
|
+
|
513
|
+
bulk = @collection.initialize_unordered_bulk_op
|
514
|
+
bulk.find({:_id => 3}).upsert.update({"$set" => {:b => 3}})
|
515
|
+
result = bulk.execute
|
516
|
+
assert_match_document(
|
517
|
+
{
|
518
|
+
"ok" => 1,
|
519
|
+
"n" => 1,
|
520
|
+
"nMatched" => 0,
|
521
|
+
"nUpserted" => 1,
|
522
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
523
|
+
"upserted" => [
|
524
|
+
{ "_id" => 3, "index" => 0 }
|
525
|
+
]
|
526
|
+
}, result, "wire_version:#{wire_version}")
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
# ----- UPSERT-UPDATE_ONE -----
|
531
|
+
|
532
|
+
should "#upsert a document without affecting non-upsert update_ones" do
|
533
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
534
|
+
@collection.remove
|
535
|
+
bulk = @collection.initialize_unordered_bulk_op
|
536
|
+
|
537
|
+
bulk.find({:a => 1}).update_one({"$set" => {:x => 1}})
|
538
|
+
bulk.find({:a => 2}).upsert.update_one({"$set" => {:x => 2}})
|
539
|
+
result = bulk.execute
|
540
|
+
assert_match_document(
|
541
|
+
{
|
542
|
+
"ok" => 1,
|
543
|
+
"n" => 1,
|
544
|
+
"nMatched" => 0,
|
545
|
+
"nUpserted" => 1,
|
546
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
547
|
+
"upserted" => [
|
548
|
+
{"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
|
549
|
+
]
|
550
|
+
}, result, "wire_version:#{wire_version}")
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
should "only update one matching document with #upsert-update_one" do
|
555
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
556
|
+
@collection.remove
|
557
|
+
@collection.insert({:a => 1})
|
558
|
+
@collection.insert({:a => 1})
|
559
|
+
|
560
|
+
bulk = @collection.initialize_unordered_bulk_op
|
561
|
+
bulk.find({:a => 1}).update_one({"$set" => {:x => 1}})
|
562
|
+
result = bulk.execute
|
563
|
+
assert_match_document(
|
564
|
+
{
|
565
|
+
"ok" => 1,
|
566
|
+
"n" => 1,
|
567
|
+
"nMatched" => 1,
|
568
|
+
"nModified" => batch_commands?(wire_version) ? 1 : nil,
|
569
|
+
}, result, "wire_version:#{wire_version}")
|
570
|
+
end
|
571
|
+
end
|
572
|
+
|
573
|
+
|
574
|
+
should "count nUpserted correctly when _id is not an ObjectId (upsert-update_one)" do
|
575
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
576
|
+
@collection.remove
|
577
|
+
bulk = @collection.initialize_ordered_bulk_op
|
578
|
+
bulk.find({:_id => 2}).upsert.update_one({"$set" => {:x => 2}})
|
579
|
+
result = bulk.execute
|
580
|
+
assert_match_document(
|
581
|
+
{
|
582
|
+
"ok" => 1,
|
583
|
+
"n" => 1,
|
584
|
+
"nMatched" => 0,
|
585
|
+
"nUpserted" => 1,
|
586
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
587
|
+
"upserted" => [
|
588
|
+
{"_id" => 2, "index" => 0 }
|
589
|
+
]
|
590
|
+
}, result, "wire_version:#{wire_version}")
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
# ----- UPSERT-REPLACE_ONE -----
|
595
|
+
|
596
|
+
should "not affect non-upsert replace_ones in same batch as #upsert-replace_one" do
|
597
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
598
|
+
@collection.remove
|
599
|
+
bulk = @collection.initialize_unordered_bulk_op
|
600
|
+
bulk.find({:a => 1}).replace_one({:x => 1})
|
601
|
+
bulk.find({:a => 2}).upsert.replace_one({:x => 2})
|
602
|
+
result = bulk.execute
|
603
|
+
assert_match_document(
|
604
|
+
{
|
605
|
+
"ok" => 1,
|
606
|
+
"n" => 1,
|
607
|
+
"nMatched" => 0,
|
608
|
+
"nUpserted" => 1,
|
609
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
610
|
+
"upserted" => [
|
611
|
+
{"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
|
612
|
+
]
|
613
|
+
}, result, "wire_version:#{wire_version}")
|
614
|
+
assert_equal 1, @collection.count
|
615
|
+
end
|
616
|
+
end
|
617
|
+
|
618
|
+
should "only replace one matching document with #upsert-replace_one" do
|
619
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
620
|
+
@collection.remove
|
621
|
+
@collection.insert({:a => 1})
|
622
|
+
@collection.insert({:a => 1})
|
623
|
+
bulk = @collection.initialize_unordered_bulk_op
|
624
|
+
bulk.find({:a => 1}).replace_one({:x => 1})
|
625
|
+
bulk.find({:a => 2}).upsert.replace_one({:x => 2})
|
626
|
+
result = bulk.execute
|
627
|
+
assert_match_document(
|
628
|
+
{
|
629
|
+
"ok" => 1,
|
630
|
+
"n" => 2,
|
631
|
+
"nMatched" => 1,
|
632
|
+
"nUpserted" => 1,
|
633
|
+
"nModified" => batch_commands?(wire_version) ? 1 : nil,
|
634
|
+
"upserted" => [
|
635
|
+
{"_id" => BSON::ObjectId('52a16767bb67fbc77e26a310'), "index" => 1}
|
636
|
+
]
|
637
|
+
}, result, "wire_version:#{wire_version}")
|
638
|
+
assert_equal 3, @collection.count
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
should "tally given all numbers or return nil for #nil_tally" do
|
643
|
+
assert_equal({"nM" => 6}, nil_tally_responses([{"nM" => 1}, {"nM" => 2}, {"nM" => 3}], "nM"))
|
644
|
+
assert_equal({"nM" => nil}, nil_tally_responses([{"nM" => 1}, { }, {"nM" => 3}], "nM"))
|
645
|
+
assert_equal({"nM" => nil}, nil_tally_responses([{"nM" => 1}, {"nM" => nil}, {"nM" => 3}], "nM"))
|
646
|
+
end
|
647
|
+
|
648
|
+
|
649
|
+
should "count nUpserted correctly when _id is not an ObjectId (upsert-replace_one)" do
|
650
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
651
|
+
@collection.remove
|
652
|
+
bulk = @collection.initialize_unordered_bulk_op
|
653
|
+
bulk.find({:a => 1}).upsert.replace_one({:_id => 2})
|
654
|
+
result = bulk.execute
|
655
|
+
assert_match_document(
|
656
|
+
{
|
657
|
+
"ok" => 1,
|
658
|
+
"n" => 1,
|
659
|
+
"nMatched" => 0,
|
660
|
+
"nUpserted" => 1,
|
661
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
662
|
+
"upserted" => [
|
663
|
+
{ "_id" => 2, "index" => 0 }
|
664
|
+
]
|
665
|
+
}, result, "wire_version:#{wire_version}")
|
666
|
+
assert_equal 1, @collection.count
|
667
|
+
end
|
668
|
+
end
|
669
|
+
|
670
|
+
# ----- MIXED OPS, ORDERED -----
|
671
|
+
|
672
|
+
should "execute, return result and reset @ops for #execute" do
|
673
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
674
|
+
@collection.remove
|
675
|
+
@bulk.insert({:x => 1})
|
676
|
+
@bulk.insert({:x => 2})
|
677
|
+
write_concern = {:w => 1}
|
678
|
+
result = @bulk.execute(write_concern)
|
679
|
+
assert_equal({"ok" => 1, "n" => 2, "nInserted" => 2}, result, "wire_version:#{wire_version}")
|
680
|
+
assert_equal 2, @collection.count
|
681
|
+
assert_equal [], @bulk.ops
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
should "run ordered big example" do
|
686
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
687
|
+
@collection.remove
|
688
|
+
big_example(@bulk)
|
689
|
+
write_concern = {:w => 1} #{:w => 1. :j => 1} #nojournal for tests
|
690
|
+
result = @bulk.execute(write_concern)
|
691
|
+
assert_match_document(
|
692
|
+
{
|
693
|
+
"ok" => 1,
|
694
|
+
"n" => 14,
|
695
|
+
"nInserted" => 6,
|
696
|
+
"nMatched" => 5,
|
697
|
+
"nUpserted" => 1,
|
698
|
+
"nModified" => batch_commands?(wire_version) ? 5 : nil,
|
699
|
+
"nRemoved" => 2,
|
700
|
+
"upserted" => [
|
701
|
+
{
|
702
|
+
"index" => 10,
|
703
|
+
"_id" => BSON::ObjectId('52a1e4a4bb67fbc77e26a340')
|
704
|
+
}
|
705
|
+
]
|
706
|
+
}, result, "wire_version:#{wire_version}")
|
707
|
+
assert_equal(batch_commands?(wire_version), result.has_key?("nModified"), "wire_version:#{wire_version}")
|
708
|
+
assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
|
709
|
+
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 })
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
should "run spec Ordered Bulk Operations" do
|
714
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
715
|
+
@bulk.insert({:a => 1})
|
716
|
+
@bulk.insert({:a => 2})
|
717
|
+
@bulk.insert({:a => 3})
|
718
|
+
@bulk.find({:a => 2}).upsert.update({'$set' => {:a => 4}})
|
719
|
+
@bulk.find({:a => 1}).remove_one
|
720
|
+
@bulk.insert({:a => 5})
|
721
|
+
result = @bulk.execute({:w => 1})
|
722
|
+
assert_match_document(
|
723
|
+
{
|
724
|
+
"ok" => 1,
|
725
|
+
"n" => 6,
|
726
|
+
"nInserted" => 4,
|
727
|
+
"nMatched" => 1,
|
728
|
+
"nModified" => batch_commands?(wire_version) ? 1 : nil,
|
729
|
+
"nRemoved" => 1,
|
730
|
+
}, result, "wire_version:#{wire_version}")
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
734
|
+
# ----- MIXED OPS, UNORDERED -----
|
735
|
+
|
736
|
+
should "run unordered big example" do
|
737
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
738
|
+
@collection.remove
|
739
|
+
@bulk = @collection.initialize_unordered_bulk_op
|
740
|
+
big_example(@bulk)
|
741
|
+
write_concern = {:w => 1} #{:w => 1. :j => 1} #nojournal for tests
|
742
|
+
result = @bulk.execute(write_concern)
|
743
|
+
assert_equal(6, result["nInserted"])
|
744
|
+
assert_true(result["n"] > 0, "wire_version:#{wire_version}")
|
745
|
+
assert_equal(batch_commands?(wire_version), result.has_key?("nModified"), "wire_version:#{wire_version}")
|
746
|
+
assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
should "run unordered big example with w 0" do
|
751
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
752
|
+
@collection.remove
|
753
|
+
@bulk = @collection.initialize_unordered_bulk_op
|
754
|
+
big_example(@bulk)
|
755
|
+
write_concern = {:w => 0}
|
756
|
+
result = @bulk.execute(write_concern)
|
757
|
+
assert_equal(true, result, "wire_version:#{wire_version}")
|
758
|
+
assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
should "run unordered bulk operations in one batch per write-type" do
|
763
|
+
with_write_commands(@db.connection) do
|
764
|
+
@collection.expects(:batch_write).at_most(3).returns([[], [], [], []])
|
765
|
+
bulk = @collection.initialize_unordered_bulk_op
|
766
|
+
bulk.insert({:_id => 1, :a => 1})
|
767
|
+
bulk.find({:_id => 1, :a => 1}).update({"$inc" => {:x => 1}})
|
768
|
+
bulk.find({:_id => 1, :a => 1}).remove
|
769
|
+
bulk.insert({:_id => 2, :a => 2})
|
770
|
+
bulk.find({:_id => 2, :a => 2}).update({"$inc" => {:x => 2}})
|
771
|
+
bulk.find({:_id => 2, :a => 2}).remove
|
772
|
+
bulk.insert({:_id => 3, :a => 3})
|
773
|
+
bulk.find({:_id => 3, :a => 3}).update({"$inc" => {:x => 3}})
|
774
|
+
bulk.find({:_id => 3, :a => 3}).remove
|
775
|
+
result = bulk.execute # unordered varies, don't use assert_match_document
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
should "run spec Unordered Bulk Operations" do
|
780
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
781
|
+
bulk = @collection.initialize_unordered_bulk_op
|
782
|
+
bulk.insert({:_id => 1})
|
783
|
+
bulk.find({:_id => 2}).update_one({'$inc' => { :x => 1 }})
|
784
|
+
bulk.find({:_id => 3}).remove_one
|
785
|
+
bulk.insert({:_id => 4})
|
786
|
+
bulk.find({:_id => 5}).update_one({'$inc' => { :x => 1 }})
|
787
|
+
bulk.find({:_id => 6}).remove_one
|
788
|
+
result = nil
|
789
|
+
begin
|
790
|
+
result = bulk.execute
|
791
|
+
rescue => ex
|
792
|
+
result = ex.result
|
793
|
+
end
|
794
|
+
# for write commands internally the driver will execute 3. One each for the inserts, updates and removes.
|
795
|
+
end
|
796
|
+
end
|
797
|
+
|
798
|
+
# ----- EMPTY BATCH -----
|
799
|
+
|
800
|
+
should "handle empty bulk op" do
|
801
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
802
|
+
assert_raise_error(MongoArgumentError, Mongo::BulkWriteCollectionView::EMPTY_BATCH_MSG) do
|
803
|
+
@bulk.execute
|
804
|
+
end
|
805
|
+
end
|
806
|
+
end
|
807
|
+
|
808
|
+
should "handle insert of overly large document" do
|
809
|
+
large_doc = {"a" => "y"*(2*@client.max_message_size)}
|
810
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
811
|
+
ex = assert_raise Mongo::BulkWriteError do
|
812
|
+
@collection.remove
|
813
|
+
bulk = @collection.initialize_unordered_bulk_op
|
814
|
+
bulk.insert(large_doc)
|
815
|
+
puts "bulk.execute:#{bulk.execute.inspect}"
|
816
|
+
end
|
817
|
+
assert_equal 22, ex.result["writeErrors"].first["code"]
|
818
|
+
end
|
819
|
+
end
|
820
|
+
|
821
|
+
# ----- ORDERED, WITH ERRORS -----
|
822
|
+
|
823
|
+
should "handle error for duplicate key with offset" do
|
824
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
825
|
+
@collection.remove
|
826
|
+
@bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
|
827
|
+
@bulk.insert({:_id => 1, :a => 1})
|
828
|
+
@bulk.insert({:_id => 1, :a => 2})
|
829
|
+
@bulk.insert({:_id => 3, :a => 3})
|
830
|
+
ex = assert_raise BulkWriteError do
|
831
|
+
@bulk.execute
|
832
|
+
end
|
833
|
+
result = ex.result
|
834
|
+
assert_match_document(
|
835
|
+
{
|
836
|
+
"ok" => 1,
|
837
|
+
"n" => 1,
|
838
|
+
"writeErrors" =>
|
839
|
+
[{
|
840
|
+
"index" => 2,
|
841
|
+
"code" => 11000,
|
842
|
+
"errmsg" => /duplicate key error/
|
843
|
+
}],
|
844
|
+
"code" => 65,
|
845
|
+
"errmsg" => "batch item errors occurred",
|
846
|
+
"nInserted" => 1,
|
847
|
+
"nMatched" => 0,
|
848
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil
|
849
|
+
}, result, "wire_version:#{wire_version}")
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
should "handle error for serialization with offset" do
|
854
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
855
|
+
@collection.remove
|
856
|
+
assert_equal 16777216, @client.max_bson_size
|
857
|
+
@bulk.find({:a => 1}).update_one({"$inc" => {:x => 1}})
|
858
|
+
@bulk.insert({:_id => 1, :a => 1})
|
859
|
+
@bulk.insert(generate_sized_doc(@client.max_message_size + 1))
|
860
|
+
@bulk.insert({:_id => 3, :a => 3})
|
861
|
+
ex = assert_raise BulkWriteError do
|
862
|
+
@bulk.execute
|
863
|
+
end
|
864
|
+
result = ex.result
|
865
|
+
assert_match_document(
|
866
|
+
{
|
867
|
+
"ok" => 1,
|
868
|
+
"n" => 1,
|
869
|
+
"writeErrors" =>
|
870
|
+
[{
|
871
|
+
"index" => 2,
|
872
|
+
"code" => 22,
|
873
|
+
"errmsg" => /too large/
|
874
|
+
}],
|
875
|
+
"code" => 65,
|
876
|
+
"errmsg" => "batch item errors occurred",
|
877
|
+
"nInserted" => 1,
|
878
|
+
"nMatched" => 0,
|
879
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil
|
880
|
+
}, result, "wire_version:#{wire_version}")
|
881
|
+
end
|
882
|
+
end
|
883
|
+
|
884
|
+
should "run ordered bulk op - spec Modes of Execution" do
|
885
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
886
|
+
@collection.remove
|
887
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
888
|
+
@bulk.insert({:a => 1})
|
889
|
+
@bulk.insert({:a => 2})
|
890
|
+
@bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
|
891
|
+
@bulk.find({:a => 1}).remove
|
892
|
+
ex = assert_raise BulkWriteError do
|
893
|
+
@bulk.execute
|
894
|
+
end
|
895
|
+
assert_equal(2, @collection.count)
|
896
|
+
end
|
897
|
+
end
|
898
|
+
|
899
|
+
should "handle duplicate key error - spec Merging Results" do
|
900
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
901
|
+
@collection.remove
|
902
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
903
|
+
bulk = @collection.initialize_ordered_bulk_op
|
904
|
+
bulk.insert({:a => 1})
|
905
|
+
bulk.insert({:a => 2})
|
906
|
+
bulk.find({:a => 2}).upsert.update({'$set' => {:a => 1}})
|
907
|
+
bulk.insert({:a => 3})
|
908
|
+
ex = assert_raise BulkWriteError do
|
909
|
+
bulk.execute
|
910
|
+
end
|
911
|
+
result = ex.result
|
912
|
+
assert_match_document(
|
913
|
+
{
|
914
|
+
"ok" => 1,
|
915
|
+
"n" => 2,
|
916
|
+
"writeErrors" =>
|
917
|
+
[{
|
918
|
+
"index" => 2,
|
919
|
+
"code" => DUPLICATE_KEY_ERROR_CODE_SET,
|
920
|
+
"errmsg" => /duplicate key error/
|
921
|
+
}],
|
922
|
+
"code" => 65,
|
923
|
+
"errmsg" => "batch item errors occurred",
|
924
|
+
"nInserted" => 2,
|
925
|
+
"nMatched" => 0,
|
926
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil
|
927
|
+
}, result, "wire_version:#{wire_version}")
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
should "report user index - spec Merging errors" do
|
932
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
933
|
+
@collection.remove
|
934
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
935
|
+
bulk = @collection.initialize_ordered_bulk_op
|
936
|
+
bulk.insert({:a => 1})
|
937
|
+
bulk.insert({:a => 2})
|
938
|
+
bulk.find({:a => 2}).update_one({'$set' => {:a => 1}});
|
939
|
+
bulk.find({:a => 4}).remove_one();
|
940
|
+
ex = assert_raise BulkWriteError do
|
941
|
+
bulk.execute({:w => 1})
|
942
|
+
end
|
943
|
+
result = ex.result
|
944
|
+
assert_match_document(
|
945
|
+
{
|
946
|
+
"ok" => 1,
|
947
|
+
"n" => 2,
|
948
|
+
"writeErrors" =>
|
949
|
+
[{
|
950
|
+
"index" => 2,
|
951
|
+
"code" => DUPLICATE_KEY_ERROR_CODE_SET,
|
952
|
+
"errmsg" => /duplicate key error/
|
953
|
+
}],
|
954
|
+
"code" => 65,
|
955
|
+
"errmsg" => "batch item errors occurred",
|
956
|
+
"nInserted" => 2,
|
957
|
+
"nMatched" => 0,
|
958
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil
|
959
|
+
}, result, "wire_version:#{wire_version}")
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
should "handle multiple upsert - spec Handling upserts" do
|
964
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
965
|
+
@collection.remove
|
966
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
967
|
+
bulk = @collection.initialize_ordered_bulk_op
|
968
|
+
bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
|
969
|
+
bulk.find({:a => 3}).upsert.update({'$set' => {:a => 4}})
|
970
|
+
result = bulk.execute
|
971
|
+
assert_match_document(
|
972
|
+
{
|
973
|
+
"ok" => 1,
|
974
|
+
"n" => 2,
|
975
|
+
"nMatched" => 0,
|
976
|
+
"nUpserted" => 2,
|
977
|
+
"nModified" => batch_commands?(wire_version) ? 0 : nil,
|
978
|
+
"upserted" => [
|
979
|
+
{"index" => 0, "_id" => BSON::ObjectId('52a1e37cbb67fbc77e26a338')},
|
980
|
+
{"index" => 1, "_id" => BSON::ObjectId('52a1e37cbb67fbc77e26a339')}
|
981
|
+
]
|
982
|
+
}, result, "wire_version:#{wire_version}")
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
986
|
+
should "handle replication usage error" do
|
987
|
+
with_no_replication(@db.connection) do
|
988
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
989
|
+
@collection.remove
|
990
|
+
@bulk = @collection.initialize_ordered_bulk_op
|
991
|
+
@bulk.insert({:_id => 1, :a => 1})
|
992
|
+
write_concern = {:w => 5}
|
993
|
+
ex = assert_raise BulkWriteError do
|
994
|
+
@bulk.execute(write_concern)
|
995
|
+
end
|
996
|
+
result = ex.result
|
997
|
+
if @version >= "2.5.5"
|
998
|
+
assert_match_document(
|
999
|
+
{
|
1000
|
+
"ok" => 0,
|
1001
|
+
"n" => 0,
|
1002
|
+
"code" => 65,
|
1003
|
+
"errmsg" => "batch item errors occurred",
|
1004
|
+
"writeErrors" => [
|
1005
|
+
{
|
1006
|
+
"errmsg" => "cannot use 'w' > 1 when a host is not replicated",
|
1007
|
+
"code" => 2,
|
1008
|
+
"index" => 0}
|
1009
|
+
],
|
1010
|
+
"nInserted" => 0,
|
1011
|
+
}, result, "wire_version:#{wire_version}")
|
1012
|
+
else
|
1013
|
+
assert_match_document(
|
1014
|
+
{
|
1015
|
+
"ok" => 1,
|
1016
|
+
"n" => 1,
|
1017
|
+
"code" => 65,
|
1018
|
+
"errmsg" => "batch item errors occurred",
|
1019
|
+
"writeConcernError" => [
|
1020
|
+
{
|
1021
|
+
"errmsg" => /no replication has been enabled/,
|
1022
|
+
"code" => 64,
|
1023
|
+
"index" => 0
|
1024
|
+
}
|
1025
|
+
],
|
1026
|
+
"nInserted" => 1,
|
1027
|
+
}, result, "wire_version:#{wire_version}")
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
end
|
1032
|
+
|
1033
|
+
# ----- UNORDERED, WITH ERRORS -----
|
1034
|
+
|
1035
|
+
should "handle error for unordered multiple duplicate key with offset" do
|
1036
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1037
|
+
@collection.remove
|
1038
|
+
@bulk = @collection.initialize_unordered_bulk_op
|
1039
|
+
@bulk.find({:a => 1}).remove
|
1040
|
+
@bulk.insert({:_id => 1, :a => 1})
|
1041
|
+
@bulk.insert({:_id => 1, :a => 2})
|
1042
|
+
@bulk.insert({:_id => 3, :a => 3})
|
1043
|
+
@bulk.insert({:_id => 3, :a => 3})
|
1044
|
+
ex = assert_raise BulkWriteError do
|
1045
|
+
@bulk.execute
|
1046
|
+
end
|
1047
|
+
result = ex.result
|
1048
|
+
assert_true (0 < result["nInserted"] && result["nInserted"] < 3)
|
1049
|
+
assert_not_nil(result["writeErrors"], "wire_version:#{wire_version}")
|
1050
|
+
end
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
should "run unordered bulk op - spec Modes of Execution" do
|
1054
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1055
|
+
@collection.remove
|
1056
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
1057
|
+
bulk = @collection.initialize_unordered_bulk_op
|
1058
|
+
bulk.insert({:a => 1})
|
1059
|
+
bulk.insert({:a => 2})
|
1060
|
+
bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
|
1061
|
+
bulk.find({:a => 3}).remove
|
1062
|
+
bulk.find({:a => 2}).update({'$set' => {:a => 1}}) # Clashes with unique index
|
1063
|
+
ex = assert_raise BulkWriteError do
|
1064
|
+
bulk.execute
|
1065
|
+
end
|
1066
|
+
result = ex.result
|
1067
|
+
assert(result["writeErrors"].size > 1, "wire_version:#{wire_version}")
|
1068
|
+
end
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
should "handle unordered errors - spec Merging Results" do
|
1072
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1073
|
+
@collection.remove
|
1074
|
+
@collection.ensure_index(BSON::OrderedHash[:a, Mongo::ASCENDING], {:unique => true})
|
1075
|
+
bulk = @collection.initialize_unordered_bulk_op
|
1076
|
+
bulk.insert({:a => 1})
|
1077
|
+
bulk.find({:a => 1}).upsert.update({'$set' => {:a => 2}})
|
1078
|
+
bulk.insert({:a => 2})
|
1079
|
+
ex = assert_raise BulkWriteError do
|
1080
|
+
bulk.execute
|
1081
|
+
end
|
1082
|
+
result = ex.result # unordered varies, don't use assert_bulk_exception
|
1083
|
+
assert_equal(1, result['ok'], "wire_version:#{wire_version}")
|
1084
|
+
assert_equal(2, result['n'], "wire_version:#{wire_version}")
|
1085
|
+
err_details = result['writeErrors']
|
1086
|
+
assert_match(/duplicate key error/, err_details.first['errmsg'], "wire_version:#{wire_version}")
|
1087
|
+
end
|
1088
|
+
end
|
1089
|
+
|
1090
|
+
should "handle multiple errors for unordered bulk write" do
|
1091
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1092
|
+
@collection.remove
|
1093
|
+
@bulk = @collection.initialize_unordered_bulk_op
|
1094
|
+
@bulk.insert({:_id => 1, :a => 1})
|
1095
|
+
@bulk.insert({:_id => 1, :a => 2})
|
1096
|
+
@bulk.insert(generate_sized_doc(@client.max_message_size + 1))
|
1097
|
+
@bulk.insert({:_id => 3, :a => 3})
|
1098
|
+
@bulk.find({:a => 4}).upsert.replace_one({:x => 3})
|
1099
|
+
ex = assert_raise BulkWriteError do
|
1100
|
+
@bulk.execute
|
1101
|
+
end
|
1102
|
+
result = ex.result # unordered varies, don't use assert_bulk_exception
|
1103
|
+
assert_equal(1, result['ok'], "wire_version:#{wire_version}")
|
1104
|
+
assert_equal(3, result['n'], "wire_version:#{wire_version}")
|
1105
|
+
err_details = result['writeErrors']
|
1106
|
+
assert_match(/duplicate key error/, err_details.find { |e| e['code']==11000 }['errmsg'], "wire_version:#{wire_version}")
|
1107
|
+
assert_match(/too large/, err_details.find { |e| e['index']==2 }['errmsg'], "wire_version:#{wire_version}")
|
1108
|
+
assert_not_nil(result['upserted'].find { |e| e['index']==4 }, "wire_version:#{wire_version}")
|
1109
|
+
end
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
# ----- NO_JOURNAL -----
|
1113
|
+
|
1114
|
+
should "handle journaling error" do
|
1115
|
+
with_no_journaling(@db.connection) do
|
1116
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1117
|
+
@collection.remove
|
1118
|
+
@bulk = @collection.initialize_ordered_bulk_op
|
1119
|
+
@bulk.insert({:_id => 1, :a => 1})
|
1120
|
+
write_concern = {:w => 1, :j => 1}
|
1121
|
+
ex = assert_raise BulkWriteError do
|
1122
|
+
@bulk.execute(write_concern)
|
1123
|
+
end
|
1124
|
+
result = ex.result
|
1125
|
+
if @version >= "2.5.5"
|
1126
|
+
assert_match_document(
|
1127
|
+
{
|
1128
|
+
"ok" => 0,
|
1129
|
+
"n" => 0,
|
1130
|
+
"writeErrors" => [
|
1131
|
+
{
|
1132
|
+
"code" => 2,
|
1133
|
+
"errmsg" => "cannot use 'j' option when a host does not have journaling enabled", "index" => 0
|
1134
|
+
}
|
1135
|
+
],
|
1136
|
+
"code" => 65,
|
1137
|
+
"errmsg" => "batch item errors occurred",
|
1138
|
+
"nInserted" => 0
|
1139
|
+
}, result, "wire_version:#{wire_version}")
|
1140
|
+
else
|
1141
|
+
assert_match_document(
|
1142
|
+
{
|
1143
|
+
"ok" => 1,
|
1144
|
+
"n" => 1,
|
1145
|
+
"writeConcernError" => [
|
1146
|
+
{
|
1147
|
+
"code" => 2,
|
1148
|
+
"errmsg" => "journaling not enabled on this server",
|
1149
|
+
"index" => 0
|
1150
|
+
}
|
1151
|
+
],
|
1152
|
+
"code" => 65,
|
1153
|
+
"errmsg" => "batch item errors occurred",
|
1154
|
+
"nInserted" => 1
|
1155
|
+
}, result, "wire_version:#{wire_version}")
|
1156
|
+
end
|
1157
|
+
end
|
1158
|
+
end
|
1159
|
+
end
|
1160
|
+
|
1161
|
+
# ----- W = 0 -----
|
1162
|
+
|
1163
|
+
should "run ordered big example with w 0" do
|
1164
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1165
|
+
@collection.remove
|
1166
|
+
big_example(@bulk)
|
1167
|
+
result = @bulk.execute({:w => 0})
|
1168
|
+
assert_equal(true, result, "wire_version:#{wire_version}")
|
1169
|
+
assert_false(@collection.find.to_a.empty?, "wire_version:#{wire_version}")
|
1170
|
+
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 })
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
|
1174
|
+
should "running with w 0 should not report write errors" do
|
1175
|
+
with_write_commands_and_operations(@db.connection) do
|
1176
|
+
@bulk.insert({:_id => 1, :a => 1 })
|
1177
|
+
@bulk.insert({:_id => 1, :a => 2 })
|
1178
|
+
@bulk.execute({:w => 0}) # should raise no duplicate key error
|
1179
|
+
end
|
1180
|
+
end
|
1181
|
+
|
1182
|
+
# ----- W > 0 WITH STANDALONE -----
|
1183
|
+
|
1184
|
+
should "disallow w > 0 against a standalone" do
|
1185
|
+
with_write_commands_and_operations(@db.connection) do |wire_version|
|
1186
|
+
@collection.remove
|
1187
|
+
@bulk.insert({:_id => 1, :a => 1 })
|
1188
|
+
@bulk.insert({:_id => 2, :a => 1 })
|
1189
|
+
@bulk.insert({:_id => 3, :a => 1 })
|
1190
|
+
assert_raise_error BulkWriteError do
|
1191
|
+
@bulk.execute({:w => 2})
|
1192
|
+
end
|
1193
|
+
assert (@collection.count == batch_commands?(wire_version) ? 0 : 1)
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
|
1197
|
+
end
|
1198
|
+
end
|