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,2175 @@
|
|
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 'rbconfig'
|
16
|
+
require 'test_helper'
|
17
|
+
|
18
|
+
class CollectionTest < Test::Unit::TestCase
|
19
|
+
|
20
|
+
LIMITED_MAX_BSON_SIZE = 1024
|
21
|
+
LIMITED_BSON_SIZE_WITH_HEADROOM = LIMITED_MAX_BSON_SIZE + MongoClient::APPEND_HEADROOM
|
22
|
+
LIMITED_MAX_MESSAGE_SIZE = 3 * LIMITED_MAX_BSON_SIZE
|
23
|
+
LIMITED_TEST_HEADROOM = 50
|
24
|
+
LIMITED_VALID_VALUE_SIZE = LIMITED_MAX_BSON_SIZE - LIMITED_TEST_HEADROOM
|
25
|
+
LIMITED_INVALID_VALUE_SIZE = LIMITED_MAX_BSON_SIZE + Mongo::MongoClient::COMMAND_HEADROOM + 1
|
26
|
+
|
27
|
+
def setup
|
28
|
+
@client ||= standard_connection(:op_timeout => 10)
|
29
|
+
@db = @client.db(TEST_DB)
|
30
|
+
@test = @db.collection("test")
|
31
|
+
@version = @client.server_version
|
32
|
+
@test.remove
|
33
|
+
@ismaster = @client['admin'].command(:isMaster => 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
@@wv0 = Mongo::MongoClient::RELEASE_2_4_AND_BEFORE
|
37
|
+
@@wv2 = Mongo::MongoClient::BATCH_COMMANDS
|
38
|
+
@@a_h = Mongo::MongoClient::APPEND_HEADROOM
|
39
|
+
@@s_h = Mongo::MongoClient::SERIALIZE_HEADROOM
|
40
|
+
|
41
|
+
def max_size_exception_test(client)
|
42
|
+
base = [
|
43
|
+
#[@@wv0, client.max_bson_size, nil, /xyzzy/], # succeeds standalone, fails whole suite
|
44
|
+
]
|
45
|
+
base += max_size_exception_cruby_test(client) unless RUBY_PLATFORM == 'java'
|
46
|
+
#base += max_size_exception_jruby_test if RUBY_PLATFORM == 'java'
|
47
|
+
base += max_size_exception_commands_test(client) if @version >= '2.5.2'
|
48
|
+
base
|
49
|
+
end
|
50
|
+
|
51
|
+
def max_size_exception_cruby_test(client)
|
52
|
+
[
|
53
|
+
[@@wv0, client.max_bson_size + 1, BSON::InvalidDocument, /Document.* too large/]
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
def max_size_exception_jruby_test(client)
|
58
|
+
[@@wv0, client.max_bson_size + 1, Mongo::OperationFailure, /object to insert too large/]
|
59
|
+
end
|
60
|
+
|
61
|
+
def max_size_exception_commands_test(client)
|
62
|
+
[
|
63
|
+
#[@@wv2, client.max_bson_size, nil, /xyzzy/], # succeeds standalone, fails whole suite
|
64
|
+
[@@wv2, client.max_bson_size + 1, Mongo::OperationFailure, /object to insert too large/],
|
65
|
+
[@@wv2, client.max_bson_size + @@s_h, Mongo::OperationFailure, /object to insert too large/],
|
66
|
+
[@@wv2, client.max_bson_size + @@a_h, BSON::InvalidDocument, /Document.* too large/]
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
def generate_sized_doc(size)
|
71
|
+
doc = {"_id" => BSON::ObjectId.new, "x" => "y"}
|
72
|
+
serialize_doc = BSON::BSON_CODER.serialize(doc, false, false, size)
|
73
|
+
doc = {"_id" => BSON::ObjectId.new, "x" => "y" * (1 + size - serialize_doc.size)}
|
74
|
+
assert_equal size, BSON::BSON_CODER.serialize(doc, false, false, size).size
|
75
|
+
doc
|
76
|
+
end
|
77
|
+
|
78
|
+
def with_max_wire_version(client, wire_version) # does not support replica sets
|
79
|
+
if client.wire_version_feature?(wire_version)
|
80
|
+
client.class.class_eval(%Q{
|
81
|
+
alias :old_max_wire_version :max_wire_version
|
82
|
+
def max_wire_version
|
83
|
+
#{wire_version}
|
84
|
+
end
|
85
|
+
})
|
86
|
+
yield wire_version
|
87
|
+
client.class.class_eval(%Q{
|
88
|
+
alias :max_wire_version :old_max_wire_version
|
89
|
+
})
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_insert_batch_max_sizes
|
94
|
+
max_size_exception_test(@client).each do |wire_version, size, exc, regexp|
|
95
|
+
with_max_wire_version(@client, wire_version) do
|
96
|
+
@test.remove
|
97
|
+
doc = generate_sized_doc(size)
|
98
|
+
begin
|
99
|
+
@test.insert([doc.dup])
|
100
|
+
assert_equal nil, exc
|
101
|
+
rescue => e
|
102
|
+
assert_equal exc, e.class, "wire_version:#{wire_version}, size:#{size}, exc:#{exc} e:#{e.message.inspect} @version:#{@version}"
|
103
|
+
assert_match regexp, e.message
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_single_delete_write_command
|
110
|
+
return unless @version >= '2.5.4'
|
111
|
+
@test.drop
|
112
|
+
@test.insert([{ :a => 1 }, { :a => 1 }])
|
113
|
+
|
114
|
+
command = BSON::OrderedHash['delete', @test.name,
|
115
|
+
:deletes, [{ :q => { :a => 1 }, :limit => 1 }],
|
116
|
+
:writeConcern, { :w => 1 },
|
117
|
+
:ordered, false]
|
118
|
+
|
119
|
+
result = @db.command(command)
|
120
|
+
assert_equal 1, result['n']
|
121
|
+
assert_equal 1, result['ok']
|
122
|
+
assert_equal 1, @test.count
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_multi_ordered_delete_write_command
|
126
|
+
return unless @version >= '2.5.4'
|
127
|
+
@test.drop
|
128
|
+
@test.insert([{ :a => 1 }, { :a => 1 }])
|
129
|
+
|
130
|
+
command = BSON::OrderedHash['delete', @test.name,
|
131
|
+
:deletes, [{ :q => { :a => 1 }, :limit => 0 }],
|
132
|
+
:writeConcern, { :w => 1 },
|
133
|
+
:ordered, true]
|
134
|
+
|
135
|
+
result = @db.command(command)
|
136
|
+
assert_equal 2, result['n']
|
137
|
+
assert_equal 1, result['ok']
|
138
|
+
assert_equal 0, @test.count
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_multi_unordered_delete_write_command
|
142
|
+
return unless @version >= '2.5.4'
|
143
|
+
@test.drop
|
144
|
+
@test.insert([{ :a => 1 }, { :a => 1 }])
|
145
|
+
|
146
|
+
command = BSON::OrderedHash['delete', @test.name,
|
147
|
+
:deletes, [{ :q => { :a => 1 }, :limit => 0 }],
|
148
|
+
:writeConcern, { :w => 1 },
|
149
|
+
:ordered, false]
|
150
|
+
|
151
|
+
result = @db.command(command)
|
152
|
+
assert_equal 2, result['n']
|
153
|
+
assert_equal 1, result['ok']
|
154
|
+
assert_equal 0, @test.count
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_delete_write_command_with_no_concern
|
158
|
+
return unless @version >= '2.5.4'
|
159
|
+
@test.drop
|
160
|
+
@test.insert([{ :a => 1 }, { :a => 1 }])
|
161
|
+
|
162
|
+
command = BSON::OrderedHash['delete', @test.name,
|
163
|
+
:deletes, [{ :q => { :a => 1 }, :limit => 0 }],
|
164
|
+
:ordered, false]
|
165
|
+
|
166
|
+
result = @db.command(command)
|
167
|
+
assert_equal 2, result['n']
|
168
|
+
assert_equal 1, result['ok']
|
169
|
+
assert_equal 0, @test.count
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_delete_write_command_with_error
|
173
|
+
return unless @version >= '2.5.4'
|
174
|
+
@test.drop
|
175
|
+
@test.insert([{ :a => 1 }, { :a => 1 }])
|
176
|
+
|
177
|
+
command = BSON::OrderedHash['delete', @test.name,
|
178
|
+
:deletes, [{ :q => { '$set' => { :a => 1 }}, :limit => 0 }],
|
179
|
+
:writeConcern, { :w => 1 },
|
180
|
+
:ordered, false]
|
181
|
+
|
182
|
+
assert_raise Mongo::OperationFailure do
|
183
|
+
@db.command(command)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_single_insert_write_command
|
188
|
+
return unless @version >= '2.5.4'
|
189
|
+
@test.drop
|
190
|
+
|
191
|
+
command = BSON::OrderedHash['insert', @test.name,
|
192
|
+
:documents, [{ :a => 1 }],
|
193
|
+
:writeConcern, { :w => 1 },
|
194
|
+
:ordered, false]
|
195
|
+
|
196
|
+
result = @db.command(command)
|
197
|
+
assert_equal 1, result['ok']
|
198
|
+
assert_equal 1, @test.count
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_multi_ordered_insert_write_command
|
202
|
+
return unless @version >= '2.5.4'
|
203
|
+
@test.drop
|
204
|
+
|
205
|
+
command = BSON::OrderedHash['insert', @test.name,
|
206
|
+
:documents, [{ :a => 1 }, { :a => 2 }],
|
207
|
+
:writeConcern, { :w => 1 },
|
208
|
+
:ordered, true]
|
209
|
+
|
210
|
+
result = @db.command(command)
|
211
|
+
assert_equal 1, result['ok']
|
212
|
+
assert_equal 2, @test.count
|
213
|
+
end
|
214
|
+
|
215
|
+
def test_multi_unordered_insert_write_command
|
216
|
+
return unless @version >= '2.5.4'
|
217
|
+
@test.drop
|
218
|
+
|
219
|
+
command = BSON::OrderedHash['insert', @test.name,
|
220
|
+
:documents, [{ :a => 1 }, { :a => 2 }],
|
221
|
+
:writeConcern, { :w => 1 },
|
222
|
+
:ordered, false]
|
223
|
+
|
224
|
+
result = @db.command(command)
|
225
|
+
assert_equal 1, result['ok']
|
226
|
+
assert_equal 2, @test.count
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_insert_write_command_with_no_concern
|
230
|
+
return unless @version >= '2.5.4'
|
231
|
+
@test.drop
|
232
|
+
|
233
|
+
command = BSON::OrderedHash['insert', @test.name,
|
234
|
+
:documents, [{ :a => 1 }, { :a => 2 }],
|
235
|
+
:ordered, false]
|
236
|
+
|
237
|
+
result = @db.command(command)
|
238
|
+
assert_equal 1, result['ok']
|
239
|
+
assert_equal 2, @test.count
|
240
|
+
end
|
241
|
+
|
242
|
+
def test_insert_write_command_with_error
|
243
|
+
return unless @version >= '2.5.4'
|
244
|
+
@test.drop
|
245
|
+
@test.ensure_index([[:a, 1]], { :unique => true })
|
246
|
+
|
247
|
+
command = BSON::OrderedHash['insert', @test.name,
|
248
|
+
:documents, [{ :a => 1 }, { :a => 1 }],
|
249
|
+
:writeConcern, { :w => 1 },
|
250
|
+
:ordered, false]
|
251
|
+
|
252
|
+
assert_raise Mongo::OperationFailure do
|
253
|
+
@db.command(command)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def test_single_update_write_command
|
258
|
+
return unless @version >= '2.5.4'
|
259
|
+
@test.drop
|
260
|
+
@test.insert([{ :a => 1 }, { :a => 2 }])
|
261
|
+
|
262
|
+
command = BSON::OrderedHash['update', @test.name,
|
263
|
+
:updates, [{ :q => { :a => 1 }, :u => { '$set' => { :a => 2 }}}],
|
264
|
+
:writeConcern, { :w => 1 }]
|
265
|
+
|
266
|
+
result = @db.command(command)
|
267
|
+
assert_equal 1, result['ok']
|
268
|
+
assert_equal 1, result['n']
|
269
|
+
assert_equal 2, @test.find({ :a => 2 }).count
|
270
|
+
end
|
271
|
+
|
272
|
+
def test_multi_ordered_update_write_command
|
273
|
+
return unless @version >= '2.5.4'
|
274
|
+
@test.drop
|
275
|
+
@test.insert([{ :a => 1 }, { :a => 3 }])
|
276
|
+
|
277
|
+
command = BSON::OrderedHash['update', @test.name,
|
278
|
+
:updates, [
|
279
|
+
{ :q => { :a => 1 }, :u => { '$set' => { :a => 2 }}},
|
280
|
+
{ :q => { :a => 3 }, :u => { '$set' => { :a => 4 }}}
|
281
|
+
],
|
282
|
+
:writeConcern, { :w => 1 },
|
283
|
+
:ordered, true]
|
284
|
+
|
285
|
+
result = @db.command(command)
|
286
|
+
assert_equal 1, result['ok']
|
287
|
+
assert_equal 2, result['n']
|
288
|
+
assert_equal 1, @test.find({ :a => 2 }).count
|
289
|
+
assert_equal 1, @test.find({ :a => 4 }).count
|
290
|
+
end
|
291
|
+
|
292
|
+
def test_multi_unordered_update_write_command
|
293
|
+
return unless @version >= '2.5.4'
|
294
|
+
@test.drop
|
295
|
+
@test.insert([{ :a => 1 }, { :a => 3 }])
|
296
|
+
|
297
|
+
command = BSON::OrderedHash['update', @test.name,
|
298
|
+
:updates, [
|
299
|
+
{ :q => { :a => 1 }, :u => { '$set' => { :a => 2 }}},
|
300
|
+
{ :q => { :a => 3 }, :u => { '$set' => { :a => 4 }}}
|
301
|
+
],
|
302
|
+
:writeConcern, { :w => 1 },
|
303
|
+
:ordered, false]
|
304
|
+
|
305
|
+
result = @db.command(command)
|
306
|
+
assert_equal 1, result['ok']
|
307
|
+
assert_equal 2, result['n']
|
308
|
+
assert_equal 1, @test.find({ :a => 2 }).count
|
309
|
+
assert_equal 1, @test.find({ :a => 4 }).count
|
310
|
+
end
|
311
|
+
|
312
|
+
def test_update_write_command_with_no_concern
|
313
|
+
return unless @version >= '2.5.4'
|
314
|
+
@test.drop
|
315
|
+
@test.insert([{ :a => 1 }, { :a => 3 }])
|
316
|
+
|
317
|
+
command = BSON::OrderedHash['update', @test.name,
|
318
|
+
:updates, [
|
319
|
+
{ :q => { :a => 1 }, :u => { '$set' => { :a => 2 }}},
|
320
|
+
{ :q => { :a => 3 }, :u => { '$set' => { :a => 4 }}}
|
321
|
+
],
|
322
|
+
:ordered, false]
|
323
|
+
|
324
|
+
result = @db.command(command)
|
325
|
+
assert_equal 1, result['ok']
|
326
|
+
assert_equal 2, result['n']
|
327
|
+
assert_equal 1, @test.find({ :a => 2 }).count
|
328
|
+
assert_equal 1, @test.find({ :a => 4 }).count
|
329
|
+
end
|
330
|
+
|
331
|
+
def test_update_write_command_with_error
|
332
|
+
return unless @version >= '2.5.4'
|
333
|
+
@test.drop
|
334
|
+
@test.ensure_index([[:a, 1]], { :unique => true })
|
335
|
+
@test.insert([{ :a => 1 }, { :a => 2 }])
|
336
|
+
|
337
|
+
command = BSON::OrderedHash['update', @test.name,
|
338
|
+
:updates, [
|
339
|
+
{ :q => { :a => 2 }, :u => { '$set' => { :a => 1 }}}
|
340
|
+
],
|
341
|
+
:ordered, false]
|
342
|
+
|
343
|
+
assert_raise Mongo::OperationFailure do
|
344
|
+
@db.command(command)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
def test_error_code
|
349
|
+
coll = @db['test-error-code']
|
350
|
+
coll.ensure_index(BSON::OrderedHash[:x, Mongo::ASCENDING], { :unique => true })
|
351
|
+
coll.save(:x => 2)
|
352
|
+
begin
|
353
|
+
coll.save(:x => 2)
|
354
|
+
rescue => ex
|
355
|
+
assert_not_nil ex.error_code
|
356
|
+
end
|
357
|
+
coll.drop
|
358
|
+
end
|
359
|
+
|
360
|
+
def test_aggregation_cursor
|
361
|
+
return unless @version >= '2.5.1'
|
362
|
+
[10, 1000].each do |size|
|
363
|
+
@test.drop
|
364
|
+
size.times {|i| @test.insert({ :_id => i }) }
|
365
|
+
expected_sum = size.times.reduce(:+)
|
366
|
+
|
367
|
+
cursor = @test.aggregate(
|
368
|
+
[{ :$project => {:_id => '$_id'}} ],
|
369
|
+
:cursor => {}
|
370
|
+
)
|
371
|
+
|
372
|
+
assert_equal Mongo::Cursor, cursor.class
|
373
|
+
|
374
|
+
cursor_sum = cursor.reduce(0) do |sum, doc|
|
375
|
+
sum += doc['_id']
|
376
|
+
end
|
377
|
+
|
378
|
+
assert_equal expected_sum, cursor_sum
|
379
|
+
end
|
380
|
+
@test.drop
|
381
|
+
end
|
382
|
+
|
383
|
+
def test_aggregation_array
|
384
|
+
return unless @version >= '2.5.1'
|
385
|
+
@test.drop
|
386
|
+
100.times {|i| @test.insert({ :_id => i }) }
|
387
|
+
agg = @test.aggregate([{ :$project => {:_id => '$_id'}} ])
|
388
|
+
|
389
|
+
assert agg.kind_of?(Array)
|
390
|
+
|
391
|
+
@test.drop
|
392
|
+
end
|
393
|
+
|
394
|
+
def test_aggregation_cursor_invalid_ops
|
395
|
+
return unless @version >= '2.5.1'
|
396
|
+
cursor = @test.aggregate([], :cursor => {})
|
397
|
+
assert_raise(Mongo::InvalidOperation) { cursor.rewind! }
|
398
|
+
assert_raise(Mongo::InvalidOperation) { cursor.explain }
|
399
|
+
assert_raise(Mongo::InvalidOperation) { cursor.count }
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_aggregation_invalid_read_pref
|
403
|
+
assert_raise Mongo::MongoArgumentError do
|
404
|
+
@test.aggregate([], :read => :invalid_read_pref)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
def test_aggregation_supports_explain
|
409
|
+
return unless @version >= '2.5.3'
|
410
|
+
@db.expects(:command).with do |selector, opts|
|
411
|
+
opts[:explain] == true
|
412
|
+
end.returns({ 'ok' => 1 })
|
413
|
+
@test.aggregate([], :explain => true)
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_aggregation_explain_returns_raw_result
|
417
|
+
return unless @version >= '2.5.3'
|
418
|
+
response = @test.aggregate([], :explain => true)
|
419
|
+
assert response['stages']
|
420
|
+
end
|
421
|
+
|
422
|
+
def test_capped_method
|
423
|
+
@db.create_collection('normal')
|
424
|
+
assert !@db['normal'].capped?
|
425
|
+
@db.drop_collection('normal')
|
426
|
+
|
427
|
+
@db.create_collection('c', :capped => true, :size => 100_000)
|
428
|
+
assert @db['c'].capped?
|
429
|
+
@db.drop_collection('c')
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_optional_pk_factory
|
433
|
+
@coll_default_pk = @db.collection('stuff')
|
434
|
+
assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
|
435
|
+
@coll_default_pk = @db.create_collection('more-stuff')
|
436
|
+
assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
|
437
|
+
|
438
|
+
# Create a db with a pk_factory.
|
439
|
+
client = MongoClient.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
|
440
|
+
ENV['MONGO_RUBY_DRIVER_PORT'] || MongoClient::DEFAULT_PORT)
|
441
|
+
client[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD)
|
442
|
+
db = client.db(TEST_DB, :pk => Object.new)
|
443
|
+
|
444
|
+
coll = db.collection('coll-with-pk')
|
445
|
+
assert coll.pk_factory.is_a?(Object)
|
446
|
+
|
447
|
+
coll = db.create_collection('created_coll_with_pk')
|
448
|
+
assert coll.pk_factory.is_a?(Object)
|
449
|
+
end
|
450
|
+
|
451
|
+
class PKTest
|
452
|
+
def self.create_pk
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
def test_pk_factory_on_collection
|
457
|
+
silently do
|
458
|
+
@coll = Collection.new('foo', @db, PKTest)
|
459
|
+
assert_equal PKTest, @coll.pk_factory
|
460
|
+
end
|
461
|
+
|
462
|
+
@coll2 = Collection.new('foo', @db, :pk => PKTest)
|
463
|
+
assert_equal PKTest, @coll2.pk_factory
|
464
|
+
end
|
465
|
+
|
466
|
+
def test_valid_names
|
467
|
+
assert_raise Mongo::InvalidNSName do
|
468
|
+
@db["te$t"]
|
469
|
+
end
|
470
|
+
|
471
|
+
assert_raise Mongo::InvalidNSName do
|
472
|
+
@db['$main']
|
473
|
+
end
|
474
|
+
|
475
|
+
assert @db['$cmd']
|
476
|
+
assert @db['oplog.$main']
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_collection
|
480
|
+
assert_kind_of Collection, @db["test"]
|
481
|
+
assert_equal @db["test"].name(), @db.collection("test").name()
|
482
|
+
assert_equal @db["test"].name(), @db[:test].name()
|
483
|
+
|
484
|
+
assert_kind_of Collection, @db["test"]["foo"]
|
485
|
+
assert_equal @db["test"]["foo"].name(), @db.collection("test.foo").name()
|
486
|
+
assert_equal @db["test"]["foo"].name(), @db["test.foo"].name()
|
487
|
+
|
488
|
+
@db["test"]["foo"].remove
|
489
|
+
@db["test"]["foo"].insert("x" => 5)
|
490
|
+
assert_equal 5, @db.collection("test.foo").find_one()["x"]
|
491
|
+
end
|
492
|
+
|
493
|
+
def test_rename_collection
|
494
|
+
@db.drop_collection('foo1')
|
495
|
+
@db.drop_collection('bar1')
|
496
|
+
|
497
|
+
@col = @db.create_collection('foo1')
|
498
|
+
assert_equal 'foo1', @col.name
|
499
|
+
|
500
|
+
@col.rename('bar1')
|
501
|
+
assert_equal 'bar1', @col.name
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_nil_id
|
505
|
+
assert_equal 5, @test.insert({"_id" => 5, "foo" => "bar"})
|
506
|
+
assert_equal 5, @test.save({"_id" => 5, "foo" => "baz"})
|
507
|
+
assert_equal nil, @test.find_one("foo" => "bar")
|
508
|
+
assert_equal "baz", @test.find_one(:_id => 5)["foo"]
|
509
|
+
assert_raise OperationFailure do
|
510
|
+
@test.insert({"_id" => 5, "foo" => "bar"})
|
511
|
+
end
|
512
|
+
|
513
|
+
assert_equal nil, @test.insert({"_id" => nil, "foo" => "bar"})
|
514
|
+
assert_equal nil, @test.save({"_id" => nil, "foo" => "baz"})
|
515
|
+
assert_equal nil, @test.find_one("foo" => "bar")
|
516
|
+
assert_equal "baz", @test.find_one(:_id => nil)["foo"]
|
517
|
+
assert_raise OperationFailure do
|
518
|
+
@test.insert({"_id" => nil, "foo" => "bar"})
|
519
|
+
end
|
520
|
+
assert_raise OperationFailure do
|
521
|
+
@test.insert({:_id => nil, "foo" => "bar"})
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
def setup_for_distinct
|
526
|
+
return unless @version > "1.1"
|
527
|
+
@test.remove
|
528
|
+
@test.insert([{:a => 0, :b => {:c => "a"}},
|
529
|
+
{:a => 1, :b => {:c => "b"}},
|
530
|
+
{:a => 1, :b => {:c => "c"}},
|
531
|
+
{:a => 2, :b => {:c => "a"}},
|
532
|
+
{:a => 3},
|
533
|
+
{:a => 3}])
|
534
|
+
end
|
535
|
+
|
536
|
+
def test_distinct_queries
|
537
|
+
return unless @version > "1.1"
|
538
|
+
setup_for_distinct
|
539
|
+
assert_equal [0, 1, 2, 3], @test.distinct(:a).sort
|
540
|
+
assert_equal ["a", "b", "c"], @test.distinct("b.c").sort
|
541
|
+
end
|
542
|
+
|
543
|
+
def test_filter_collection_with_query
|
544
|
+
return unless @version >= "1.2"
|
545
|
+
setup_for_distinct
|
546
|
+
assert_equal [2, 3], @test.distinct(:a, {:a => {"$gt" => 1}}).sort
|
547
|
+
end
|
548
|
+
|
549
|
+
def test_filter_nested_objects
|
550
|
+
return unless @version >= "1.2"
|
551
|
+
setup_for_distinct
|
552
|
+
assert_equal ["a", "b"], @test.distinct("b.c", {"b.c" => {"$ne" => "c"}}).sort
|
553
|
+
end
|
554
|
+
|
555
|
+
def test_safe_insert
|
556
|
+
@test.create_index("hello", :unique => true)
|
557
|
+
begin
|
558
|
+
a = {"hello" => "world"}
|
559
|
+
@test.insert(a)
|
560
|
+
@test.insert(a, :w => 0)
|
561
|
+
assert(@db.get_last_error['err'].include?("11000"))
|
562
|
+
|
563
|
+
assert_raise OperationFailure do
|
564
|
+
@test.insert(a)
|
565
|
+
end
|
566
|
+
ensure
|
567
|
+
@test.drop_indexes
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
def test_bulk_insert
|
572
|
+
docs = []
|
573
|
+
docs << {:foo => 1}
|
574
|
+
docs << {:foo => 2}
|
575
|
+
docs << {:foo => 3}
|
576
|
+
response = @test.insert(docs)
|
577
|
+
assert_equal 3, response.length
|
578
|
+
assert response.all? {|id| id.is_a?(BSON::ObjectId)}
|
579
|
+
assert_equal 3, @test.count
|
580
|
+
end
|
581
|
+
|
582
|
+
def test_bulk_insert_with_continue_on_error
|
583
|
+
if @version >= "2.0"
|
584
|
+
@test.create_index([["foo", 1]], :unique => true)
|
585
|
+
begin
|
586
|
+
docs = []
|
587
|
+
docs << {:foo => 1}
|
588
|
+
docs << {:foo => 1}
|
589
|
+
docs << {:foo => 2}
|
590
|
+
docs << {:foo => 3}
|
591
|
+
assert_raise OperationFailure do
|
592
|
+
@test.insert(docs)
|
593
|
+
end
|
594
|
+
assert_equal 1, @test.count
|
595
|
+
@test.remove
|
596
|
+
|
597
|
+
docs = []
|
598
|
+
docs << {:foo => 1}
|
599
|
+
docs << {:foo => 1}
|
600
|
+
docs << {:foo => 2}
|
601
|
+
docs << {:foo => 3}
|
602
|
+
assert_raise OperationFailure do
|
603
|
+
@test.insert(docs, :continue_on_error => true)
|
604
|
+
end
|
605
|
+
assert_equal 3, @test.count
|
606
|
+
|
607
|
+
@test.remove
|
608
|
+
ensure
|
609
|
+
@test.drop_index("foo_1")
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
def test_bson_valid_with_collect_on_error
|
615
|
+
docs = []
|
616
|
+
docs << {:foo => 1}
|
617
|
+
docs << {:bar => 1}
|
618
|
+
doc_ids, error_docs = @test.insert(docs, :collect_on_error => true)
|
619
|
+
assert_equal 2, @test.count
|
620
|
+
assert_equal 2, doc_ids.count
|
621
|
+
assert_equal error_docs, []
|
622
|
+
end
|
623
|
+
|
624
|
+
def test_bson_invalid_key_serialize_error_with_collect_on_error
|
625
|
+
docs = []
|
626
|
+
docs << {:foo => 1}
|
627
|
+
docs << {:bar => 1}
|
628
|
+
invalid_docs = []
|
629
|
+
invalid_docs << {'$invalid-key' => 1}
|
630
|
+
invalid_docs << {'invalid.key' => 1}
|
631
|
+
docs += invalid_docs
|
632
|
+
assert_raise BSON::InvalidKeyName do
|
633
|
+
@test.insert(docs, :collect_on_error => false)
|
634
|
+
end
|
635
|
+
assert_equal 2, @test.count
|
636
|
+
|
637
|
+
doc_ids, error_docs = @test.insert(docs, :collect_on_error => true)
|
638
|
+
assert_equal 2, @test.count
|
639
|
+
assert_equal 2, doc_ids.count
|
640
|
+
assert_equal error_docs, invalid_docs
|
641
|
+
end
|
642
|
+
|
643
|
+
def test_bson_invalid_encoding_serialize_error_with_collect_on_error
|
644
|
+
# Broken for current JRuby
|
645
|
+
if RUBY_PLATFORM == 'java' then return end
|
646
|
+
docs = []
|
647
|
+
docs << {:foo => 1}
|
648
|
+
docs << {:bar => 1}
|
649
|
+
invalid_docs = []
|
650
|
+
invalid_docs << {"\223\372\226}" => 1} # non utf8 encoding
|
651
|
+
docs += invalid_docs
|
652
|
+
|
653
|
+
assert_raise BSON::InvalidStringEncoding do
|
654
|
+
@test.insert(docs, :collect_on_error => false)
|
655
|
+
end
|
656
|
+
assert_equal 2, @test.count
|
657
|
+
|
658
|
+
doc_ids, error_docs = @test.insert(docs, :collect_on_error => true)
|
659
|
+
assert_equal 2, @test.count
|
660
|
+
assert_equal 2, doc_ids.count
|
661
|
+
assert_equal error_docs, invalid_docs
|
662
|
+
end
|
663
|
+
|
664
|
+
def test_insert_one_error_doc_with_collect_on_error
|
665
|
+
invalid_doc = {'$invalid-key' => 1}
|
666
|
+
invalid_docs = [invalid_doc]
|
667
|
+
doc_ids, error_docs = @test.insert(invalid_docs, :collect_on_error => true)
|
668
|
+
assert_equal [], doc_ids
|
669
|
+
assert_equal [invalid_doc], error_docs
|
670
|
+
end
|
671
|
+
|
672
|
+
def test_insert_empty_docs_raises_exception
|
673
|
+
assert_raise OperationFailure do
|
674
|
+
@test.insert([])
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
def test_insert_empty_docs_with_collect_on_error_raises_exception
|
679
|
+
assert_raise OperationFailure do
|
680
|
+
@test.insert([], :collect_on_error => true)
|
681
|
+
end
|
682
|
+
end
|
683
|
+
|
684
|
+
def limited_collection
|
685
|
+
conn = standard_connection(:connect => false)
|
686
|
+
is_master = @ismaster.merge('maxBsonObjectSize' => LIMITED_MAX_BSON_SIZE,
|
687
|
+
'maxMessageSizeBytes' => LIMITED_MAX_BSON_SIZE)
|
688
|
+
admin_db = Object.new
|
689
|
+
admin_db.expects(:command).returns(is_master)
|
690
|
+
conn.expects(:[]).with(TEST_DB).returns(admin_db)
|
691
|
+
conn.connect
|
692
|
+
return conn.db(TEST_DB)["test"]
|
693
|
+
end
|
694
|
+
|
695
|
+
def test_non_operation_failure_halts_insertion_with_continue_on_error
|
696
|
+
coll = limited_collection
|
697
|
+
if @client.wire_version_feature?(MongoClient::BATCH_COMMANDS)
|
698
|
+
coll.db.stubs(:command).raises(OperationTimeout).times(1)
|
699
|
+
else
|
700
|
+
coll.db.connection.stubs(:send_message_with_gle).raises(OperationTimeout).times(1)
|
701
|
+
end
|
702
|
+
docs = []
|
703
|
+
10.times do
|
704
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
705
|
+
end
|
706
|
+
assert_raise OperationTimeout do
|
707
|
+
coll.insert(docs, :continue_on_error => true)
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_chunking_batch_insert
|
712
|
+
docs = []
|
713
|
+
10.times do
|
714
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
715
|
+
end
|
716
|
+
limited_collection.insert(docs)
|
717
|
+
assert_equal 10, limited_collection.count
|
718
|
+
end
|
719
|
+
|
720
|
+
def test_chunking_batch_insert_without_collect_on_error
|
721
|
+
docs = []
|
722
|
+
4.times do
|
723
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
724
|
+
end
|
725
|
+
invalid_docs = []
|
726
|
+
invalid_docs << {'$invalid-key' => 1} # non utf8 encoding
|
727
|
+
docs += invalid_docs
|
728
|
+
4.times do
|
729
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
730
|
+
end
|
731
|
+
assert_raise BSON::InvalidKeyName do
|
732
|
+
limited_collection.insert(docs, :collect_on_error => false)
|
733
|
+
end
|
734
|
+
end
|
735
|
+
|
736
|
+
def test_chunking_batch_insert_with_collect_on_error
|
737
|
+
# Broken for current JRuby
|
738
|
+
if RUBY_PLATFORM == 'java' then return end
|
739
|
+
docs = []
|
740
|
+
4.times do
|
741
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
742
|
+
end
|
743
|
+
invalid_docs = []
|
744
|
+
invalid_docs << {'$invalid-key' => 1} # non utf8 encoding
|
745
|
+
docs += invalid_docs
|
746
|
+
4.times do
|
747
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
748
|
+
end
|
749
|
+
doc_ids, error_docs = limited_collection.insert(docs, :collect_on_error => true)
|
750
|
+
assert_equal 8, doc_ids.count
|
751
|
+
assert_equal doc_ids.count, limited_collection.count
|
752
|
+
assert_equal error_docs, invalid_docs
|
753
|
+
end
|
754
|
+
|
755
|
+
def test_chunking_batch_insert_with_continue_on_error
|
756
|
+
coll = limited_collection
|
757
|
+
docs = []
|
758
|
+
4.times do
|
759
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
760
|
+
end
|
761
|
+
docs << {'_id' => 'b', 'foo' => 'a'}
|
762
|
+
docs << {'_id' => 'b', 'foo' => 'c'}
|
763
|
+
4.times do
|
764
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
765
|
+
end
|
766
|
+
assert_raise OperationFailure do
|
767
|
+
coll.insert(docs, :continue_on_error => true)
|
768
|
+
end
|
769
|
+
assert coll.count >= 6, "write commands need headroom for doc wrapping overhead - count:#{coll.count}"
|
770
|
+
end
|
771
|
+
|
772
|
+
def test_chunking_batch_insert_without_continue_on_error
|
773
|
+
docs = []
|
774
|
+
4.times do
|
775
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
776
|
+
end
|
777
|
+
docs << {'_id' => 'b', 'foo' => 'a'}
|
778
|
+
docs << {'_id' => 'b', 'foo' => 'c'}
|
779
|
+
4.times do
|
780
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
781
|
+
end
|
782
|
+
assert_raise OperationFailure do
|
783
|
+
limited_collection.insert(docs, :continue_on_error => false)
|
784
|
+
end
|
785
|
+
assert_equal 5, limited_collection.count
|
786
|
+
end
|
787
|
+
|
788
|
+
def test_maximum_insert_size
|
789
|
+
docs = []
|
790
|
+
3.times do
|
791
|
+
docs << {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
792
|
+
end
|
793
|
+
assert_equal limited_collection.insert(docs).length, 3
|
794
|
+
end
|
795
|
+
|
796
|
+
def test_maximum_document_size
|
797
|
+
assert_raise InvalidDocument do
|
798
|
+
limited_collection.insert({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
|
799
|
+
end
|
800
|
+
end
|
801
|
+
|
802
|
+
def test_maximum_save_size
|
803
|
+
assert limited_collection.save({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
|
804
|
+
assert_raise InvalidDocument do
|
805
|
+
limited_collection.save({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
|
806
|
+
end
|
807
|
+
end
|
808
|
+
|
809
|
+
def test_maximum_remove_size
|
810
|
+
assert limited_collection.remove({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
|
811
|
+
assert_raise InvalidDocument do
|
812
|
+
limited_collection.remove({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
816
|
+
def test_maximum_update_size
|
817
|
+
assert_raise InvalidDocument do
|
818
|
+
limited_collection.update(
|
819
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
|
820
|
+
{'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
|
821
|
+
)
|
822
|
+
end
|
823
|
+
|
824
|
+
assert_raise InvalidDocument do
|
825
|
+
limited_collection.update(
|
826
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
|
827
|
+
{'foo' => 'a' * LIMITED_MAX_BSON_SIZE}
|
828
|
+
)
|
829
|
+
end
|
830
|
+
|
831
|
+
assert_raise InvalidDocument do
|
832
|
+
limited_collection.update(
|
833
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
|
834
|
+
{'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM}
|
835
|
+
)
|
836
|
+
end
|
837
|
+
|
838
|
+
assert limited_collection.update(
|
839
|
+
{'foo' => 'a' * (LIMITED_VALID_VALUE_SIZE/2)},
|
840
|
+
{'foo' => 'a' * (LIMITED_VALID_VALUE_SIZE/2)}
|
841
|
+
)
|
842
|
+
end
|
843
|
+
|
844
|
+
def test_maximum_query_size
|
845
|
+
assert limited_collection.find({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}).to_a
|
846
|
+
assert limited_collection.find(
|
847
|
+
{'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
|
848
|
+
{:fields => {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}}
|
849
|
+
).to_a
|
850
|
+
|
851
|
+
assert_raise InvalidDocument do
|
852
|
+
limited_collection.find({'foo' => 'a' * LIMITED_INVALID_VALUE_SIZE}).to_a
|
853
|
+
end
|
854
|
+
|
855
|
+
assert_raise InvalidDocument do
|
856
|
+
limited_collection.find(
|
857
|
+
{'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
|
858
|
+
{:fields => {'foo' => 'a' * LIMITED_MAX_BSON_SIZE}}
|
859
|
+
).to_a
|
860
|
+
end
|
861
|
+
end
|
862
|
+
|
863
|
+
#if @version >= "1.5.1"
|
864
|
+
# def test_safe_mode_with_advanced_safe_with_invalid_options
|
865
|
+
# assert_raise_error ArgumentError, "Unknown key(s): wtime" do
|
866
|
+
# @test.insert({:foo => 1}, :w => 2, :wtime => 1, :fsync => true)
|
867
|
+
# end
|
868
|
+
# assert_raise_error ArgumentError, "Unknown key(s): wtime" do
|
869
|
+
# @test.update({:foo => 1}, {:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
|
870
|
+
# end
|
871
|
+
#
|
872
|
+
# assert_raise_error ArgumentError, "Unknown key(s): wtime" do
|
873
|
+
# @test.remove({:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
|
874
|
+
# end
|
875
|
+
# end
|
876
|
+
#end
|
877
|
+
|
878
|
+
def test_safe_mode_with_journal_commit_option
|
879
|
+
with_default_journaling(@client) do
|
880
|
+
@test.insert({:foo => 1}, :j => true)
|
881
|
+
@test.update({:foo => 1}, {:foo => 2}, :j => true)
|
882
|
+
@test.remove({:foo => 2}, :j => true)
|
883
|
+
end
|
884
|
+
end
|
885
|
+
|
886
|
+
def test_jnote_raises_exception
|
887
|
+
return unless @version < "2.5.3"
|
888
|
+
with_no_journaling(@client) do
|
889
|
+
ex = assert_raise Mongo::WriteConcernError do
|
890
|
+
@test.insert({:foo => 1}, :j => true)
|
891
|
+
end
|
892
|
+
result = ex.result
|
893
|
+
assert_true result.has_key?("jnote")
|
894
|
+
end
|
895
|
+
end
|
896
|
+
|
897
|
+
def test_wnote_raises_exception_with_err_not_nil
|
898
|
+
return unless @version < "2.5.3"
|
899
|
+
ex = assert_raise Mongo::WriteConcernError do
|
900
|
+
@test.insert({:foo => 1}, :w => 2)
|
901
|
+
end
|
902
|
+
result = ex.result
|
903
|
+
assert_not_nil result["err"]
|
904
|
+
assert_true result.has_key?("wnote")
|
905
|
+
end
|
906
|
+
|
907
|
+
def test_update
|
908
|
+
id1 = @test.save("x" => 5)
|
909
|
+
@test.update({}, {"$inc" => {"x" => 1}})
|
910
|
+
assert_equal 1, @test.count()
|
911
|
+
assert_equal 6, @test.find_one(:_id => id1)["x"]
|
912
|
+
|
913
|
+
id2 = @test.save("x" => 1)
|
914
|
+
@test.update({"x" => 6}, {"$inc" => {"x" => 1}})
|
915
|
+
assert_equal 7, @test.find_one(:_id => id1)["x"]
|
916
|
+
assert_equal 1, @test.find_one(:_id => id2)["x"]
|
917
|
+
end
|
918
|
+
|
919
|
+
def test_update_check_keys
|
920
|
+
return unless @version < "2.5.3"
|
921
|
+
@test.save("x" => 1)
|
922
|
+
@test.update({"x" => 1}, {"$set" => {"a.b" => 2}})
|
923
|
+
assert_equal 2, @test.find_one("x" => 1)["a"]["b"]
|
924
|
+
|
925
|
+
assert_raise_error BSON::InvalidKeyName do
|
926
|
+
@test.update({"x" => 1}, {"a.b" => 3})
|
927
|
+
end
|
928
|
+
end
|
929
|
+
|
930
|
+
def test_multi_update
|
931
|
+
return unless @version >= "1.1.3"
|
932
|
+
@test.save("num" => 10)
|
933
|
+
@test.save("num" => 10)
|
934
|
+
@test.save("num" => 10)
|
935
|
+
assert_equal 3, @test.count
|
936
|
+
|
937
|
+
@test.update({"num" => 10}, {"$set" => {"num" => 100}}, :multi => true)
|
938
|
+
@test.find.each do |doc|
|
939
|
+
assert_equal 100, doc["num"]
|
940
|
+
end
|
941
|
+
end
|
942
|
+
|
943
|
+
def test_upsert
|
944
|
+
@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
|
945
|
+
@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
|
946
|
+
|
947
|
+
assert_equal 1, @test.count()
|
948
|
+
assert_equal 2, @test.find_one()["count"]
|
949
|
+
end
|
950
|
+
|
951
|
+
def test_safe_update
|
952
|
+
@test.create_index("x", :unique => true)
|
953
|
+
@test.insert("x" => 5)
|
954
|
+
@test.insert("x" => 10)
|
955
|
+
|
956
|
+
# Can update an indexed collection.
|
957
|
+
@test.update({}, {"$inc" => {"x" => 1}})
|
958
|
+
assert !@db.error?
|
959
|
+
|
960
|
+
# Can't duplicate an index.
|
961
|
+
assert_raise OperationFailure do
|
962
|
+
@test.update({}, {"x" => 10})
|
963
|
+
end
|
964
|
+
@test.drop
|
965
|
+
end
|
966
|
+
|
967
|
+
def test_safe_save
|
968
|
+
@test.create_index("hello", :unique => true)
|
969
|
+
|
970
|
+
@test.save("hello" => "world")
|
971
|
+
@test.save({"hello" => "world"}, :w => 0)
|
972
|
+
|
973
|
+
assert_raise OperationFailure do
|
974
|
+
@test.save({"hello" => "world"})
|
975
|
+
end
|
976
|
+
@test.drop
|
977
|
+
end
|
978
|
+
|
979
|
+
def test_mocked_safe_remove
|
980
|
+
@client = standard_connection
|
981
|
+
@db = @client[TEST_DB]
|
982
|
+
@test = @db['test-safe-remove']
|
983
|
+
@test.save({:a => 20})
|
984
|
+
@client.stubs(:receive).returns([[{'ok' => 0, 'err' => 'failed'}], 1, 0])
|
985
|
+
|
986
|
+
assert_raise OperationFailure do
|
987
|
+
@test.remove({})
|
988
|
+
end
|
989
|
+
@test.drop
|
990
|
+
end
|
991
|
+
|
992
|
+
def test_safe_remove
|
993
|
+
@client = standard_connection
|
994
|
+
@db = @client[TEST_DB]
|
995
|
+
@test = @db['test-safe-remove']
|
996
|
+
@test.remove
|
997
|
+
@test.save({:a => 50})
|
998
|
+
assert_equal 1, @test.remove({})["n"]
|
999
|
+
@test.drop
|
1000
|
+
end
|
1001
|
+
|
1002
|
+
def test_remove_return_value
|
1003
|
+
assert_equal true, @test.remove({}, :w => 0)
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
def test_remove_with_limit
|
1007
|
+
@test.insert([{:n => 1},{:n => 2},{:n => 3}])
|
1008
|
+
@test.remove({}, :limit => 1)
|
1009
|
+
assert_equal 2, @test.count
|
1010
|
+
@test.remove({}, :limit => 0)
|
1011
|
+
assert_equal 0, @test.count
|
1012
|
+
end
|
1013
|
+
|
1014
|
+
def test_count
|
1015
|
+
@test.drop
|
1016
|
+
|
1017
|
+
assert_equal 0, @test.count
|
1018
|
+
@test.save(:x => 1)
|
1019
|
+
@test.save(:x => 2)
|
1020
|
+
assert_equal 2, @test.count
|
1021
|
+
|
1022
|
+
assert_equal 1, @test.count(:query => {:x => 1})
|
1023
|
+
assert_equal 1, @test.count(:limit => 1)
|
1024
|
+
assert_equal 0, @test.count(:skip => 2)
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
def test_count_with_hint
|
1028
|
+
@test.drop
|
1029
|
+
@test.save(:i => 1)
|
1030
|
+
@test.save(:i => 2)
|
1031
|
+
assert_equal 2, @test.count
|
1032
|
+
|
1033
|
+
@test.ensure_index(BSON::OrderedHash[:i, Mongo::ASCENDING])
|
1034
|
+
|
1035
|
+
# Check that a named_hint can be specified
|
1036
|
+
assert_equal 1, @test.count(:query => { :i => 1 }, :named_hint => '_id_')
|
1037
|
+
assert_equal 2, @test.count(:query => { }, :named_hint => '_id_')
|
1038
|
+
|
1039
|
+
# Verify that the hint is being sent to the server by providing a bad hint
|
1040
|
+
if @version > '2.6'
|
1041
|
+
assert_raise Mongo::OperationFailure do
|
1042
|
+
@test.count(:query => { :i => 1 }, :hint => 'bad_hint')
|
1043
|
+
end
|
1044
|
+
else
|
1045
|
+
assert_equal 1, @test.count(:query => { :i => 1 }, :hint => 'bad_hint')
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
# Verify that the named_hint is being sent to the server by providing a bad hint
|
1049
|
+
if @version > '2.6'
|
1050
|
+
assert_raise Mongo::OperationFailure do
|
1051
|
+
@test.count(:query => { :i => 1 }, :named_hint => 'bad_hint')
|
1052
|
+
end
|
1053
|
+
else
|
1054
|
+
assert_equal 1, @test.count(:query => { :i => 1 }, :named_hint => 'bad_hint')
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
@test.ensure_index(BSON::OrderedHash[:x, Mongo::ASCENDING], :sparse => true)
|
1058
|
+
|
1059
|
+
# The sparse index won't have any entries.
|
1060
|
+
# Check that count returns 0 when using the hint.
|
1061
|
+
expected = @version > '2.6' ? 0 : 1
|
1062
|
+
assert_equal expected, @test.count(:query => { :i => 1 }, :hint => { 'x' => 1 })
|
1063
|
+
assert_equal expected, @test.count(:query => { :i => 1 }, :hint => 'x')
|
1064
|
+
assert_equal expected, @test.count(:query => { :i => 1 }, :named_hint => 'x_1')
|
1065
|
+
|
1066
|
+
# Verify that the hint / named hint set on the collection is used.
|
1067
|
+
@test.hint = { 'x' => 1 }
|
1068
|
+
assert_equal expected, @test.count(:query => { :i => 1 })
|
1069
|
+
|
1070
|
+
@test.hint = 'x'
|
1071
|
+
assert_equal expected, @test.count(:query => { :i => 1 })
|
1072
|
+
|
1073
|
+
# The driver should allow x_1, but the code sets named_hint to @hint without
|
1074
|
+
# normalizing.
|
1075
|
+
@test.named_hint = 'x'
|
1076
|
+
assert_equal expected, @test.count(:query => { :i => 1 })
|
1077
|
+
|
1078
|
+
assert_equal 2, @test.count(:query => { }, :hint => 'x')
|
1079
|
+
assert_equal 2, @test.count(:query => { }, :named_hint => 'x_1')
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
# Note: #size is just an alias for #count.
|
1083
|
+
def test_size
|
1084
|
+
@test.drop
|
1085
|
+
|
1086
|
+
assert_equal 0, @test.count
|
1087
|
+
assert_equal @test.size, @test.count
|
1088
|
+
@test.save("x" => 1)
|
1089
|
+
@test.save("x" => 2)
|
1090
|
+
assert_equal @test.size, @test.count
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
def test_no_timeout_option
|
1094
|
+
@test.drop
|
1095
|
+
|
1096
|
+
assert_raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block." do
|
1097
|
+
@test.find({}, :timeout => false)
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
@test.find({}, :timeout => false) do |cursor|
|
1101
|
+
assert_equal 0, cursor.count
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
@test.save("x" => 1)
|
1105
|
+
@test.save("x" => 2)
|
1106
|
+
@test.find({}, :timeout => false) do |cursor|
|
1107
|
+
assert_equal 2, cursor.count
|
1108
|
+
end
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
def test_default_timeout
|
1112
|
+
cursor = @test.find
|
1113
|
+
assert_equal true, cursor.timeout
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
def test_fields_as_hash
|
1117
|
+
@test.save(:a => 1, :b => 1, :c => 1)
|
1118
|
+
|
1119
|
+
doc = @test.find_one({:a => 1}, :fields => {:b => 0})
|
1120
|
+
assert_nil doc['b']
|
1121
|
+
assert doc['a']
|
1122
|
+
assert doc['c']
|
1123
|
+
|
1124
|
+
doc = @test.find_one({:a => 1}, :fields => {:a => 1, :b => 1})
|
1125
|
+
assert_nil doc['c']
|
1126
|
+
assert doc['a']
|
1127
|
+
assert doc['b']
|
1128
|
+
|
1129
|
+
|
1130
|
+
assert_raise Mongo::OperationFailure do
|
1131
|
+
@test.find_one({:a => 1}, :fields => {:a => 1, :b => 0})
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
|
1135
|
+
|
1136
|
+
def test_meta_field_projection
|
1137
|
+
return unless @version >= '2.5.5'
|
1138
|
+
@test.save({ :t => 'spam eggs and spam'})
|
1139
|
+
@test.save({ :t => 'spam'})
|
1140
|
+
@test.save({ :t => 'egg sausage and bacon'})
|
1141
|
+
|
1142
|
+
@test.ensure_index([[:t, 'text']])
|
1143
|
+
assert @test.find_one({ :$text => { :$search => 'spam' }},
|
1144
|
+
{ :fields => [:t, { :score => { :$meta => 'textScore' } }] })
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def test_sort_by_meta
|
1148
|
+
return unless @version >= '2.5.5'
|
1149
|
+
@test.save({ :t => 'spam eggs and spam'})
|
1150
|
+
@test.save({ :t => 'spam'})
|
1151
|
+
@test.save({ :t => 'egg sausage and bacon'})
|
1152
|
+
|
1153
|
+
@test.ensure_index([[:t, 'text']])
|
1154
|
+
assert @test.find({ :$text => { :$search => 'spam' }}).sort([:score, { '$meta' => 'textScore' }])
|
1155
|
+
assert @test.find({ :$text => { :$search => 'spam' }}).sort(:score => { '$meta' =>'textScore' })
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
def test_fields_with_slice
|
1159
|
+
return unless @version >= "1.5.1"
|
1160
|
+
@test.save({:foo => [1, 2, 3, 4, 5, 6], :test => 'slice'})
|
1161
|
+
|
1162
|
+
doc = @test.find_one({:test => 'slice'}, :fields => {'foo' => {'$slice' => [0, 3]}})
|
1163
|
+
assert_equal [1, 2, 3], doc['foo']
|
1164
|
+
@test.remove
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
def test_find_one
|
1168
|
+
id = @test.save("hello" => "world", "foo" => "bar")
|
1169
|
+
|
1170
|
+
assert_equal "world", @test.find_one()["hello"]
|
1171
|
+
assert_equal @test.find_one(id), @test.find_one()
|
1172
|
+
assert_equal @test.find_one(nil), @test.find_one()
|
1173
|
+
assert_equal @test.find_one({}), @test.find_one()
|
1174
|
+
assert_equal @test.find_one("hello" => "world"), @test.find_one()
|
1175
|
+
assert_equal @test.find_one(BSON::OrderedHash["hello", "world"]), @test.find_one()
|
1176
|
+
|
1177
|
+
assert @test.find_one(nil, :fields => ["hello"]).include?("hello")
|
1178
|
+
assert !@test.find_one(nil, :fields => ["foo"]).include?("hello")
|
1179
|
+
assert_equal ["_id"], @test.find_one(nil, :fields => []).keys()
|
1180
|
+
|
1181
|
+
assert_equal nil, @test.find_one("hello" => "foo")
|
1182
|
+
assert_equal nil, @test.find_one(BSON::OrderedHash["hello", "foo"])
|
1183
|
+
assert_equal nil, @test.find_one(ObjectId.new)
|
1184
|
+
|
1185
|
+
assert_raise TypeError do
|
1186
|
+
@test.find_one(6)
|
1187
|
+
end
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
def test_find_one_with_max_time_ms
|
1191
|
+
with_forced_timeout(@client) do
|
1192
|
+
assert_raise ExecutionTimeout do
|
1193
|
+
@test.find_one({}, { :max_time_ms => 100 })
|
1194
|
+
end
|
1195
|
+
end
|
1196
|
+
end
|
1197
|
+
|
1198
|
+
def test_find_one_with_compile_regex_option
|
1199
|
+
regex = /.*/
|
1200
|
+
@test.insert('r' => /.*/)
|
1201
|
+
assert_kind_of Regexp, @test.find_one({})['r']
|
1202
|
+
assert_kind_of Regexp, @test.find_one({}, :compile_regex => true)['r']
|
1203
|
+
assert_equal BSON::Regex, @test.find_one({}, :compile_regex => false)['r'].class
|
1204
|
+
end
|
1205
|
+
|
1206
|
+
def test_insert_adds_id
|
1207
|
+
doc = {"hello" => "world"}
|
1208
|
+
@test.insert(doc)
|
1209
|
+
assert(doc.include?(:_id))
|
1210
|
+
|
1211
|
+
docs = [{"hello" => "world"}, {"hello" => "world"}]
|
1212
|
+
@test.insert(docs)
|
1213
|
+
docs.each do |d|
|
1214
|
+
assert(d.include?(:_id))
|
1215
|
+
end
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
def test_save_adds_id
|
1219
|
+
doc = {"hello" => "world"}
|
1220
|
+
@test.save(doc)
|
1221
|
+
assert(doc.include?(:_id))
|
1222
|
+
end
|
1223
|
+
|
1224
|
+
def test_optional_find_block
|
1225
|
+
10.times do |i|
|
1226
|
+
@test.save("i" => i)
|
1227
|
+
end
|
1228
|
+
|
1229
|
+
x = nil
|
1230
|
+
@test.find("i" => 2) { |cursor|
|
1231
|
+
x = cursor.count()
|
1232
|
+
}
|
1233
|
+
assert_equal 1, x
|
1234
|
+
|
1235
|
+
i = 0
|
1236
|
+
@test.find({}, :skip => 5) do |cursor|
|
1237
|
+
cursor.each do |doc|
|
1238
|
+
i = i + 1
|
1239
|
+
end
|
1240
|
+
end
|
1241
|
+
assert_equal 5, i
|
1242
|
+
|
1243
|
+
c = nil
|
1244
|
+
@test.find() do |cursor|
|
1245
|
+
c = cursor
|
1246
|
+
end
|
1247
|
+
assert c.closed?
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
def setup_aggregate_data
|
1251
|
+
# save some data
|
1252
|
+
@test.save( {
|
1253
|
+
"_id" => 1,
|
1254
|
+
"title" => "this is my title",
|
1255
|
+
"author" => "bob",
|
1256
|
+
"posted" => Time.utc(2000),
|
1257
|
+
"pageViews" => 5 ,
|
1258
|
+
"tags" => [ "fun" , "good" , "fun" ],
|
1259
|
+
"comments" => [
|
1260
|
+
{ "author" => "joe", "text" => "this is cool" },
|
1261
|
+
{ "author" => "sam", "text" => "this is bad" }
|
1262
|
+
],
|
1263
|
+
"other" => { "foo" => 5 }
|
1264
|
+
} )
|
1265
|
+
|
1266
|
+
@test.save( {
|
1267
|
+
"_id" => 2,
|
1268
|
+
"title" => "this is your title",
|
1269
|
+
"author" => "dave",
|
1270
|
+
"posted" => Time.utc(2001),
|
1271
|
+
"pageViews" => 7,
|
1272
|
+
"tags" => [ "fun" , "nasty" ],
|
1273
|
+
"comments" => [
|
1274
|
+
{ "author" => "barbara" , "text" => "this is interesting" },
|
1275
|
+
{ "author" => "jenny", "text" => "i like to play pinball", "votes" => 10 }
|
1276
|
+
],
|
1277
|
+
"other" => { "bar" => 14 }
|
1278
|
+
})
|
1279
|
+
|
1280
|
+
@test.save( {
|
1281
|
+
"_id" => 3,
|
1282
|
+
"title" => "this is some other title",
|
1283
|
+
"author" => "jane",
|
1284
|
+
"posted" => Time.utc(2002),
|
1285
|
+
"pageViews" => 6 ,
|
1286
|
+
"tags" => [ "nasty", "filthy" ],
|
1287
|
+
"comments" => [
|
1288
|
+
{ "author" => "will" , "text" => "i don't like the color" } ,
|
1289
|
+
{ "author" => "jenny" , "text" => "can i get that in green?" }
|
1290
|
+
],
|
1291
|
+
"other" => { "bar" => 14 }
|
1292
|
+
})
|
1293
|
+
|
1294
|
+
end
|
1295
|
+
|
1296
|
+
def test_reponds_to_aggregate
|
1297
|
+
return unless @version > '2.1.1'
|
1298
|
+
assert_respond_to @test, :aggregate
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
def test_aggregate_requires_arguments
|
1302
|
+
return unless @version > '2.1.1'
|
1303
|
+
assert_raise MongoArgumentError do
|
1304
|
+
@test.aggregate()
|
1305
|
+
end
|
1306
|
+
end
|
1307
|
+
|
1308
|
+
def test_aggregate_requires_valid_arguments
|
1309
|
+
return unless @version > '2.1.1'
|
1310
|
+
assert_raise MongoArgumentError do
|
1311
|
+
@test.aggregate({})
|
1312
|
+
end
|
1313
|
+
end
|
1314
|
+
|
1315
|
+
def test_aggregate_pipeline_operator_format
|
1316
|
+
return unless @version > '2.1.1'
|
1317
|
+
assert_raise Mongo::OperationFailure do
|
1318
|
+
@test.aggregate([{"$project" => "_id"}])
|
1319
|
+
end
|
1320
|
+
end
|
1321
|
+
|
1322
|
+
def test_aggregate_pipeline_operators_using_strings
|
1323
|
+
return unless @version > '2.1.1'
|
1324
|
+
setup_aggregate_data
|
1325
|
+
desired_results = [ {"_id"=>1, "pageViews"=>5, "tags"=>["fun", "good", "fun"]},
|
1326
|
+
{"_id"=>2, "pageViews"=>7, "tags"=>["fun", "nasty"]},
|
1327
|
+
{"_id"=>3, "pageViews"=>6, "tags"=>["nasty", "filthy"]} ]
|
1328
|
+
results = @test.aggregate([{"$project" => {"tags" => 1, "pageViews" => 1}}])
|
1329
|
+
assert_equal desired_results, results
|
1330
|
+
end
|
1331
|
+
|
1332
|
+
def test_aggregate_pipeline_operators_using_symbols
|
1333
|
+
return unless @version > '2.1.1'
|
1334
|
+
setup_aggregate_data
|
1335
|
+
desired_results = [ {"_id"=>1, "pageViews"=>5, "tags"=>["fun", "good", "fun"]},
|
1336
|
+
{"_id"=>2, "pageViews"=>7, "tags"=>["fun", "nasty"]},
|
1337
|
+
{"_id"=>3, "pageViews"=>6, "tags"=>["nasty", "filthy"]} ]
|
1338
|
+
results = @test.aggregate([{"$project" => {:tags => 1, :pageViews => 1}}])
|
1339
|
+
assert_equal desired_results, results
|
1340
|
+
end
|
1341
|
+
|
1342
|
+
def test_aggregate_command_using_sym
|
1343
|
+
return unless @version > '2.1.1'
|
1344
|
+
cmd = BSON::OrderedHash[:aggregate, @test.name, :pipeline, [{'$match' => {:_id => true}}]]
|
1345
|
+
assert @db.command(cmd)
|
1346
|
+
end
|
1347
|
+
|
1348
|
+
def test_aggregate_pipeline_multiple_operators
|
1349
|
+
return unless @version > '2.1.1'
|
1350
|
+
setup_aggregate_data
|
1351
|
+
results = @test.aggregate([{"$project" => {"tags" => 1, "pageViews" => 1}}, {"$match" => {"pageViews" => 7}}])
|
1352
|
+
assert_equal 1, results.length
|
1353
|
+
end
|
1354
|
+
|
1355
|
+
def test_aggregate_pipeline_unwind
|
1356
|
+
return unless @version > '2.1.1'
|
1357
|
+
setup_aggregate_data
|
1358
|
+
desired_results = [ {"_id"=>1, "title"=>"this is my title", "author"=>"bob", "posted"=>Time.utc(2000),
|
1359
|
+
"pageViews"=>5, "tags"=>"fun", "comments"=>[{"author"=>"joe", "text"=>"this is cool"},
|
1360
|
+
{"author"=>"sam", "text"=>"this is bad"}], "other"=>{"foo"=>5 } },
|
1361
|
+
{"_id"=>1, "title"=>"this is my title", "author"=>"bob", "posted"=>Time.utc(2000),
|
1362
|
+
"pageViews"=>5, "tags"=>"good", "comments"=>[{"author"=>"joe", "text"=>"this is cool"},
|
1363
|
+
{"author"=>"sam", "text"=>"this is bad"}], "other"=>{"foo"=>5 } },
|
1364
|
+
{"_id"=>1, "title"=>"this is my title", "author"=>"bob", "posted"=>Time.utc(2000),
|
1365
|
+
"pageViews"=>5, "tags"=>"fun", "comments"=>[{"author"=>"joe", "text"=>"this is cool"},
|
1366
|
+
{"author"=>"sam", "text"=>"this is bad"}], "other"=>{"foo"=>5 } },
|
1367
|
+
{"_id"=>2, "title"=>"this is your title", "author"=>"dave", "posted"=>Time.utc(2001),
|
1368
|
+
"pageViews"=>7, "tags"=>"fun", "comments"=>[{"author"=>"barbara", "text"=>"this is interesting"},
|
1369
|
+
{"author"=>"jenny", "text"=>"i like to play pinball", "votes"=>10 }], "other"=>{"bar"=>14 } },
|
1370
|
+
{"_id"=>2, "title"=>"this is your title", "author"=>"dave", "posted"=>Time.utc(2001),
|
1371
|
+
"pageViews"=>7, "tags"=>"nasty", "comments"=>[{"author"=>"barbara", "text"=>"this is interesting"},
|
1372
|
+
{"author"=>"jenny", "text"=>"i like to play pinball", "votes"=>10 }], "other"=>{"bar"=>14 } },
|
1373
|
+
{"_id"=>3, "title"=>"this is some other title", "author"=>"jane", "posted"=>Time.utc(2002),
|
1374
|
+
"pageViews"=>6, "tags"=>"nasty", "comments"=>[{"author"=>"will", "text"=>"i don't like the color"},
|
1375
|
+
{"author"=>"jenny", "text"=>"can i get that in green?"}], "other"=>{"bar"=>14 } },
|
1376
|
+
{"_id"=>3, "title"=>"this is some other title", "author"=>"jane", "posted"=>Time.utc(2002),
|
1377
|
+
"pageViews"=>6, "tags"=>"filthy", "comments"=>[{"author"=>"will", "text"=>"i don't like the color"},
|
1378
|
+
{"author"=>"jenny", "text"=>"can i get that in green?"}], "other"=>{"bar"=>14 } }
|
1379
|
+
]
|
1380
|
+
results = @test.aggregate([{"$unwind"=> "$tags"}])
|
1381
|
+
assert_equal desired_results, results
|
1382
|
+
end
|
1383
|
+
|
1384
|
+
def test_aggregate_with_compile_regex_option
|
1385
|
+
return unless @version > '2.1.1'
|
1386
|
+
# see SERVER-6470
|
1387
|
+
return unless @version >= '2.3.2'
|
1388
|
+
@test.insert({ 'r' => /.*/ })
|
1389
|
+
result1 = @test.aggregate([])
|
1390
|
+
assert_kind_of Regexp, result1.first['r']
|
1391
|
+
|
1392
|
+
result2 = @test.aggregate([], :compile_regex => false)
|
1393
|
+
assert_kind_of BSON::Regex, result2.first['r']
|
1394
|
+
|
1395
|
+
return unless @version >= '2.5.1'
|
1396
|
+
result = @test.aggregate([], :compile_regex => false, :cursor => {})
|
1397
|
+
assert_kind_of BSON::Regex, result.first['r']
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
def test_out_aggregate
|
1401
|
+
return unless @version >= "2.5.2"
|
1402
|
+
out_collection = 'test_out'
|
1403
|
+
@db.drop_collection(out_collection)
|
1404
|
+
setup_aggregate_data
|
1405
|
+
docs = @test.find.to_a
|
1406
|
+
pipeline = [{:$out => out_collection}]
|
1407
|
+
@test.aggregate(pipeline)
|
1408
|
+
assert_equal docs, @db.collection(out_collection).find.to_a
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
def test_out_aggregate_nonprimary_sym_warns
|
1412
|
+
return unless @version >= "2.5.2"
|
1413
|
+
ReadPreference::expects(:warn).with(regexp_matches(/rerouted to primary/))
|
1414
|
+
pipeline = [{:$out => 'test_out'}]
|
1415
|
+
@test.aggregate(pipeline, :read => :secondary)
|
1416
|
+
end
|
1417
|
+
|
1418
|
+
def test_out_aggregate_nonprimary_string_warns
|
1419
|
+
return unless @version >= "2.5.2"
|
1420
|
+
ReadPreference::expects(:warn).with(regexp_matches(/rerouted to primary/))
|
1421
|
+
pipeline = [{'$out' => 'test_out'}]
|
1422
|
+
@test.aggregate(pipeline, :read => :secondary)
|
1423
|
+
end
|
1424
|
+
|
1425
|
+
def test_out_aggregate_string_returns_raw_response
|
1426
|
+
return unless @version >= "2.5.2"
|
1427
|
+
pipeline = [{'$out' => 'test_out'}]
|
1428
|
+
response = @test.aggregate(pipeline)
|
1429
|
+
assert response.respond_to?(:keys)
|
1430
|
+
end
|
1431
|
+
|
1432
|
+
def test_out_aggregate_sym_returns_raw_response
|
1433
|
+
return unless @version >= "2.5.2"
|
1434
|
+
pipeline = [{:$out => 'test_out'}]
|
1435
|
+
response = @test.aggregate(pipeline)
|
1436
|
+
assert response.respond_to?(:keys)
|
1437
|
+
end
|
1438
|
+
|
1439
|
+
def test_map_reduce
|
1440
|
+
return unless @version > "1.1.1"
|
1441
|
+
@test << { "user_id" => 1 }
|
1442
|
+
@test << { "user_id" => 2 }
|
1443
|
+
|
1444
|
+
m = "function() { emit(this.user_id, 1); }"
|
1445
|
+
r = "function(k,vals) { return 1; }"
|
1446
|
+
res = @test.map_reduce(m, r, :out => 'foo')
|
1447
|
+
assert res.find_one({"_id" => 1})
|
1448
|
+
assert res.find_one({"_id" => 2})
|
1449
|
+
end
|
1450
|
+
|
1451
|
+
def test_map_reduce_with_code_objects
|
1452
|
+
return unless @version > "1.1.1"
|
1453
|
+
@test << { "user_id" => 1 }
|
1454
|
+
@test << { "user_id" => 2 }
|
1455
|
+
|
1456
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
1457
|
+
r = Code.new("function(k,vals) { return 1; }")
|
1458
|
+
res = @test.map_reduce(m, r, :out => 'foo')
|
1459
|
+
assert res.find_one({"_id" => 1})
|
1460
|
+
assert res.find_one({"_id" => 2})
|
1461
|
+
end
|
1462
|
+
|
1463
|
+
def test_map_reduce_with_options
|
1464
|
+
return unless @version > "1.1.1"
|
1465
|
+
@test.remove
|
1466
|
+
@test << { "user_id" => 1 }
|
1467
|
+
@test << { "user_id" => 2 }
|
1468
|
+
@test << { "user_id" => 3 }
|
1469
|
+
|
1470
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
1471
|
+
r = Code.new("function(k,vals) { return 1; }")
|
1472
|
+
res = @test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo')
|
1473
|
+
assert_equal 2, res.count
|
1474
|
+
assert res.find_one({"_id" => 2})
|
1475
|
+
assert res.find_one({"_id" => 3})
|
1476
|
+
end
|
1477
|
+
|
1478
|
+
def test_map_reduce_with_raw_response
|
1479
|
+
return unless @version > "1.1.1"
|
1480
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
1481
|
+
r = Code.new("function(k,vals) { return 1; }")
|
1482
|
+
res = @test.map_reduce(m, r, :raw => true, :out => 'foo')
|
1483
|
+
assert res["result"]
|
1484
|
+
assert res["counts"]
|
1485
|
+
assert res["timeMillis"]
|
1486
|
+
end
|
1487
|
+
|
1488
|
+
def test_map_reduce_with_output_collection
|
1489
|
+
return unless @version > "1.1.1"
|
1490
|
+
output_collection = "test-map-coll"
|
1491
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
1492
|
+
r = Code.new("function(k,vals) { return 1; }")
|
1493
|
+
res = @test.map_reduce(m, r, :raw => true, :out => output_collection)
|
1494
|
+
assert_equal output_collection, res["result"]
|
1495
|
+
assert res["counts"]
|
1496
|
+
assert res["timeMillis"]
|
1497
|
+
end
|
1498
|
+
|
1499
|
+
def test_map_reduce_nonprimary_output_collection_reroutes
|
1500
|
+
return unless @version > "1.1.1"
|
1501
|
+
output_collection = "test-map-coll"
|
1502
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
1503
|
+
r = Code.new("function(k,vals) { return 1; }")
|
1504
|
+
Mongo::ReadPreference.expects(:warn).with(regexp_matches(/rerouted to primary/))
|
1505
|
+
res = @test.map_reduce(m, r, :raw => true, :out => output_collection, :read => :secondary)
|
1506
|
+
end
|
1507
|
+
|
1508
|
+
def test_map_reduce_with_collection_merge
|
1509
|
+
return unless @version >= "1.8.0"
|
1510
|
+
@test << {:user_id => 1}
|
1511
|
+
@test << {:user_id => 2}
|
1512
|
+
output_collection = "test-map-coll"
|
1513
|
+
m = Code.new("function() { emit(this.user_id, {count: 1}); }")
|
1514
|
+
r = Code.new("function(k,vals) { var sum = 0;" +
|
1515
|
+
" vals.forEach(function(v) { sum += v.count;} ); return {count: sum}; }")
|
1516
|
+
res = @test.map_reduce(m, r, :out => output_collection)
|
1517
|
+
|
1518
|
+
@test.remove
|
1519
|
+
@test << {:user_id => 3}
|
1520
|
+
res = @test.map_reduce(m, r, :out => {:merge => output_collection})
|
1521
|
+
assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 1}
|
1522
|
+
|
1523
|
+
@test.remove
|
1524
|
+
@test << {:user_id => 3}
|
1525
|
+
res = @test.map_reduce(m, r, :out => {:reduce => output_collection})
|
1526
|
+
assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 2}
|
1527
|
+
|
1528
|
+
assert_raise ArgumentError do
|
1529
|
+
@test.map_reduce(m, r, :out => {:inline => 1})
|
1530
|
+
end
|
1531
|
+
|
1532
|
+
@test.map_reduce(m, r, :raw => true, :out => {:inline => 1})
|
1533
|
+
assert res["results"]
|
1534
|
+
end
|
1535
|
+
|
1536
|
+
def test_map_reduce_with_collection_output_to_other_db
|
1537
|
+
return unless @version > "1.1.1"
|
1538
|
+
@test << {:user_id => 1}
|
1539
|
+
@test << {:user_id => 2}
|
1540
|
+
|
1541
|
+
m = Code.new("function() { emit(this.user_id, 1); }")
|
1542
|
+
r = Code.new("function(k,vals) { return 1; }")
|
1543
|
+
oh = BSON::OrderedHash.new
|
1544
|
+
oh[:replace] = 'foo'
|
1545
|
+
oh[:db] = TEST_DB
|
1546
|
+
res = @test.map_reduce(m, r, :out => (oh))
|
1547
|
+
assert res["result"]
|
1548
|
+
assert res["counts"]
|
1549
|
+
assert res["timeMillis"]
|
1550
|
+
assert res.find.to_a.any? {|doc| doc["_id"] == 2 && doc["value"] == 1}
|
1551
|
+
end
|
1552
|
+
|
1553
|
+
def test_aggregation_allow_disk_use
|
1554
|
+
return unless @version >= '2.5.5'
|
1555
|
+
@db.expects(:command).with do |selector, opts|
|
1556
|
+
opts[:allowDiskUse] == true
|
1557
|
+
end.returns({ 'ok' => 1 })
|
1558
|
+
@test.aggregate([], :allowDiskUse => true)
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
def test_parallel_scan
|
1562
|
+
return unless @version >= '2.5.5'
|
1563
|
+
8000.times { |i| @test.insert({ :_id => i }) }
|
1564
|
+
|
1565
|
+
lock = Mutex.new
|
1566
|
+
doc_ids = Set.new
|
1567
|
+
threads = []
|
1568
|
+
cursors = @test.parallel_scan(3)
|
1569
|
+
cursors.each_with_index do |cursor, i|
|
1570
|
+
threads << Thread.new do
|
1571
|
+
docs = cursor.to_a
|
1572
|
+
lock.synchronize do
|
1573
|
+
docs.each do |doc|
|
1574
|
+
doc_ids << doc['_id']
|
1575
|
+
end
|
1576
|
+
end
|
1577
|
+
end
|
1578
|
+
end
|
1579
|
+
threads.each(&:join)
|
1580
|
+
assert_equal 8000, doc_ids.count
|
1581
|
+
end
|
1582
|
+
|
1583
|
+
def test_find_and_modify
|
1584
|
+
return unless @version > "1.3.0"
|
1585
|
+
@test << { :a => 1, :processed => false }
|
1586
|
+
@test << { :a => 2, :processed => false }
|
1587
|
+
@test << { :a => 3, :processed => false }
|
1588
|
+
|
1589
|
+
@test.find_and_modify(:query => {},
|
1590
|
+
:sort => [['a', -1]],
|
1591
|
+
:update => {"$set" => {:processed => true}})
|
1592
|
+
|
1593
|
+
assert @test.find_one({:a => 3})['processed']
|
1594
|
+
end
|
1595
|
+
|
1596
|
+
def test_find_and_modify_with_invalid_options
|
1597
|
+
@test << { :a => 1, :processed => false }
|
1598
|
+
@test << { :a => 2, :processed => false }
|
1599
|
+
@test << { :a => 3, :processed => false }
|
1600
|
+
|
1601
|
+
assert_raise Mongo::OperationFailure do
|
1602
|
+
@test.find_and_modify(:blimey => {})
|
1603
|
+
end
|
1604
|
+
end
|
1605
|
+
|
1606
|
+
def test_find_and_modify_with_full_response
|
1607
|
+
@test << { :a => 1, :processed => false }
|
1608
|
+
@test << { :a => 2, :processed => false }
|
1609
|
+
@test << { :a => 3, :processed => false }
|
1610
|
+
|
1611
|
+
doc = @test.find_and_modify(:query => {},
|
1612
|
+
:sort => [['a', -1]],
|
1613
|
+
:update => {"$set" => {:processed => true}},
|
1614
|
+
:full_response => true,
|
1615
|
+
:new => true)
|
1616
|
+
|
1617
|
+
assert doc['value']['processed']
|
1618
|
+
assert ['ok', 'value', 'lastErrorObject'].all? { |key| doc.key?(key) }
|
1619
|
+
end
|
1620
|
+
|
1621
|
+
def test_coll_stats
|
1622
|
+
return unless @version >= "1.3.5"
|
1623
|
+
@test << {:n => 1}
|
1624
|
+
@test.create_index("n")
|
1625
|
+
|
1626
|
+
assert_equal "#{TEST_DB}.test", @test.stats['ns']
|
1627
|
+
@test.drop
|
1628
|
+
end
|
1629
|
+
|
1630
|
+
def test_saving_dates_pre_epoch
|
1631
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/ then return true end
|
1632
|
+
begin
|
1633
|
+
@test.save({'date' => Time.utc(1600)})
|
1634
|
+
assert_in_delta Time.utc(1600), @test.find_one()["date"], 2
|
1635
|
+
rescue ArgumentError
|
1636
|
+
# See note in test_date_before_epoch (BSONTest)
|
1637
|
+
end
|
1638
|
+
end
|
1639
|
+
|
1640
|
+
def test_save_symbol_find_string
|
1641
|
+
@test.save(:foo => :mike)
|
1642
|
+
|
1643
|
+
assert_equal :mike, @test.find_one(:foo => :mike)["foo"]
|
1644
|
+
assert_equal :mike, @test.find_one("foo" => :mike)["foo"]
|
1645
|
+
|
1646
|
+
# TODO enable these tests conditionally based on server version (if >1.0)
|
1647
|
+
# assert_equal :mike, @test.find_one(:foo => "mike")["foo"]
|
1648
|
+
# assert_equal :mike, @test.find_one("foo" => "mike")["foo"]
|
1649
|
+
end
|
1650
|
+
|
1651
|
+
def test_batch_size
|
1652
|
+
n_docs = 6
|
1653
|
+
batch_size = n_docs/2
|
1654
|
+
n_docs.times do |i|
|
1655
|
+
@test.save(:foo => i)
|
1656
|
+
end
|
1657
|
+
|
1658
|
+
doc_count = 0
|
1659
|
+
cursor = @test.find({}, :batch_size => batch_size)
|
1660
|
+
cursor.next
|
1661
|
+
assert_equal batch_size, cursor.instance_variable_get(:@returned)
|
1662
|
+
doc_count += batch_size
|
1663
|
+
batch_size.times { cursor.next }
|
1664
|
+
assert_equal doc_count + batch_size, cursor.instance_variable_get(:@returned)
|
1665
|
+
doc_count += batch_size
|
1666
|
+
assert_equal n_docs, doc_count
|
1667
|
+
end
|
1668
|
+
|
1669
|
+
def test_batch_size_with_smaller_limit
|
1670
|
+
n_docs = 6
|
1671
|
+
batch_size = n_docs/2
|
1672
|
+
n_docs.times do |i|
|
1673
|
+
@test.insert(:foo => i)
|
1674
|
+
end
|
1675
|
+
|
1676
|
+
cursor = @test.find({}, :batch_size => batch_size, :limit => 2)
|
1677
|
+
cursor.next
|
1678
|
+
assert_equal 2, cursor.instance_variable_get(:@returned)
|
1679
|
+
end
|
1680
|
+
|
1681
|
+
def test_batch_size_with_larger_limit
|
1682
|
+
n_docs = 6
|
1683
|
+
batch_size = n_docs/2
|
1684
|
+
n_docs.times do |i|
|
1685
|
+
@test.insert(:foo => i)
|
1686
|
+
end
|
1687
|
+
|
1688
|
+
doc_count = 0
|
1689
|
+
cursor = @test.find({}, :batch_size => batch_size, :limit => n_docs + 5)
|
1690
|
+
cursor.next
|
1691
|
+
assert_equal batch_size, cursor.instance_variable_get(:@returned)
|
1692
|
+
doc_count += batch_size
|
1693
|
+
batch_size.times { cursor.next }
|
1694
|
+
assert_equal doc_count + batch_size, cursor.instance_variable_get(:@returned)
|
1695
|
+
doc_count += batch_size
|
1696
|
+
assert_equal n_docs, doc_count
|
1697
|
+
end
|
1698
|
+
|
1699
|
+
def test_batch_size_with_negative_limit
|
1700
|
+
n_docs = 6
|
1701
|
+
batch_size = n_docs/2
|
1702
|
+
n_docs.times do |i|
|
1703
|
+
@test.insert(:foo => i)
|
1704
|
+
end
|
1705
|
+
|
1706
|
+
cursor = @test.find({}, :batch_size => batch_size, :limit => -7)
|
1707
|
+
cursor.next
|
1708
|
+
assert_equal n_docs, cursor.instance_variable_get(:@returned)
|
1709
|
+
end
|
1710
|
+
|
1711
|
+
def test_limit_and_skip
|
1712
|
+
10.times do |i|
|
1713
|
+
@test.save(:foo => i)
|
1714
|
+
end
|
1715
|
+
|
1716
|
+
assert_equal 5, @test.find({}, :skip => 5).next_document()["foo"]
|
1717
|
+
assert_equal nil, @test.find({}, :skip => 10).next_document()
|
1718
|
+
|
1719
|
+
assert_equal 5, @test.find({}, :limit => 5).to_a.length
|
1720
|
+
|
1721
|
+
assert_equal 3, @test.find({}, :skip => 3, :limit => 5).next_document()["foo"]
|
1722
|
+
assert_equal 5, @test.find({}, :skip => 3, :limit => 5).to_a.length
|
1723
|
+
end
|
1724
|
+
|
1725
|
+
def test_large_limit
|
1726
|
+
2000.times do |i|
|
1727
|
+
@test.insert("x" => i, "y" => "mongomongo" * 1000)
|
1728
|
+
end
|
1729
|
+
|
1730
|
+
assert_equal 2000, @test.count
|
1731
|
+
|
1732
|
+
i = 0
|
1733
|
+
y = 0
|
1734
|
+
@test.find({}, :limit => 1900).each do |doc|
|
1735
|
+
i += 1
|
1736
|
+
y += doc["x"]
|
1737
|
+
end
|
1738
|
+
|
1739
|
+
assert_equal 1900, i
|
1740
|
+
assert_equal 1804050, y
|
1741
|
+
end
|
1742
|
+
|
1743
|
+
def test_small_limit
|
1744
|
+
@test.insert("x" => "hello world")
|
1745
|
+
@test.insert("x" => "goodbye world")
|
1746
|
+
|
1747
|
+
assert_equal 2, @test.count
|
1748
|
+
|
1749
|
+
x = 0
|
1750
|
+
@test.find({}, :limit => 1).each do |doc|
|
1751
|
+
x += 1
|
1752
|
+
assert_equal "hello world", doc["x"]
|
1753
|
+
end
|
1754
|
+
|
1755
|
+
assert_equal 1, x
|
1756
|
+
end
|
1757
|
+
|
1758
|
+
def test_find_with_transformer
|
1759
|
+
klass = Struct.new(:id, :a)
|
1760
|
+
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
1761
|
+
cursor = @test.find({}, :transformer => transformer)
|
1762
|
+
assert_equal(transformer, cursor.transformer)
|
1763
|
+
end
|
1764
|
+
|
1765
|
+
def test_find_one_with_transformer
|
1766
|
+
klass = Struct.new(:id, :a)
|
1767
|
+
transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
|
1768
|
+
id = @test.insert('a' => 1)
|
1769
|
+
doc = @test.find_one(id, :transformer => transformer)
|
1770
|
+
assert_instance_of(klass, doc)
|
1771
|
+
end
|
1772
|
+
|
1773
|
+
def test_ensure_index
|
1774
|
+
@test.drop_indexes
|
1775
|
+
@test.insert("x" => "hello world")
|
1776
|
+
assert_equal 1, @test.index_information.keys.count #default index
|
1777
|
+
|
1778
|
+
@test.ensure_index([["x", Mongo::DESCENDING]], {})
|
1779
|
+
assert_equal 2, @test.index_information.keys.count
|
1780
|
+
assert @test.index_information.keys.include?("x_-1")
|
1781
|
+
|
1782
|
+
@test.ensure_index([["x", Mongo::ASCENDING]])
|
1783
|
+
assert @test.index_information.keys.include?("x_1")
|
1784
|
+
|
1785
|
+
@test.ensure_index([["type", 1], ["date", -1]])
|
1786
|
+
assert @test.index_information.keys.include?("type_1_date_-1")
|
1787
|
+
|
1788
|
+
@test.drop_index("x_1")
|
1789
|
+
assert_equal 3, @test.index_information.keys.count
|
1790
|
+
@test.drop_index("x_-1")
|
1791
|
+
assert_equal 2, @test.index_information.keys.count
|
1792
|
+
|
1793
|
+
@test.ensure_index([["x", Mongo::DESCENDING]], {})
|
1794
|
+
assert_equal 3, @test.index_information.keys.count
|
1795
|
+
assert @test.index_information.keys.include?("x_-1")
|
1796
|
+
|
1797
|
+
# Make sure that drop_index expires cache properly
|
1798
|
+
@test.ensure_index([['a', 1]])
|
1799
|
+
assert @test.index_information.keys.include?("a_1")
|
1800
|
+
@test.drop_index("a_1")
|
1801
|
+
assert !@test.index_information.keys.include?("a_1")
|
1802
|
+
@test.ensure_index([['a', 1]])
|
1803
|
+
assert @test.index_information.keys.include?("a_1")
|
1804
|
+
@test.drop_index("a_1")
|
1805
|
+
@test.drop_indexes
|
1806
|
+
end
|
1807
|
+
|
1808
|
+
def test_ensure_index_timeout
|
1809
|
+
@db.cache_time = 1
|
1810
|
+
coll = @db['ensure_test']
|
1811
|
+
coll.expects(:generate_indexes).twice
|
1812
|
+
coll.ensure_index([['a', 1]])
|
1813
|
+
|
1814
|
+
# These will be cached
|
1815
|
+
coll.ensure_index([['a', 1]])
|
1816
|
+
coll.ensure_index([['a', 1]])
|
1817
|
+
coll.ensure_index([['a', 1]])
|
1818
|
+
coll.ensure_index([['a', 1]])
|
1819
|
+
|
1820
|
+
sleep(1)
|
1821
|
+
# This won't be, so generate_indexes will be called twice
|
1822
|
+
coll.ensure_index([['a', 1]])
|
1823
|
+
coll.drop
|
1824
|
+
end
|
1825
|
+
|
1826
|
+
def test_show_disk_loc
|
1827
|
+
return unless @version > '2.0.0'
|
1828
|
+
@test.save({:a => 1})
|
1829
|
+
@test.save({:a => 2})
|
1830
|
+
assert @test.find({:a => 1}, :show_disk_loc => true).show_disk_loc
|
1831
|
+
doc = @test.find({:a => 1}, :show_disk_loc => true).next
|
1832
|
+
assert (doc['$diskLoc'] || doc['$recordId'])
|
1833
|
+
@test.remove
|
1834
|
+
end
|
1835
|
+
|
1836
|
+
def test_max_scan
|
1837
|
+
return unless @version > '2.0.0'
|
1838
|
+
@test.drop
|
1839
|
+
n = 100
|
1840
|
+
n.times do |i|
|
1841
|
+
@test.save({:_id => i, :x => i % 10})
|
1842
|
+
end
|
1843
|
+
assert_equal(n, @test.find.to_a.size)
|
1844
|
+
assert_equal(50, @test.find({}, :max_scan => 50).to_a.size)
|
1845
|
+
assert_equal(10, @test.find({:x => 2}).to_a.size)
|
1846
|
+
assert_equal(5, @test.find({:x => 2}, :max_scan => 50).to_a.size)
|
1847
|
+
@test.ensure_index([[:x, 1]])
|
1848
|
+
assert_equal(10, @test.find({:x => 2}, :max_scan => n).to_a.size)
|
1849
|
+
@test.drop
|
1850
|
+
end
|
1851
|
+
|
1852
|
+
context "Grouping" do
|
1853
|
+
setup do
|
1854
|
+
@test.remove
|
1855
|
+
@test.save("a" => 1)
|
1856
|
+
@test.save("b" => 1)
|
1857
|
+
@initial = {"count" => 0}
|
1858
|
+
@reduce_function = "function (obj, prev) { prev.count += inc_value; }"
|
1859
|
+
end
|
1860
|
+
|
1861
|
+
should "fail if missing required options" do
|
1862
|
+
assert_raise MongoArgumentError do
|
1863
|
+
@test.group(:initial => {})
|
1864
|
+
end
|
1865
|
+
|
1866
|
+
assert_raise MongoArgumentError do
|
1867
|
+
@test.group(:reduce => "foo")
|
1868
|
+
end
|
1869
|
+
end
|
1870
|
+
|
1871
|
+
should "group results using eval form" do
|
1872
|
+
assert_equal 1, @test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 0.5}))[0]["count"]
|
1873
|
+
assert_equal 2, @test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}))[0]["count"]
|
1874
|
+
assert_equal 4, @test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 2}))[0]["count"]
|
1875
|
+
end
|
1876
|
+
|
1877
|
+
should "finalize grouped results" do
|
1878
|
+
@finalize = "function(doc) {doc.f = doc.count + 200; }"
|
1879
|
+
assert_equal 202, @test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}), :finalize => @finalize)[0]["f"]
|
1880
|
+
end
|
1881
|
+
end
|
1882
|
+
|
1883
|
+
context "Grouping with key" do
|
1884
|
+
setup do
|
1885
|
+
@test.remove
|
1886
|
+
@test.save("a" => 1, "pop" => 100)
|
1887
|
+
@test.save("a" => 1, "pop" => 100)
|
1888
|
+
@test.save("a" => 2, "pop" => 100)
|
1889
|
+
@test.save("a" => 2, "pop" => 100)
|
1890
|
+
@initial = {"count" => 0, "foo" => 1}
|
1891
|
+
@reduce_function = "function (obj, prev) { prev.count += obj.pop; }"
|
1892
|
+
end
|
1893
|
+
|
1894
|
+
should "group" do
|
1895
|
+
result = @test.group(:key => :a, :initial => @initial, :reduce => @reduce_function)
|
1896
|
+
assert result.all? { |r| r['count'] == 200 }
|
1897
|
+
end
|
1898
|
+
end
|
1899
|
+
|
1900
|
+
context "Grouping with a key function" do
|
1901
|
+
setup do
|
1902
|
+
@test.remove
|
1903
|
+
@test.save("a" => 1)
|
1904
|
+
@test.save("a" => 2)
|
1905
|
+
@test.save("a" => 3)
|
1906
|
+
@test.save("a" => 4)
|
1907
|
+
@test.save("a" => 5)
|
1908
|
+
@initial = {"count" => 0}
|
1909
|
+
@keyf = "function (doc) { if(doc.a % 2 == 0) { return {even: true}; } else {return {odd: true}} };"
|
1910
|
+
@reduce = "function (obj, prev) { prev.count += 1; }"
|
1911
|
+
end
|
1912
|
+
|
1913
|
+
should "group results" do
|
1914
|
+
results = @test.group(:keyf => @keyf, :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
|
1915
|
+
assert results[0]['even'] && results[0]['count'] == 2.0
|
1916
|
+
assert results[1]['odd'] && results[1]['count'] == 3.0
|
1917
|
+
end
|
1918
|
+
|
1919
|
+
should "group filtered results" do
|
1920
|
+
results = @test.group(:keyf => @keyf, :cond => {:a => {'$ne' => 2}},
|
1921
|
+
:initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
|
1922
|
+
assert results[0]['even'] && results[0]['count'] == 1.0
|
1923
|
+
assert results[1]['odd'] && results[1]['count'] == 3.0
|
1924
|
+
end
|
1925
|
+
end
|
1926
|
+
|
1927
|
+
context "A collection with two records" do
|
1928
|
+
setup do
|
1929
|
+
@collection = @db.collection('test-collection')
|
1930
|
+
@collection.remove
|
1931
|
+
@collection.insert({:name => "Jones"})
|
1932
|
+
@collection.insert({:name => "Smith"})
|
1933
|
+
end
|
1934
|
+
|
1935
|
+
should "have two records" do
|
1936
|
+
assert_equal 2, @collection.size
|
1937
|
+
end
|
1938
|
+
|
1939
|
+
should "remove the two records" do
|
1940
|
+
@collection.remove()
|
1941
|
+
assert_equal 0, @collection.size
|
1942
|
+
end
|
1943
|
+
|
1944
|
+
should "remove all records if an empty document is specified" do
|
1945
|
+
@collection.remove({})
|
1946
|
+
assert_equal 0, @collection.find.count
|
1947
|
+
end
|
1948
|
+
|
1949
|
+
should "remove only matching records" do
|
1950
|
+
@collection.remove({:name => "Jones"})
|
1951
|
+
assert_equal 1, @collection.size
|
1952
|
+
end
|
1953
|
+
end
|
1954
|
+
|
1955
|
+
context "Drop index " do
|
1956
|
+
setup do
|
1957
|
+
@db.drop_collection('test-collection')
|
1958
|
+
@collection = @db.collection('test-collection')
|
1959
|
+
end
|
1960
|
+
|
1961
|
+
should "drop an index" do
|
1962
|
+
@collection.create_index([['a', Mongo::ASCENDING]])
|
1963
|
+
assert @collection.index_information['a_1']
|
1964
|
+
@collection.drop_index([['a', Mongo::ASCENDING]])
|
1965
|
+
assert_nil @collection.index_information['a_1']
|
1966
|
+
end
|
1967
|
+
|
1968
|
+
should "drop an index which was given a specific name" do
|
1969
|
+
@collection.create_index([['a', Mongo::DESCENDING]], {:name => 'i_will_not_fear'})
|
1970
|
+
assert @collection.index_information['i_will_not_fear']
|
1971
|
+
@collection.drop_index([['a', Mongo::DESCENDING]])
|
1972
|
+
assert_nil @collection.index_information['i_will_not_fear']
|
1973
|
+
end
|
1974
|
+
|
1975
|
+
should "drops an composite index" do
|
1976
|
+
@collection.create_index([['a', Mongo::DESCENDING], ['b', Mongo::ASCENDING]])
|
1977
|
+
assert @collection.index_information['a_-1_b_1']
|
1978
|
+
@collection.drop_index([['a', Mongo::DESCENDING], ['b', Mongo::ASCENDING]])
|
1979
|
+
assert_nil @collection.index_information['a_-1_b_1']
|
1980
|
+
end
|
1981
|
+
|
1982
|
+
should "drops an index with symbols" do
|
1983
|
+
@collection.create_index([['a', Mongo::DESCENDING], [:b, Mongo::ASCENDING]])
|
1984
|
+
assert @collection.index_information['a_-1_b_1']
|
1985
|
+
@collection.drop_index([['a', Mongo::DESCENDING], [:b, Mongo::ASCENDING]])
|
1986
|
+
assert_nil @collection.index_information['a_-1_b_1']
|
1987
|
+
end
|
1988
|
+
end
|
1989
|
+
|
1990
|
+
context "Creating indexes " do
|
1991
|
+
setup do
|
1992
|
+
@db.drop_collection('geo')
|
1993
|
+
@db.drop_collection('test-collection')
|
1994
|
+
@collection = @db.collection('test-collection')
|
1995
|
+
@geo = @db.collection('geo')
|
1996
|
+
end
|
1997
|
+
|
1998
|
+
should "create index using symbols" do
|
1999
|
+
@collection.create_index :foo, :name => :bar
|
2000
|
+
@geo.create_index :goo, :name => :baz
|
2001
|
+
assert @collection.index_information['bar']
|
2002
|
+
@collection.drop_index :bar
|
2003
|
+
assert_nil @collection.index_information['bar']
|
2004
|
+
assert @geo.index_information['baz']
|
2005
|
+
@geo.drop_index(:baz)
|
2006
|
+
assert_nil @geo.index_information['baz']
|
2007
|
+
end
|
2008
|
+
|
2009
|
+
#should "create a text index" do
|
2010
|
+
# @geo.save({'title' => "some text"})
|
2011
|
+
# @geo.create_index([['title', Mongo::TEXT]])
|
2012
|
+
# assert @geo.index_information['title_text']
|
2013
|
+
#end
|
2014
|
+
|
2015
|
+
should "create a hashed index" do
|
2016
|
+
@geo.save({'a' => 1})
|
2017
|
+
@geo.create_index([['a', Mongo::HASHED]])
|
2018
|
+
assert @geo.index_information['a_hashed']
|
2019
|
+
end
|
2020
|
+
|
2021
|
+
should "create a geospatial index" do
|
2022
|
+
@geo.save({'loc' => [-100, 100]})
|
2023
|
+
@geo.create_index([['loc', Mongo::GEO2D]])
|
2024
|
+
assert @geo.index_information['loc_2d']
|
2025
|
+
end
|
2026
|
+
|
2027
|
+
should "create a geoHaystack index" do
|
2028
|
+
@geo.save({ "_id" => 100, "pos" => { "long" => 126.9, "lat" => 35.2 }, "type" => "restaurant"})
|
2029
|
+
@geo.create_index([['pos', Mongo::GEOHAYSTACK], ['type', Mongo::ASCENDING]], :bucket_size => 1)
|
2030
|
+
assert @geo.index_information['pos_geoHaystack_type_1']
|
2031
|
+
end
|
2032
|
+
|
2033
|
+
should "create a geo 2dsphere index" do
|
2034
|
+
@collection.insert({"coordinates" => [ 5 , 5 ], "type" => "Point"})
|
2035
|
+
@geo.create_index([['coordinates', Mongo::GEO2DSPHERE]])
|
2036
|
+
assert @geo.index_information['coordinates_2dsphere']
|
2037
|
+
end
|
2038
|
+
|
2039
|
+
should "create a unique index" do
|
2040
|
+
@collection.create_index([['a', Mongo::ASCENDING]], :unique => true)
|
2041
|
+
assert @collection.index_information['a_1']['unique'] == true
|
2042
|
+
end
|
2043
|
+
|
2044
|
+
should "drop duplicates" do
|
2045
|
+
if @version < '2.7'
|
2046
|
+
@collection.insert({:a => 1})
|
2047
|
+
@collection.insert({:a => 1})
|
2048
|
+
assert_equal 2, @collection.find({:a => 1}).count
|
2049
|
+
@collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :dropDups => true)
|
2050
|
+
assert_equal 1, @collection.find({:a => 1}).count
|
2051
|
+
end
|
2052
|
+
end
|
2053
|
+
|
2054
|
+
should "drop duplicates with ruby-like drop_dups key" do
|
2055
|
+
if @version < '2.7'
|
2056
|
+
@collection.insert({:a => 1})
|
2057
|
+
@collection.insert({:a => 1})
|
2058
|
+
assert_equal 2, @collection.find({:a => 1}).count
|
2059
|
+
@collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true)
|
2060
|
+
assert_equal 1, @collection.find({:a => 1}).count
|
2061
|
+
end
|
2062
|
+
end
|
2063
|
+
|
2064
|
+
should "drop duplicates with ensure_index and drop_dups key" do
|
2065
|
+
if @version < '2.7'
|
2066
|
+
@collection.insert({:a => 1})
|
2067
|
+
@collection.insert({:a => 1})
|
2068
|
+
assert_equal 2, @collection.find({:a => 1}).count
|
2069
|
+
@collection.ensure_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true)
|
2070
|
+
assert_equal 1, @collection.find({:a => 1}).count
|
2071
|
+
end
|
2072
|
+
end
|
2073
|
+
|
2074
|
+
should "create an index in the background" do
|
2075
|
+
if @version > '1.3.1'
|
2076
|
+
@collection.create_index([['b', Mongo::ASCENDING]], :background => true)
|
2077
|
+
assert @collection.index_information['b_1']['background'] == true
|
2078
|
+
else
|
2079
|
+
assert true
|
2080
|
+
end
|
2081
|
+
end
|
2082
|
+
|
2083
|
+
should "require an array of arrays" do
|
2084
|
+
assert_raise MongoArgumentError do
|
2085
|
+
@collection.create_index(['c', Mongo::ASCENDING])
|
2086
|
+
end
|
2087
|
+
end
|
2088
|
+
|
2089
|
+
should "enforce proper index types" do
|
2090
|
+
assert_raise MongoArgumentError do
|
2091
|
+
@collection.create_index([['c', 'blah']])
|
2092
|
+
end
|
2093
|
+
end
|
2094
|
+
|
2095
|
+
should "raise an error if index name is greater than 128" do
|
2096
|
+
assert_raise Mongo::OperationFailure do
|
2097
|
+
@collection.create_index([['a' * 25, 1], ['b' * 25, 1],
|
2098
|
+
['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]])
|
2099
|
+
end
|
2100
|
+
end
|
2101
|
+
|
2102
|
+
should "allow for an alternate name to be specified" do
|
2103
|
+
@collection.create_index([['a' * 25, 1], ['b' * 25, 1],
|
2104
|
+
['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]], :name => 'foo_index')
|
2105
|
+
assert @collection.index_information['foo_index']
|
2106
|
+
end
|
2107
|
+
|
2108
|
+
should "generate indexes in the proper order" do
|
2109
|
+
key = BSON::OrderedHash['b', 1, 'a', 1]
|
2110
|
+
if @version < '2.5.5'
|
2111
|
+
@collection.expects(:send_write) do |type, selector, documents, check_keys, opts, collection_name|
|
2112
|
+
assert_equal key, selector[:key]
|
2113
|
+
end
|
2114
|
+
else
|
2115
|
+
@collection.db.expects(:command) do |selector|
|
2116
|
+
assert_equal key, selector[:indexes].first[:key]
|
2117
|
+
end
|
2118
|
+
end
|
2119
|
+
@collection.create_index([['b', 1], ['a', 1]])
|
2120
|
+
end
|
2121
|
+
|
2122
|
+
should "allow creation of multiple indexes" do
|
2123
|
+
assert @collection.create_index([['a', 1]])
|
2124
|
+
assert @collection.create_index([['a', 1]])
|
2125
|
+
end
|
2126
|
+
|
2127
|
+
context "with an index created" do
|
2128
|
+
setup do
|
2129
|
+
@collection.create_index([['b', 1], ['a', 1]])
|
2130
|
+
end
|
2131
|
+
|
2132
|
+
should "return properly ordered index information" do
|
2133
|
+
assert @collection.index_information['b_1_a_1']
|
2134
|
+
end
|
2135
|
+
end
|
2136
|
+
end
|
2137
|
+
|
2138
|
+
context "Capped collections" do
|
2139
|
+
setup do
|
2140
|
+
@db.drop_collection('log')
|
2141
|
+
@capped = @db.create_collection('log', :capped => true, :size => LIMITED_MAX_BSON_SIZE)
|
2142
|
+
|
2143
|
+
10.times { |n| @capped.insert({:n => n}) }
|
2144
|
+
end
|
2145
|
+
|
2146
|
+
should "find using a standard cursor" do
|
2147
|
+
cursor = @capped.find
|
2148
|
+
10.times do
|
2149
|
+
assert cursor.next_document
|
2150
|
+
end
|
2151
|
+
assert_nil cursor.next_document
|
2152
|
+
@capped.insert({:n => 100})
|
2153
|
+
assert_nil cursor.next_document
|
2154
|
+
end
|
2155
|
+
|
2156
|
+
should "fail tailable cursor on a non-capped collection" do
|
2157
|
+
col = @db['regular-collection']
|
2158
|
+
col.insert({:a => 1000})
|
2159
|
+
tail = Cursor.new(col, :tailable => true, :order => [['$natural', 1]])
|
2160
|
+
assert_raise OperationFailure do
|
2161
|
+
tail.next_document
|
2162
|
+
end
|
2163
|
+
end
|
2164
|
+
|
2165
|
+
should "find using a tailable cursor" do
|
2166
|
+
tail = Cursor.new(@capped, :tailable => true, :order => [['$natural', 1]])
|
2167
|
+
10.times do
|
2168
|
+
assert tail.next_document
|
2169
|
+
end
|
2170
|
+
assert_nil tail.next_document
|
2171
|
+
@capped.insert({:n => 100})
|
2172
|
+
assert tail.next_document
|
2173
|
+
end
|
2174
|
+
end
|
2175
|
+
end
|