mongo 1.8.6 → 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.
Files changed (129) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/LICENSE +1 -1
  4. data/README.md +114 -282
  5. data/Rakefile +18 -4
  6. data/VERSION +1 -1
  7. data/bin/mongo_console +27 -5
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +283 -222
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/{util → connection}/node.rb +58 -6
  12. data/lib/mongo/{util → connection}/pool.rb +61 -37
  13. data/lib/mongo/{util → connection}/pool_manager.rb +72 -22
  14. data/lib/mongo/{util → connection}/sharding_pool_manager.rb +13 -0
  15. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  16. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  17. data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
  18. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection.rb +19 -0
  21. data/lib/mongo/cursor.rb +183 -57
  22. data/lib/mongo/db.rb +302 -138
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/{util → functional}/logging.rb +23 -7
  26. data/lib/mongo/functional/read_preference.rb +183 -0
  27. data/lib/mongo/functional/scram.rb +556 -0
  28. data/lib/mongo/functional/uri_parser.rb +409 -0
  29. data/lib/mongo/{util → functional}/write_concern.rb +21 -9
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +19 -8
  32. data/lib/mongo/gridfs/grid_ext.rb +14 -0
  33. data/lib/mongo/gridfs/grid_file_system.rb +17 -4
  34. data/lib/mongo/gridfs/grid_io.rb +21 -9
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +76 -7
  37. data/lib/mongo/mongo_client.rb +246 -206
  38. data/lib/mongo/mongo_replica_set_client.rb +65 -15
  39. data/lib/mongo/mongo_sharded_client.rb +18 -3
  40. data/lib/mongo/networking.rb +47 -18
  41. data/lib/mongo/{util → utils}/conversions.rb +18 -3
  42. data/lib/mongo/{util → utils}/core_ext.rb +15 -32
  43. data/lib/mongo/{util → utils}/server_version.rb +15 -0
  44. data/lib/mongo/{util → utils}/support.rb +22 -55
  45. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  46. data/lib/mongo/utils.rb +19 -0
  47. data/lib/mongo.rb +44 -26
  48. data/mongo.gemspec +2 -2
  49. data/test/functional/authentication_test.rb +31 -10
  50. data/test/functional/bulk_api_stress_test.rb +133 -0
  51. data/test/functional/bulk_write_collection_view_test.rb +1198 -0
  52. data/test/functional/client_test.rb +627 -0
  53. data/test/functional/collection_test.rb +1419 -654
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/functional/conversions_test.rb +46 -2
  56. data/test/functional/cursor_fail_test.rb +17 -9
  57. data/test/functional/cursor_message_test.rb +28 -15
  58. data/test/functional/cursor_test.rb +300 -165
  59. data/test/functional/db_api_test.rb +294 -264
  60. data/test/functional/db_connection_test.rb +15 -3
  61. data/test/functional/db_test.rb +165 -99
  62. data/test/functional/grid_file_system_test.rb +124 -112
  63. data/test/functional/grid_io_test.rb +17 -3
  64. data/test/functional/grid_test.rb +16 -2
  65. data/test/functional/pool_test.rb +99 -10
  66. data/test/functional/safe_test.rb +18 -4
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +14 -0
  69. data/test/functional/timeout_test.rb +27 -27
  70. data/test/functional/uri_test.rb +268 -22
  71. data/test/functional/write_concern_test.rb +19 -5
  72. data/test/helpers/general.rb +50 -0
  73. data/test/helpers/test_unit.rb +476 -0
  74. data/test/replica_set/authentication_test.rb +28 -11
  75. data/test/replica_set/basic_test.rb +79 -23
  76. data/test/replica_set/client_test.rb +253 -124
  77. data/test/replica_set/connection_test.rb +59 -37
  78. data/test/replica_set/count_test.rb +18 -2
  79. data/test/replica_set/cursor_test.rb +30 -8
  80. data/test/replica_set/insert_test.rb +109 -2
  81. data/test/replica_set/max_values_test.rb +85 -10
  82. data/test/replica_set/pinning_test.rb +66 -2
  83. data/test/replica_set/query_test.rb +17 -3
  84. data/test/replica_set/read_preference_test.rb +115 -96
  85. data/test/replica_set/refresh_test.rb +59 -9
  86. data/test/replica_set/replication_ack_test.rb +32 -11
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +73 -25
  89. data/test/shared/authentication/basic_auth_shared.rb +260 -0
  90. data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
  91. data/test/shared/authentication/gssapi_shared.rb +176 -0
  92. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  93. data/test/shared/authentication/scram_shared.rb +92 -0
  94. data/test/shared/ssl_shared.rb +235 -0
  95. data/test/test_helper.rb +47 -196
  96. data/test/threading/basic_test.rb +42 -2
  97. data/test/tools/mongo_config.rb +175 -35
  98. data/test/tools/mongo_config_test.rb +15 -1
  99. data/test/unit/client_test.rb +186 -57
  100. data/test/unit/collection_test.rb +44 -54
  101. data/test/unit/connection_test.rb +160 -71
  102. data/test/unit/cursor_test.rb +37 -3
  103. data/test/unit/db_test.rb +38 -14
  104. data/test/unit/grid_test.rb +15 -1
  105. data/test/unit/mongo_sharded_client_test.rb +30 -14
  106. data/test/unit/node_test.rb +16 -1
  107. data/test/unit/pool_manager_test.rb +21 -4
  108. data/test/unit/read_pref_test.rb +386 -1
  109. data/test/unit/read_test.rb +27 -13
  110. data/test/unit/safe_test.rb +22 -8
  111. data/test/unit/sharding_pool_manager_test.rb +25 -4
  112. data/test/unit/write_concern_test.rb +23 -9
  113. data.tar.gz.sig +0 -0
  114. metadata +80 -54
  115. metadata.gz.sig +0 -0
  116. data/lib/mongo/exceptions.rb +0 -65
  117. data/lib/mongo/util/read_preference.rb +0 -112
  118. data/lib/mongo/util/socket_util.rb +0 -20
  119. data/lib/mongo/util/ssl_socket.rb +0 -51
  120. data/lib/mongo/util/tcp_socket.rb +0 -62
  121. data/lib/mongo/util/thread_local_variable_manager.rb +0 -11
  122. data/lib/mongo/util/unix_socket.rb +0 -23
  123. data/lib/mongo/util/uri_parser.rb +0 -337
  124. data/test/functional/connection_test.rb +0 -449
  125. data/test/functional/threading_test.rb +0 -95
  126. data/test/replica_set/complex_connect_test.rb +0 -64
  127. data/test/shared/authentication.rb +0 -66
  128. data/test/unit/pool_test.rb +0 -9
  129. data/test/unit/util_test.rb +0 -55
@@ -1,90 +1,500 @@
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
+
1
15
  require 'rbconfig'
2
16
  require 'test_helper'
3
17
 
4
- class TestCollection < Test::Unit::TestCase
5
- @@client ||= standard_connection(:op_timeout => 10)
6
- @@db = @@client.db(MONGO_TEST_DB)
7
- @@test = @@db.collection("test")
8
- @@version = @@client.server_version
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
9
26
 
10
27
  def setup
11
- @@test.remove
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']
12
420
  end
13
421
 
14
422
  def test_capped_method
15
- @@db.create_collection('normal')
16
- assert !@@db['normal'].capped?
17
- @@db.drop_collection('normal')
423
+ @db.create_collection('normal')
424
+ assert !@db['normal'].capped?
425
+ @db.drop_collection('normal')
18
426
 
19
- @@db.create_collection('c', :capped => true, :size => 100_000)
20
- assert @@db['c'].capped?
21
- @@db.drop_collection('c')
427
+ @db.create_collection('c', :capped => true, :size => 100_000)
428
+ assert @db['c'].capped?
429
+ @db.drop_collection('c')
22
430
  end
23
431
 
24
432
  def test_optional_pk_factory
25
- @coll_default_pk = @@db.collection('stuff')
433
+ @coll_default_pk = @db.collection('stuff')
26
434
  assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
27
- @coll_default_pk = @@db.create_collection('more-stuff')
435
+ @coll_default_pk = @db.create_collection('more-stuff')
28
436
  assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
29
437
 
30
438
  # Create a db with a pk_factory.
31
- @db = MongoClient.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
32
- ENV['MONGO_RUBY_DRIVER_PORT'] || MongoClient::DEFAULT_PORT).db(MONGO_TEST_DB, :pk => Object.new)
33
- @coll = @db.collection('coll-with-pk')
34
- assert @coll.pk_factory.is_a?(Object)
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)
35
443
 
36
- @coll = @db.create_collection('created_coll_with_pk')
37
- assert @coll.pk_factory.is_a?(Object)
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)
38
449
  end
39
450
 
40
- class TestPK
451
+ class PKTest
41
452
  def self.create_pk
42
453
  end
43
454
  end
44
455
 
45
456
  def test_pk_factory_on_collection
46
457
  silently do
47
- @coll = Collection.new('foo', @@db, TestPK)
48
- assert_equal TestPK, @coll.pk_factory
458
+ @coll = Collection.new('foo', @db, PKTest)
459
+ assert_equal PKTest, @coll.pk_factory
49
460
  end
50
461
 
51
-
52
- @coll2 = Collection.new('foo', @@db, :pk => TestPK)
53
- assert_equal TestPK, @coll2.pk_factory
462
+ @coll2 = Collection.new('foo', @db, :pk => PKTest)
463
+ assert_equal PKTest, @coll2.pk_factory
54
464
  end
55
465
 
56
466
  def test_valid_names
57
467
  assert_raise Mongo::InvalidNSName do
58
- @@db["te$t"]
468
+ @db["te$t"]
59
469
  end
60
470
 
61
471
  assert_raise Mongo::InvalidNSName do
62
- @@db['$main']
472
+ @db['$main']
63
473
  end
64
474
 
65
- assert @@db['$cmd']
66
- assert @@db['oplog.$main']
475
+ assert @db['$cmd']
476
+ assert @db['oplog.$main']
67
477
  end
68
478
 
69
479
  def test_collection
70
- assert_kind_of Collection, @@db["test"]
71
- assert_equal @@db["test"].name(), @@db.collection("test").name()
72
- assert_equal @@db["test"].name(), @@db[:test].name()
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()
73
483
 
74
- assert_kind_of Collection, @@db["test"]["foo"]
75
- assert_equal @@db["test"]["foo"].name(), @@db.collection("test.foo").name()
76
- assert_equal @@db["test"]["foo"].name(), @@db["test.foo"].name()
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()
77
487
 
78
- @@db["test"]["foo"].remove
79
- @@db["test"]["foo"].insert("x" => 5)
80
- assert_equal 5, @@db.collection("test.foo").find_one()["x"]
488
+ @db["test"]["foo"].remove
489
+ @db["test"]["foo"].insert("x" => 5)
490
+ assert_equal 5, @db.collection("test.foo").find_one()["x"]
81
491
  end
82
492
 
83
493
  def test_rename_collection
84
- @@db.drop_collection('foo1')
85
- @@db.drop_collection('bar1')
494
+ @db.drop_collection('foo1')
495
+ @db.drop_collection('bar1')
86
496
 
87
- @col = @@db.create_collection('foo1')
497
+ @col = @db.create_collection('foo1')
88
498
  assert_equal 'foo1', @col.name
89
499
 
90
500
  @col.rename('bar1')
@@ -92,65 +502,69 @@ class TestCollection < Test::Unit::TestCase
92
502
  end
93
503
 
94
504
  def test_nil_id
95
- assert_equal 5, @@test.insert({"_id" => 5, "foo" => "bar"})
96
- assert_equal 5, @@test.save({"_id" => 5, "foo" => "baz"})
97
- assert_equal nil, @@test.find_one("foo" => "bar")
98
- assert_equal "baz", @@test.find_one(:_id => 5)["foo"]
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"]
99
509
  assert_raise OperationFailure do
100
- @@test.insert({"_id" => 5, "foo" => "bar"})
510
+ @test.insert({"_id" => 5, "foo" => "bar"})
101
511
  end
102
512
 
103
- assert_equal nil, @@test.insert({"_id" => nil, "foo" => "bar"})
104
- assert_equal nil, @@test.save({"_id" => nil, "foo" => "baz"})
105
- assert_equal nil, @@test.find_one("foo" => "bar")
106
- assert_equal "baz", @@test.find_one(:_id => nil)["foo"]
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"]
107
517
  assert_raise OperationFailure do
108
- @@test.insert({"_id" => nil, "foo" => "bar"})
518
+ @test.insert({"_id" => nil, "foo" => "bar"})
109
519
  end
110
520
  assert_raise OperationFailure do
111
- @@test.insert({:_id => nil, "foo" => "bar"})
521
+ @test.insert({:_id => nil, "foo" => "bar"})
112
522
  end
113
523
  end
114
524
 
115
- if @@version > "1.1"
116
- def setup_for_distinct
117
- @@test.remove
118
- @@test.insert([{:a => 0, :b => {:c => "a"}},
119
- {:a => 1, :b => {:c => "b"}},
120
- {:a => 1, :b => {:c => "c"}},
121
- {:a => 2, :b => {:c => "a"}},
122
- {:a => 3},
123
- {:a => 3}])
124
- end
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
125
535
 
126
- def test_distinct_queries
127
- setup_for_distinct
128
- assert_equal [0, 1, 2, 3], @@test.distinct(:a).sort
129
- assert_equal ["a", "b", "c"], @@test.distinct("b.c").sort
130
- end
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
131
542
 
132
- if @@version >= "1.2"
133
- def test_filter_collection_with_query
134
- setup_for_distinct
135
- assert_equal [2, 3], @@test.distinct(:a, {:a => {"$gt" => 1}}).sort
136
- end
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
137
548
 
138
- def test_filter_nested_objects
139
- setup_for_distinct
140
- assert_equal ["a", "b"], @@test.distinct("b.c", {"b.c" => {"$ne" => "c"}}).sort
141
- end
142
- end
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
143
553
  end
144
554
 
145
555
  def test_safe_insert
146
- @@test.create_index("hello", :unique => true)
147
- a = {"hello" => "world"}
148
- @@test.insert(a)
149
- @@test.insert(a, :w => 0)
150
- assert(@@db.get_last_error['err'].include?("11000"))
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"))
151
562
 
152
- assert_raise OperationFailure do
153
- @@test.insert(a)
563
+ assert_raise OperationFailure do
564
+ @test.insert(a)
565
+ end
566
+ ensure
567
+ @test.drop_indexes
154
568
  end
155
569
  end
156
570
 
@@ -159,38 +573,41 @@ class TestCollection < Test::Unit::TestCase
159
573
  docs << {:foo => 1}
160
574
  docs << {:foo => 2}
161
575
  docs << {:foo => 3}
162
- response = @@test.insert(docs)
576
+ response = @test.insert(docs)
163
577
  assert_equal 3, response.length
164
578
  assert response.all? {|id| id.is_a?(BSON::ObjectId)}
165
- assert_equal 3, @@test.count
579
+ assert_equal 3, @test.count
166
580
  end
167
581
 
168
582
  def test_bulk_insert_with_continue_on_error
169
- if @@version >= "2.0"
170
- @@test.create_index([["foo", 1]], :unique => true)
171
- docs = []
172
- docs << {:foo => 1}
173
- docs << {:foo => 1}
174
- docs << {:foo => 2}
175
- docs << {:foo => 3}
176
- assert_raise OperationFailure do
177
- @@test.insert(docs)
178
- end
179
- assert_equal 1, @@test.count
180
- @@test.remove
181
-
182
- docs = []
183
- docs << {:foo => 1}
184
- docs << {:foo => 1}
185
- docs << {:foo => 2}
186
- docs << {:foo => 3}
187
- assert_raise OperationFailure do
188
- @@test.insert(docs, :continue_on_error => true)
189
- end
190
- assert_equal 3, @@test.count
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
191
606
 
192
- @@test.remove
193
- @@test.drop_index("foo_1")
607
+ @test.remove
608
+ ensure
609
+ @test.drop_index("foo_1")
610
+ end
194
611
  end
195
612
  end
196
613
 
@@ -198,8 +615,8 @@ class TestCollection < Test::Unit::TestCase
198
615
  docs = []
199
616
  docs << {:foo => 1}
200
617
  docs << {:bar => 1}
201
- doc_ids, error_docs = @@test.insert(docs, :collect_on_error => true)
202
- assert_equal 2, @@test.count
618
+ doc_ids, error_docs = @test.insert(docs, :collect_on_error => true)
619
+ assert_equal 2, @test.count
203
620
  assert_equal 2, doc_ids.count
204
621
  assert_equal error_docs, []
205
622
  end
@@ -213,12 +630,12 @@ class TestCollection < Test::Unit::TestCase
213
630
  invalid_docs << {'invalid.key' => 1}
214
631
  docs += invalid_docs
215
632
  assert_raise BSON::InvalidKeyName do
216
- @@test.insert(docs, :collect_on_error => false)
633
+ @test.insert(docs, :collect_on_error => false)
217
634
  end
218
- assert_equal 0, @@test.count
635
+ assert_equal 2, @test.count
219
636
 
220
- doc_ids, error_docs = @@test.insert(docs, :collect_on_error => true)
221
- assert_equal 2, @@test.count
637
+ doc_ids, error_docs = @test.insert(docs, :collect_on_error => true)
638
+ assert_equal 2, @test.count
222
639
  assert_equal 2, doc_ids.count
223
640
  assert_equal error_docs, invalid_docs
224
641
  end
@@ -234,230 +651,334 @@ class TestCollection < Test::Unit::TestCase
234
651
  docs += invalid_docs
235
652
 
236
653
  assert_raise BSON::InvalidStringEncoding do
237
- @@test.insert(docs, :collect_on_error => false)
654
+ @test.insert(docs, :collect_on_error => false)
238
655
  end
239
- assert_equal 0, @@test.count
656
+ assert_equal 2, @test.count
240
657
 
241
- doc_ids, error_docs = @@test.insert(docs, :collect_on_error => true)
242
- assert_equal 2, @@test.count
658
+ doc_ids, error_docs = @test.insert(docs, :collect_on_error => true)
659
+ assert_equal 2, @test.count
243
660
  assert_equal 2, doc_ids.count
244
661
  assert_equal error_docs, invalid_docs
245
662
  end
246
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
+
247
684
  def limited_collection
248
685
  conn = standard_connection(:connect => false)
686
+ is_master = @ismaster.merge('maxBsonObjectSize' => LIMITED_MAX_BSON_SIZE,
687
+ 'maxMessageSizeBytes' => LIMITED_MAX_BSON_SIZE)
249
688
  admin_db = Object.new
250
- admin_db.expects(:command).returns({
251
- 'ok' => 1,
252
- 'ismaster' => 1,
253
- 'maxBsonObjectSize' => 1024,
254
- 'maxMessageSizeBytes' => 3 * 1024
255
- })
256
- conn.expects(:[]).with('admin').returns(admin_db)
689
+ admin_db.expects(:command).returns(is_master)
690
+ conn.expects(:[]).with(TEST_DB).returns(admin_db)
257
691
  conn.connect
258
- return conn.db(MONGO_TEST_DB)["test"]
692
+ return conn.db(TEST_DB)["test"]
259
693
  end
260
694
 
261
- def test_maximum_insert_size
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
262
702
  docs = []
263
- 3.times do
264
- docs << {'foo' => 'a' * 950}
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)
265
708
  end
266
- assert_equal limited_collection.insert(docs).length, 3
267
709
  end
268
710
 
269
- def test_maximum_document_size
270
- assert_raise InvalidDocument do
271
- limited_collection.insert({'foo' => 'a' * 1024})
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)
272
768
  end
769
+ assert coll.count >= 6, "write commands need headroom for doc wrapping overhead - count:#{coll.count}"
273
770
  end
274
771
 
275
- def test_maximum_message_size
772
+ def test_chunking_batch_insert_without_continue_on_error
276
773
  docs = []
277
774
  4.times do
278
- docs << {'foo' => 'a' * 950}
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}
279
792
  end
793
+ assert_equal limited_collection.insert(docs).length, 3
794
+ end
280
795
 
281
- assert_raise InvalidOperation do
282
- limited_collection.insert(docs)
796
+ def test_maximum_document_size
797
+ assert_raise InvalidDocument do
798
+ limited_collection.insert({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
283
799
  end
284
800
  end
285
801
 
286
802
  def test_maximum_save_size
287
- assert limited_collection.save({'foo' => 'a' * 950})
803
+ assert limited_collection.save({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
288
804
  assert_raise InvalidDocument do
289
- limited_collection.save({'foo' => 'a' * 1024})
805
+ limited_collection.save({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
290
806
  end
291
807
  end
292
808
 
293
809
  def test_maximum_remove_size
294
- assert limited_collection.remove({'foo' => 'a' * 950})
810
+ assert limited_collection.remove({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE})
295
811
  assert_raise InvalidDocument do
296
- limited_collection.remove({'foo' => 'a' * 1024})
812
+ limited_collection.remove({'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM})
297
813
  end
298
814
  end
299
815
 
300
816
  def test_maximum_update_size
301
817
  assert_raise InvalidDocument do
302
818
  limited_collection.update(
303
- {'foo' => 'a' * 1024},
304
- {'foo' => 'a' * 950}
819
+ {'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
820
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}
305
821
  )
306
822
  end
307
823
 
308
824
  assert_raise InvalidDocument do
309
825
  limited_collection.update(
310
- {'foo' => 'a' * 950},
311
- {'foo' => 'a' * 1024}
826
+ {'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
827
+ {'foo' => 'a' * LIMITED_MAX_BSON_SIZE}
312
828
  )
313
829
  end
314
830
 
315
831
  assert_raise InvalidDocument do
316
832
  limited_collection.update(
317
- {'foo' => 'a' * 1024},
318
- {'foo' => 'a' * 1024}
833
+ {'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM},
834
+ {'foo' => 'a' * LIMITED_BSON_SIZE_WITH_HEADROOM}
319
835
  )
320
836
  end
321
837
 
322
838
  assert limited_collection.update(
323
- {'foo' => 'a' * 950},
324
- {'foo' => 'a' * 950}
325
- )
839
+ {'foo' => 'a' * (LIMITED_VALID_VALUE_SIZE/2)},
840
+ {'foo' => 'a' * (LIMITED_VALID_VALUE_SIZE/2)}
841
+ )
326
842
  end
327
843
 
328
844
  def test_maximum_query_size
329
- assert limited_collection.find({'foo' => 'a' * 950}).to_a
845
+ assert limited_collection.find({'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}).to_a
330
846
  assert limited_collection.find(
331
- {'foo' => 'a' * 950},
332
- {:fields => {'foo' => 'a' * 950}}
333
- ).to_a
847
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
848
+ {:fields => {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE}}
849
+ ).to_a
334
850
 
335
851
  assert_raise InvalidDocument do
336
- limited_collection.find({'foo' => 'a' * 1024}).to_a
852
+ limited_collection.find({'foo' => 'a' * LIMITED_INVALID_VALUE_SIZE}).to_a
337
853
  end
338
854
 
339
855
  assert_raise InvalidDocument do
340
856
  limited_collection.find(
341
- {'foo' => 'a' * 950},
342
- {:fields => {'foo' => 'a' * 1024}}
857
+ {'foo' => 'a' * LIMITED_VALID_VALUE_SIZE},
858
+ {:fields => {'foo' => 'a' * LIMITED_MAX_BSON_SIZE}}
343
859
  ).to_a
344
860
  end
345
861
  end
346
862
 
347
- #if @@version >= "1.5.1"
863
+ #if @version >= "1.5.1"
348
864
  # def test_safe_mode_with_advanced_safe_with_invalid_options
349
865
  # assert_raise_error ArgumentError, "Unknown key(s): wtime" do
350
- # @@test.insert({:foo => 1}, :w => 2, :wtime => 1, :fsync => true)
866
+ # @test.insert({:foo => 1}, :w => 2, :wtime => 1, :fsync => true)
351
867
  # end
352
868
  # assert_raise_error ArgumentError, "Unknown key(s): wtime" do
353
- # @@test.update({:foo => 1}, {:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
869
+ # @test.update({:foo => 1}, {:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
354
870
  # end
355
871
  #
356
872
  # assert_raise_error ArgumentError, "Unknown key(s): wtime" do
357
- # @@test.remove({:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
873
+ # @test.remove({:foo => 2}, :w => 2, :wtime => 1, :fsync => true)
358
874
  # end
359
875
  # end
360
876
  #end
361
877
 
362
- if @@version >= "2.0.0"
363
- def test_safe_mode_with_journal_commit_option
364
- @@test.insert({:foo => 1}, :j => true)
365
- @@test.update({:foo => 1}, {:foo => 2}, :j => true)
366
- @@test.remove({:foo => 2}, :j => true)
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")
367
894
  end
368
895
  end
369
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
+
370
907
  def test_update
371
- id1 = @@test.save("x" => 5)
372
- @@test.update({}, {"$inc" => {"x" => 1}})
373
- assert_equal 1, @@test.count()
374
- assert_equal 6, @@test.find_one(:_id => id1)["x"]
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"]
375
912
 
376
- id2 = @@test.save("x" => 1)
377
- @@test.update({"x" => 6}, {"$inc" => {"x" => 1}})
378
- assert_equal 7, @@test.find_one(:_id => id1)["x"]
379
- assert_equal 1, @@test.find_one(:_id => id2)["x"]
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"]
380
917
  end
381
918
 
382
919
  def test_update_check_keys
383
- @@test.save("x" => 1)
384
- @@test.update({"x" => 1}, {"$set" => {"a.b" => 2}})
385
- assert_equal 2, @@test.find_one("x" => 1)["a"]["b"]
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"]
386
924
 
387
925
  assert_raise_error BSON::InvalidKeyName do
388
- @@test.update({"x" => 1}, {"a.b" => 3})
926
+ @test.update({"x" => 1}, {"a.b" => 3})
389
927
  end
390
928
  end
391
929
 
392
- if @@version >= "1.1.3"
393
- def test_multi_update
394
- @@test.save("num" => 10)
395
- @@test.save("num" => 10)
396
- @@test.save("num" => 10)
397
- assert_equal 3, @@test.count
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
398
936
 
399
- @@test.update({"num" => 10}, {"$set" => {"num" => 100}}, :multi => true)
400
- @@test.find.each do |doc|
401
- assert_equal 100, doc["num"]
402
- end
937
+ @test.update({"num" => 10}, {"$set" => {"num" => 100}}, :multi => true)
938
+ @test.find.each do |doc|
939
+ assert_equal 100, doc["num"]
403
940
  end
404
941
  end
405
942
 
406
943
  def test_upsert
407
- @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
408
- @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
944
+ @test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
945
+ @test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
409
946
 
410
- assert_equal 1, @@test.count()
411
- assert_equal 2, @@test.find_one()["count"]
947
+ assert_equal 1, @test.count()
948
+ assert_equal 2, @test.find_one()["count"]
412
949
  end
413
950
 
414
- if @@version < "1.1.3"
415
- def test_safe_update
416
- @@test.create_index("x")
417
- @@test.insert("x" => 5)
418
-
419
- @@test.update({}, {"$inc" => {"x" => 1}})
420
- assert @@db.error?
421
-
422
- # Can't change an index.
423
- assert_raise OperationFailure do
424
- @@test.update({}, {"$inc" => {"x" => 1}})
425
- end
426
- @@test.drop
427
- end
428
- else
429
- def test_safe_update
430
- @@test.create_index("x", :unique => true)
431
- @@test.insert("x" => 5)
432
- @@test.insert("x" => 10)
951
+ def test_safe_update
952
+ @test.create_index("x", :unique => true)
953
+ @test.insert("x" => 5)
954
+ @test.insert("x" => 10)
433
955
 
434
- # Can update an indexed collection.
435
- @@test.update({}, {"$inc" => {"x" => 1}})
436
- assert !@@db.error?
956
+ # Can update an indexed collection.
957
+ @test.update({}, {"$inc" => {"x" => 1}})
958
+ assert !@db.error?
437
959
 
438
- # Can't duplicate an index.
439
- assert_raise OperationFailure do
440
- @@test.update({}, {"x" => 10})
441
- end
442
- @@test.drop
960
+ # Can't duplicate an index.
961
+ assert_raise OperationFailure do
962
+ @test.update({}, {"x" => 10})
443
963
  end
964
+ @test.drop
444
965
  end
445
966
 
446
967
  def test_safe_save
447
- @@test.create_index("hello", :unique => true)
968
+ @test.create_index("hello", :unique => true)
448
969
 
449
- @@test.save("hello" => "world")
450
- @@test.save({"hello" => "world"}, :w => 0)
970
+ @test.save("hello" => "world")
971
+ @test.save({"hello" => "world"}, :w => 0)
451
972
 
452
973
  assert_raise OperationFailure do
453
- @@test.save({"hello" => "world"})
974
+ @test.save({"hello" => "world"})
454
975
  end
455
- @@test.drop
976
+ @test.drop
456
977
  end
457
978
 
458
979
  def test_mocked_safe_remove
459
980
  @client = standard_connection
460
- @db = @client[MONGO_TEST_DB]
981
+ @db = @client[TEST_DB]
461
982
  @test = @db['test-safe-remove']
462
983
  @test.save({:a => 20})
463
984
  @client.stubs(:receive).returns([[{'ok' => 0, 'err' => 'failed'}], 1, 0])
@@ -470,7 +991,7 @@ class TestCollection < Test::Unit::TestCase
470
991
 
471
992
  def test_safe_remove
472
993
  @client = standard_connection
473
- @db = @client[MONGO_TEST_DB]
994
+ @db = @client[TEST_DB]
474
995
  @test = @db['test-safe-remove']
475
996
  @test.remove
476
997
  @test.save({:a => 50})
@@ -479,115 +1000,216 @@ class TestCollection < Test::Unit::TestCase
479
1000
  end
480
1001
 
481
1002
  def test_remove_return_value
482
- assert_equal true, @@test.remove({}, :w => 0)
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
483
1012
  end
484
1013
 
485
1014
  def test_count
486
- @@test.drop
1015
+ @test.drop
487
1016
 
488
- assert_equal 0, @@test.count
489
- @@test.save(:x => 1)
490
- @@test.save(:x => 2)
491
- assert_equal 2, @@test.count
1017
+ assert_equal 0, @test.count
1018
+ @test.save(:x => 1)
1019
+ @test.save(:x => 2)
1020
+ assert_equal 2, @test.count
492
1021
 
493
- assert_equal 1, @@test.count(:query => {:x => 1})
494
- assert_equal 1, @@test.count(:limit => 1)
495
- assert_equal 0, @@test.count(:skip => 2)
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')
496
1080
  end
497
1081
 
498
1082
  # Note: #size is just an alias for #count.
499
1083
  def test_size
500
- @@test.drop
1084
+ @test.drop
501
1085
 
502
- assert_equal 0, @@test.count
503
- assert_equal @@test.size, @@test.count
504
- @@test.save("x" => 1)
505
- @@test.save("x" => 2)
506
- assert_equal @@test.size, @@test.count
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
507
1091
  end
508
1092
 
509
1093
  def test_no_timeout_option
510
- @@test.drop
1094
+ @test.drop
511
1095
 
512
1096
  assert_raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block." do
513
- @@test.find({}, :timeout => false)
1097
+ @test.find({}, :timeout => false)
514
1098
  end
515
1099
 
516
- @@test.find({}, :timeout => false) do |cursor|
1100
+ @test.find({}, :timeout => false) do |cursor|
517
1101
  assert_equal 0, cursor.count
518
1102
  end
519
1103
 
520
- @@test.save("x" => 1)
521
- @@test.save("x" => 2)
522
- @@test.find({}, :timeout => false) do |cursor|
1104
+ @test.save("x" => 1)
1105
+ @test.save("x" => 2)
1106
+ @test.find({}, :timeout => false) do |cursor|
523
1107
  assert_equal 2, cursor.count
524
1108
  end
525
1109
  end
526
1110
 
527
- def test_defualt_timeout
528
- cursor = @@test.find
1111
+ def test_default_timeout
1112
+ cursor = @test.find
529
1113
  assert_equal true, cursor.timeout
530
1114
  end
531
1115
 
532
1116
  def test_fields_as_hash
533
- @@test.save(:a => 1, :b => 1, :c => 1)
1117
+ @test.save(:a => 1, :b => 1, :c => 1)
534
1118
 
535
- doc = @@test.find_one({:a => 1}, :fields => {:b => 0})
1119
+ doc = @test.find_one({:a => 1}, :fields => {:b => 0})
536
1120
  assert_nil doc['b']
537
1121
  assert doc['a']
538
1122
  assert doc['c']
539
1123
 
540
- doc = @@test.find_one({:a => 1}, :fields => {:a => 1, :b => 1})
1124
+ doc = @test.find_one({:a => 1}, :fields => {:a => 1, :b => 1})
541
1125
  assert_nil doc['c']
542
1126
  assert doc['a']
543
1127
  assert doc['b']
544
1128
 
545
1129
 
546
1130
  assert_raise Mongo::OperationFailure do
547
- @@test.find_one({:a => 1}, :fields => {:a => 1, :b => 0})
1131
+ @test.find_one({:a => 1}, :fields => {:a => 1, :b => 0})
548
1132
  end
549
1133
  end
550
1134
 
551
- if @@version >= "1.5.1"
552
- def test_fields_with_slice
553
- @@test.save({:foo => [1, 2, 3, 4, 5, 6], :test => 'slice'})
554
1135
 
555
- doc = @@test.find_one({:test => 'slice'}, :fields => {'foo' => {'$slice' => [0, 3]}})
556
- assert_equal [1, 2, 3], doc['foo']
557
- @@test.remove
558
- end
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
559
1165
  end
560
1166
 
561
1167
  def test_find_one
562
- id = @@test.save("hello" => "world", "foo" => "bar")
1168
+ id = @test.save("hello" => "world", "foo" => "bar")
563
1169
 
564
- assert_equal "world", @@test.find_one()["hello"]
565
- assert_equal @@test.find_one(id), @@test.find_one()
566
- assert_equal @@test.find_one(nil), @@test.find_one()
567
- assert_equal @@test.find_one({}), @@test.find_one()
568
- assert_equal @@test.find_one("hello" => "world"), @@test.find_one()
569
- assert_equal @@test.find_one(BSON::OrderedHash["hello", "world"]), @@test.find_one()
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()
570
1176
 
571
- assert @@test.find_one(nil, :fields => ["hello"]).include?("hello")
572
- assert !@@test.find_one(nil, :fields => ["foo"]).include?("hello")
573
- assert_equal ["_id"], @@test.find_one(nil, :fields => []).keys()
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()
574
1180
 
575
- assert_equal nil, @@test.find_one("hello" => "foo")
576
- assert_equal nil, @@test.find_one(BSON::OrderedHash["hello", "foo"])
577
- assert_equal nil, @@test.find_one(ObjectId.new)
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)
578
1184
 
579
1185
  assert_raise TypeError do
580
- @@test.find_one(6)
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
581
1195
  end
582
1196
  end
583
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
+
584
1206
  def test_insert_adds_id
585
1207
  doc = {"hello" => "world"}
586
- @@test.insert(doc)
1208
+ @test.insert(doc)
587
1209
  assert(doc.include?(:_id))
588
1210
 
589
1211
  docs = [{"hello" => "world"}, {"hello" => "world"}]
590
- @@test.insert(docs)
1212
+ @test.insert(docs)
591
1213
  docs.each do |d|
592
1214
  assert(d.include?(:_id))
593
1215
  end
@@ -595,23 +1217,23 @@ class TestCollection < Test::Unit::TestCase
595
1217
 
596
1218
  def test_save_adds_id
597
1219
  doc = {"hello" => "world"}
598
- @@test.save(doc)
1220
+ @test.save(doc)
599
1221
  assert(doc.include?(:_id))
600
1222
  end
601
1223
 
602
1224
  def test_optional_find_block
603
1225
  10.times do |i|
604
- @@test.save("i" => i)
1226
+ @test.save("i" => i)
605
1227
  end
606
1228
 
607
1229
  x = nil
608
- @@test.find("i" => 2) { |cursor|
1230
+ @test.find("i" => 2) { |cursor|
609
1231
  x = cursor.count()
610
1232
  }
611
1233
  assert_equal 1, x
612
1234
 
613
1235
  i = 0
614
- @@test.find({}, :skip => 5) do |cursor|
1236
+ @test.find({}, :skip => 5) do |cursor|
615
1237
  cursor.each do |doc|
616
1238
  i = i + 1
617
1239
  end
@@ -619,7 +1241,7 @@ class TestCollection < Test::Unit::TestCase
619
1241
  assert_equal 5, i
620
1242
 
621
1243
  c = nil
622
- @@test.find() do |cursor|
1244
+ @test.find() do |cursor|
623
1245
  c = cursor
624
1246
  end
625
1247
  assert c.closed?
@@ -627,290 +1249,414 @@ class TestCollection < Test::Unit::TestCase
627
1249
 
628
1250
  def setup_aggregate_data
629
1251
  # save some data
630
- @@test.save( {
631
- "_id" => 1,
632
- "title" => "this is my title",
633
- "author" => "bob",
634
- "posted" => Time.utc(2000),
635
- "pageViews" => 5 ,
636
- "tags" => [ "fun" , "good" , "fun" ],
637
- "comments" => [
638
- { "author" => "joe", "text" => "this is cool" },
639
- { "author" => "sam", "text" => "this is bad" }
640
- ],
641
- "other" => { "foo" => 5 }
642
- } )
643
-
644
- @@test.save( {
645
- "_id" => 2,
646
- "title" => "this is your title",
647
- "author" => "dave",
648
- "posted" => Time.utc(2001),
649
- "pageViews" => 7,
650
- "tags" => [ "fun" , "nasty" ],
651
- "comments" => [
652
- { "author" => "barbara" , "text" => "this is interesting" },
653
- { "author" => "jenny", "text" => "i like to play pinball", "votes" => 10 }
654
- ],
655
- "other" => { "bar" => 14 }
656
- })
657
-
658
- @@test.save( {
659
- "_id" => 3,
660
- "title" => "this is some other title",
661
- "author" => "jane",
662
- "posted" => Time.utc(2002),
663
- "pageViews" => 6 ,
664
- "tags" => [ "nasty", "filthy" ],
665
- "comments" => [
666
- { "author" => "will" , "text" => "i don't like the color" } ,
667
- { "author" => "jenny" , "text" => "can i get that in green?" }
668
- ],
669
- "other" => { "bar" => 14 }
670
- })
671
-
672
- end
673
-
674
- if @@version > '2.1.1'
675
- def test_reponds_to_aggregate
676
- assert_respond_to @@test, :aggregate
677
- end
678
-
679
- def test_aggregate_requires_arguments
680
- assert_raise MongoArgumentError do
681
- @@test.aggregate()
682
- end
683
- end
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)
684
1517
 
685
- def test_aggregate_requires_valid_arguments
686
- assert_raise MongoArgumentError do
687
- @@test.aggregate({})
688
- end
689
- end
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}
690
1522
 
691
- def test_aggregate_pipeline_operator_format
692
- assert_raise Mongo::OperationFailure do
693
- @@test.aggregate([{"$project" => "_id"}])
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
694
1577
  end
695
1578
  end
1579
+ threads.each(&:join)
1580
+ assert_equal 8000, doc_ids.count
1581
+ end
696
1582
 
697
- def test_aggregate_pipeline_operators_using_strings
698
- setup_aggregate_data
699
- desired_results = [ {"_id"=>1, "pageViews"=>5, "tags"=>["fun", "good", "fun"]},
700
- {"_id"=>2, "pageViews"=>7, "tags"=>["fun", "nasty"]},
701
- {"_id"=>3, "pageViews"=>6, "tags"=>["nasty", "filthy"]} ]
702
- results = @@test.aggregate([{"$project" => {"tags" => 1, "pageViews" => 1}}])
703
- assert_equal desired_results, results
704
- end
705
-
706
- def test_aggregate_pipeline_operators_using_symbols
707
- setup_aggregate_data
708
- desired_results = [ {"_id"=>1, "pageViews"=>5, "tags"=>["fun", "good", "fun"]},
709
- {"_id"=>2, "pageViews"=>7, "tags"=>["fun", "nasty"]},
710
- {"_id"=>3, "pageViews"=>6, "tags"=>["nasty", "filthy"]} ]
711
- results = @@test.aggregate([{"$project" => {:tags => 1, :pageViews => 1}}])
712
- assert_equal desired_results, results
713
- end
714
-
715
- def test_aggregate_pipeline_multiple_operators
716
- setup_aggregate_data
717
- results = @@test.aggregate([{"$project" => {"tags" => 1, "pageViews" => 1}}, {"$match" => {"pageViews" => 7}}])
718
- assert_equal 1, results.length
719
- end
720
-
721
- def test_aggregate_pipeline_unwind
722
- setup_aggregate_data
723
- desired_results = [ {"_id"=>1, "title"=>"this is my title", "author"=>"bob", "posted"=>Time.utc(2000),
724
- "pageViews"=>5, "tags"=>"fun", "comments"=>[{"author"=>"joe", "text"=>"this is cool"},
725
- {"author"=>"sam", "text"=>"this is bad"}], "other"=>{"foo"=>5 } },
726
- {"_id"=>1, "title"=>"this is my title", "author"=>"bob", "posted"=>Time.utc(2000),
727
- "pageViews"=>5, "tags"=>"good", "comments"=>[{"author"=>"joe", "text"=>"this is cool"},
728
- {"author"=>"sam", "text"=>"this is bad"}], "other"=>{"foo"=>5 } },
729
- {"_id"=>1, "title"=>"this is my title", "author"=>"bob", "posted"=>Time.utc(2000),
730
- "pageViews"=>5, "tags"=>"fun", "comments"=>[{"author"=>"joe", "text"=>"this is cool"},
731
- {"author"=>"sam", "text"=>"this is bad"}], "other"=>{"foo"=>5 } },
732
- {"_id"=>2, "title"=>"this is your title", "author"=>"dave", "posted"=>Time.utc(2001),
733
- "pageViews"=>7, "tags"=>"fun", "comments"=>[{"author"=>"barbara", "text"=>"this is interesting"},
734
- {"author"=>"jenny", "text"=>"i like to play pinball", "votes"=>10 }], "other"=>{"bar"=>14 } },
735
- {"_id"=>2, "title"=>"this is your title", "author"=>"dave", "posted"=>Time.utc(2001),
736
- "pageViews"=>7, "tags"=>"nasty", "comments"=>[{"author"=>"barbara", "text"=>"this is interesting"},
737
- {"author"=>"jenny", "text"=>"i like to play pinball", "votes"=>10 }], "other"=>{"bar"=>14 } },
738
- {"_id"=>3, "title"=>"this is some other title", "author"=>"jane", "posted"=>Time.utc(2002),
739
- "pageViews"=>6, "tags"=>"nasty", "comments"=>[{"author"=>"will", "text"=>"i don't like the color"},
740
- {"author"=>"jenny", "text"=>"can i get that in green?"}], "other"=>{"bar"=>14 } },
741
- {"_id"=>3, "title"=>"this is some other title", "author"=>"jane", "posted"=>Time.utc(2002),
742
- "pageViews"=>6, "tags"=>"filthy", "comments"=>[{"author"=>"will", "text"=>"i don't like the color"},
743
- {"author"=>"jenny", "text"=>"can i get that in green?"}], "other"=>{"bar"=>14 } }
744
- ]
745
- results = @@test.aggregate([{"$unwind"=> "$tags"}])
746
- assert_equal desired_results, results
747
- end
748
- end
749
-
750
- if @@version > "1.1.1"
751
- def test_map_reduce
752
- @@test << { "user_id" => 1 }
753
- @@test << { "user_id" => 2 }
754
-
755
- m = "function() { emit(this.user_id, 1); }"
756
- r = "function(k,vals) { return 1; }"
757
- res = @@test.map_reduce(m, r, :out => 'foo');
758
- assert res.find_one({"_id" => 1})
759
- assert res.find_one({"_id" => 2})
760
- end
761
-
762
- def test_map_reduce_with_code_objects
763
- @@test << { "user_id" => 1 }
764
- @@test << { "user_id" => 2 }
765
-
766
- m = Code.new("function() { emit(this.user_id, 1); }")
767
- r = Code.new("function(k,vals) { return 1; }")
768
- res = @@test.map_reduce(m, r, :out => 'foo');
769
- assert res.find_one({"_id" => 1})
770
- assert res.find_one({"_id" => 2})
771
- end
772
-
773
- def test_map_reduce_with_options
774
- @@test.remove
775
- @@test << { "user_id" => 1 }
776
- @@test << { "user_id" => 2 }
777
- @@test << { "user_id" => 3 }
778
-
779
- m = Code.new("function() { emit(this.user_id, 1); }")
780
- r = Code.new("function(k,vals) { return 1; }")
781
- res = @@test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo');
782
- assert_equal 2, res.count
783
- assert res.find_one({"_id" => 2})
784
- assert res.find_one({"_id" => 3})
785
- end
786
-
787
- def test_map_reduce_with_raw_response
788
- m = Code.new("function() { emit(this.user_id, 1); }")
789
- r = Code.new("function(k,vals) { return 1; }")
790
- res = @@test.map_reduce(m, r, :raw => true, :out => 'foo')
791
- assert res["result"]
792
- assert res["counts"]
793
- assert res["timeMillis"]
794
- end
795
-
796
- def test_map_reduce_with_output_collection
797
- output_collection = "test-map-coll"
798
- m = Code.new("function() { emit(this.user_id, 1); }")
799
- r = Code.new("function(k,vals) { return 1; }")
800
- res = @@test.map_reduce(m, r, :raw => true, :out => output_collection)
801
- assert_equal output_collection, res["result"]
802
- assert res["counts"]
803
- assert res["timeMillis"]
804
- end
805
-
806
-
807
- if @@version >= "1.8.0"
808
- def test_map_reduce_with_collection_merge
809
- @@test << {:user_id => 1}
810
- @@test << {:user_id => 2}
811
- output_collection = "test-map-coll"
812
- m = Code.new("function() { emit(this.user_id, {count: 1}); }")
813
- r = Code.new("function(k,vals) { var sum = 0;" +
814
- " vals.forEach(function(v) { sum += v.count;} ); return {count: sum}; }")
815
- res = @@test.map_reduce(m, r, :out => output_collection)
816
-
817
- @@test.remove
818
- @@test << {:user_id => 3}
819
- res = @@test.map_reduce(m, r, :out => {:merge => output_collection})
820
- assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 1}
821
-
822
- @@test.remove
823
- @@test << {:user_id => 3}
824
- res = @@test.map_reduce(m, r, :out => {:reduce => output_collection})
825
- assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 2}
826
-
827
- assert_raise ArgumentError do
828
- @@test.map_reduce(m, r, :out => {:inline => 1})
829
- end
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 }
830
1588
 
831
- @@test.map_reduce(m, r, :raw => true, :out => {:inline => 1})
832
- assert res["results"]
833
- end
1589
+ @test.find_and_modify(:query => {},
1590
+ :sort => [['a', -1]],
1591
+ :update => {"$set" => {:processed => true}})
834
1592
 
835
- def test_map_reduce_with_collection_output_to_other_db
836
- @@test << {:user_id => 1}
837
- @@test << {:user_id => 2}
838
-
839
- m = Code.new("function() { emit(this.user_id, 1); }")
840
- r = Code.new("function(k,vals) { return 1; }")
841
- oh = BSON::OrderedHash.new
842
- oh[:replace] = 'foo'
843
- oh[:db] = MONGO_TEST_DB
844
- res = @@test.map_reduce(m, r, :out => (oh))
845
- assert res["result"]
846
- assert res["counts"]
847
- assert res["timeMillis"]
848
- assert res.find.to_a.any? {|doc| doc["_id"] == 2 && doc["value"] == 1}
849
- end
850
- end
1593
+ assert @test.find_one({:a => 3})['processed']
851
1594
  end
852
1595
 
853
- if @@version > "1.3.0"
854
- def test_find_and_modify
855
- @@test << { :a => 1, :processed => false }
856
- @@test << { :a => 2, :processed => false }
857
- @@test << { :a => 3, :processed => false }
858
-
859
- @@test.find_and_modify(:query => {}, :sort => [['a', -1]], :update => {"$set" => {:processed => true}})
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 }
860
1600
 
861
- assert @@test.find_one({:a => 3})['processed']
1601
+ assert_raise Mongo::OperationFailure do
1602
+ @test.find_and_modify(:blimey => {})
862
1603
  end
1604
+ end
863
1605
 
864
- def test_find_and_modify_with_invalid_options
865
- @@test << { :a => 1, :processed => false }
866
- @@test << { :a => 2, :processed => false }
867
- @@test << { :a => 3, :processed => false }
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 }
868
1610
 
869
- assert_raise Mongo::OperationFailure do
870
- @@test.find_and_modify(:blimey => {})
871
- end
872
- end
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) }
873
1619
  end
874
1620
 
875
- if @@version >= "1.3.5"
876
- def test_coll_stats
877
- @@test << {:n => 1}
878
- @@test.create_index("n")
1621
+ def test_coll_stats
1622
+ return unless @version >= "1.3.5"
1623
+ @test << {:n => 1}
1624
+ @test.create_index("n")
879
1625
 
880
- assert_equal "#{MONGO_TEST_DB}.test", @@test.stats['ns']
881
- end
1626
+ assert_equal "#{TEST_DB}.test", @test.stats['ns']
1627
+ @test.drop
882
1628
  end
883
1629
 
884
1630
  def test_saving_dates_pre_epoch
885
1631
  if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/ then return true end
886
1632
  begin
887
- @@test.save({'date' => Time.utc(1600)})
888
- assert_in_delta Time.utc(1600), @@test.find_one()["date"], 2
1633
+ @test.save({'date' => Time.utc(1600)})
1634
+ assert_in_delta Time.utc(1600), @test.find_one()["date"], 2
889
1635
  rescue ArgumentError
890
1636
  # See note in test_date_before_epoch (BSONTest)
891
1637
  end
892
1638
  end
893
1639
 
894
1640
  def test_save_symbol_find_string
895
- @@test.save(:foo => :mike)
1641
+ @test.save(:foo => :mike)
896
1642
 
897
- assert_equal :mike, @@test.find_one(:foo => :mike)["foo"]
898
- assert_equal :mike, @@test.find_one("foo" => :mike)["foo"]
1643
+ assert_equal :mike, @test.find_one(:foo => :mike)["foo"]
1644
+ assert_equal :mike, @test.find_one("foo" => :mike)["foo"]
899
1645
 
900
1646
  # TODO enable these tests conditionally based on server version (if >1.0)
901
- # assert_equal :mike, @@test.find_one(:foo => "mike")["foo"]
902
- # assert_equal :mike, @@test.find_one("foo" => "mike")["foo"]
1647
+ # assert_equal :mike, @test.find_one(:foo => "mike")["foo"]
1648
+ # assert_equal :mike, @test.find_one("foo" => "mike")["foo"]
903
1649
  end
904
1650
 
905
1651
  def test_batch_size
906
1652
  n_docs = 6
907
1653
  batch_size = n_docs/2
908
1654
  n_docs.times do |i|
909
- @@test.save(:foo => i)
1655
+ @test.save(:foo => i)
910
1656
  end
911
1657
 
912
1658
  doc_count = 0
913
- cursor = @@test.find({}, :batch_size => batch_size)
1659
+ cursor = @test.find({}, :batch_size => batch_size)
914
1660
  cursor.next
915
1661
  assert_equal batch_size, cursor.instance_variable_get(:@returned)
916
1662
  doc_count += batch_size
@@ -924,10 +1670,10 @@ class TestCollection < Test::Unit::TestCase
924
1670
  n_docs = 6
925
1671
  batch_size = n_docs/2
926
1672
  n_docs.times do |i|
927
- @@test.insert(:foo => i)
1673
+ @test.insert(:foo => i)
928
1674
  end
929
1675
 
930
- cursor = @@test.find({}, :batch_size => batch_size, :limit => 2)
1676
+ cursor = @test.find({}, :batch_size => batch_size, :limit => 2)
931
1677
  cursor.next
932
1678
  assert_equal 2, cursor.instance_variable_get(:@returned)
933
1679
  end
@@ -936,11 +1682,11 @@ class TestCollection < Test::Unit::TestCase
936
1682
  n_docs = 6
937
1683
  batch_size = n_docs/2
938
1684
  n_docs.times do |i|
939
- @@test.insert(:foo => i)
1685
+ @test.insert(:foo => i)
940
1686
  end
941
1687
 
942
1688
  doc_count = 0
943
- cursor = @@test.find({}, :batch_size => batch_size, :limit => n_docs + 5)
1689
+ cursor = @test.find({}, :batch_size => batch_size, :limit => n_docs + 5)
944
1690
  cursor.next
945
1691
  assert_equal batch_size, cursor.instance_variable_get(:@returned)
946
1692
  doc_count += batch_size
@@ -948,44 +1694,44 @@ class TestCollection < Test::Unit::TestCase
948
1694
  assert_equal doc_count + batch_size, cursor.instance_variable_get(:@returned)
949
1695
  doc_count += batch_size
950
1696
  assert_equal n_docs, doc_count
951
- end
1697
+ end
952
1698
 
953
1699
  def test_batch_size_with_negative_limit
954
1700
  n_docs = 6
955
1701
  batch_size = n_docs/2
956
1702
  n_docs.times do |i|
957
- @@test.insert(:foo => i)
1703
+ @test.insert(:foo => i)
958
1704
  end
959
1705
 
960
- cursor = @@test.find({}, :batch_size => batch_size, :limit => -7)
1706
+ cursor = @test.find({}, :batch_size => batch_size, :limit => -7)
961
1707
  cursor.next
962
1708
  assert_equal n_docs, cursor.instance_variable_get(:@returned)
963
1709
  end
964
1710
 
965
1711
  def test_limit_and_skip
966
1712
  10.times do |i|
967
- @@test.save(:foo => i)
1713
+ @test.save(:foo => i)
968
1714
  end
969
1715
 
970
- assert_equal 5, @@test.find({}, :skip => 5).next_document()["foo"]
971
- assert_equal nil, @@test.find({}, :skip => 10).next_document()
1716
+ assert_equal 5, @test.find({}, :skip => 5).next_document()["foo"]
1717
+ assert_equal nil, @test.find({}, :skip => 10).next_document()
972
1718
 
973
- assert_equal 5, @@test.find({}, :limit => 5).to_a.length
1719
+ assert_equal 5, @test.find({}, :limit => 5).to_a.length
974
1720
 
975
- assert_equal 3, @@test.find({}, :skip => 3, :limit => 5).next_document()["foo"]
976
- assert_equal 5, @@test.find({}, :skip => 3, :limit => 5).to_a.length
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
977
1723
  end
978
1724
 
979
1725
  def test_large_limit
980
1726
  2000.times do |i|
981
- @@test.insert("x" => i, "y" => "mongomongo" * 1000)
1727
+ @test.insert("x" => i, "y" => "mongomongo" * 1000)
982
1728
  end
983
1729
 
984
- assert_equal 2000, @@test.count
1730
+ assert_equal 2000, @test.count
985
1731
 
986
1732
  i = 0
987
1733
  y = 0
988
- @@test.find({}, :limit => 1900).each do |doc|
1734
+ @test.find({}, :limit => 1900).each do |doc|
989
1735
  i += 1
990
1736
  y += doc["x"]
991
1737
  end
@@ -995,13 +1741,13 @@ end
995
1741
  end
996
1742
 
997
1743
  def test_small_limit
998
- @@test.insert("x" => "hello world")
999
- @@test.insert("x" => "goodbye world")
1744
+ @test.insert("x" => "hello world")
1745
+ @test.insert("x" => "goodbye world")
1000
1746
 
1001
- assert_equal 2, @@test.count
1747
+ assert_equal 2, @test.count
1002
1748
 
1003
1749
  x = 0
1004
- @@test.find({}, :limit => 1).each do |doc|
1750
+ @test.find({}, :limit => 1).each do |doc|
1005
1751
  x += 1
1006
1752
  assert_equal "hello world", doc["x"]
1007
1753
  end
@@ -1012,55 +1758,56 @@ end
1012
1758
  def test_find_with_transformer
1013
1759
  klass = Struct.new(:id, :a)
1014
1760
  transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
1015
- cursor = @@test.find({}, :transformer => transformer)
1761
+ cursor = @test.find({}, :transformer => transformer)
1016
1762
  assert_equal(transformer, cursor.transformer)
1017
1763
  end
1018
1764
 
1019
1765
  def test_find_one_with_transformer
1020
1766
  klass = Struct.new(:id, :a)
1021
1767
  transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
1022
- id = @@test.insert('a' => 1)
1023
- doc = @@test.find_one(id, :transformer => transformer)
1768
+ id = @test.insert('a' => 1)
1769
+ doc = @test.find_one(id, :transformer => transformer)
1024
1770
  assert_instance_of(klass, doc)
1025
1771
  end
1026
1772
 
1027
1773
  def test_ensure_index
1028
- @@test.drop_indexes
1029
- @@test.insert("x" => "hello world")
1030
- assert_equal 1, @@test.index_information.keys.count #default index
1774
+ @test.drop_indexes
1775
+ @test.insert("x" => "hello world")
1776
+ assert_equal 1, @test.index_information.keys.count #default index
1031
1777
 
1032
- @@test.ensure_index([["x", Mongo::DESCENDING]], {})
1033
- assert_equal 2, @@test.index_information.keys.count
1034
- assert @@test.index_information.keys.include?("x_-1")
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")
1035
1781
 
1036
- @@test.ensure_index([["x", Mongo::ASCENDING]])
1037
- assert @@test.index_information.keys.include?("x_1")
1782
+ @test.ensure_index([["x", Mongo::ASCENDING]])
1783
+ assert @test.index_information.keys.include?("x_1")
1038
1784
 
1039
- @@test.ensure_index([["type", 1], ["date", -1]])
1040
- assert @@test.index_information.keys.include?("type_1_date_-1")
1785
+ @test.ensure_index([["type", 1], ["date", -1]])
1786
+ assert @test.index_information.keys.include?("type_1_date_-1")
1041
1787
 
1042
- @@test.drop_index("x_1")
1043
- assert_equal 3, @@test.index_information.keys.count
1044
- @@test.drop_index("x_-1")
1045
- assert_equal 2, @@test.index_information.keys.count
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
1046
1792
 
1047
- @@test.ensure_index([["x", Mongo::DESCENDING]], {})
1048
- assert_equal 3, @@test.index_information.keys.count
1049
- assert @@test.index_information.keys.include?("x_-1")
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")
1050
1796
 
1051
1797
  # Make sure that drop_index expires cache properly
1052
- @@test.ensure_index([['a', 1]])
1053
- assert @@test.index_information.keys.include?("a_1")
1054
- @@test.drop_index("a_1")
1055
- assert !@@test.index_information.keys.include?("a_1")
1056
- @@test.ensure_index([['a', 1]])
1057
- assert @@test.index_information.keys.include?("a_1")
1058
- @@test.drop_index("a_1")
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
1059
1806
  end
1060
1807
 
1061
1808
  def test_ensure_index_timeout
1062
- @@db.cache_time = 2
1063
- coll = @@db['ensure_test']
1809
+ @db.cache_time = 1
1810
+ coll = @db['ensure_test']
1064
1811
  coll.expects(:generate_indexes).twice
1065
1812
  coll.ensure_index([['a', 1]])
1066
1813
 
@@ -1070,100 +1817,108 @@ end
1070
1817
  coll.ensure_index([['a', 1]])
1071
1818
  coll.ensure_index([['a', 1]])
1072
1819
 
1073
- sleep(3)
1820
+ sleep(1)
1074
1821
  # This won't be, so generate_indexes will be called twice
1075
1822
  coll.ensure_index([['a', 1]])
1823
+ coll.drop
1076
1824
  end
1077
1825
 
1078
- if @@version > '2.0.0'
1079
- def test_show_disk_loc
1080
- @@test.save({:a => 1})
1081
- @@test.save({:a => 2})
1082
- assert @@test.find({:a => 1}, :show_disk_loc => true).show_disk_loc
1083
- assert @@test.find({:a => 1}, :show_disk_loc => true).next['$diskLoc']
1084
- @@test.remove
1085
- end
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
1086
1835
 
1087
- def test_max_scan
1088
- 1000.times do |n|
1089
- @@test.save({:a => n})
1090
- end
1091
- assert @@test.find({:a => 999}).next
1092
- assert !@@test.find({:a => 999}, :max_scan => 500).next
1093
- @@test.remove
1094
- end
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
1095
1850
  end
1096
1851
 
1097
1852
  context "Grouping" do
1098
1853
  setup do
1099
- @@test.remove
1100
- @@test.save("a" => 1)
1101
- @@test.save("b" => 1)
1854
+ @test.remove
1855
+ @test.save("a" => 1)
1856
+ @test.save("b" => 1)
1102
1857
  @initial = {"count" => 0}
1103
1858
  @reduce_function = "function (obj, prev) { prev.count += inc_value; }"
1104
1859
  end
1105
1860
 
1106
1861
  should "fail if missing required options" do
1107
1862
  assert_raise MongoArgumentError do
1108
- @@test.group(:initial => {})
1863
+ @test.group(:initial => {})
1109
1864
  end
1110
1865
 
1111
1866
  assert_raise MongoArgumentError do
1112
- @@test.group(:reduce => "foo")
1867
+ @test.group(:reduce => "foo")
1113
1868
  end
1114
1869
  end
1115
1870
 
1116
1871
  should "group results using eval form" do
1117
- assert_equal 1, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 0.5}))[0]["count"]
1118
- assert_equal 2, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}))[0]["count"]
1119
- assert_equal 4, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 2}))[0]["count"]
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"]
1120
1875
  end
1121
1876
 
1122
1877
  should "finalize grouped results" do
1123
1878
  @finalize = "function(doc) {doc.f = doc.count + 200; }"
1124
- assert_equal 202, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}), :finalize => @finalize)[0]["f"]
1879
+ assert_equal 202, @test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}), :finalize => @finalize)[0]["f"]
1125
1880
  end
1126
1881
  end
1127
1882
 
1128
1883
  context "Grouping with key" do
1129
1884
  setup do
1130
- @@test.remove
1131
- @@test.save("a" => 1, "pop" => 100)
1132
- @@test.save("a" => 1, "pop" => 100)
1133
- @@test.save("a" => 2, "pop" => 100)
1134
- @@test.save("a" => 2, "pop" => 100)
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)
1135
1890
  @initial = {"count" => 0, "foo" => 1}
1136
1891
  @reduce_function = "function (obj, prev) { prev.count += obj.pop; }"
1137
1892
  end
1138
1893
 
1139
1894
  should "group" do
1140
- result = @@test.group(:key => :a, :initial => @initial, :reduce => @reduce_function)
1895
+ result = @test.group(:key => :a, :initial => @initial, :reduce => @reduce_function)
1141
1896
  assert result.all? { |r| r['count'] == 200 }
1142
1897
  end
1143
1898
  end
1144
1899
 
1145
1900
  context "Grouping with a key function" do
1146
- setup do
1147
- @@test.remove
1148
- @@test.save("a" => 1)
1149
- @@test.save("a" => 2)
1150
- @@test.save("a" => 3)
1151
- @@test.save("a" => 4)
1152
- @@test.save("a" => 5)
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)
1153
1908
  @initial = {"count" => 0}
1154
1909
  @keyf = "function (doc) { if(doc.a % 2 == 0) { return {even: true}; } else {return {odd: true}} };"
1155
1910
  @reduce = "function (obj, prev) { prev.count += 1; }"
1156
1911
  end
1157
1912
 
1158
1913
  should "group results" do
1159
- results = @@test.group(:keyf => @keyf, :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
1914
+ results = @test.group(:keyf => @keyf, :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
1160
1915
  assert results[0]['even'] && results[0]['count'] == 2.0
1161
1916
  assert results[1]['odd'] && results[1]['count'] == 3.0
1162
1917
  end
1163
1918
 
1164
1919
  should "group filtered results" do
1165
- results = @@test.group(:keyf => @keyf, :cond => {:a => {'$ne' => 2}},
1166
- :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
1920
+ results = @test.group(:keyf => @keyf, :cond => {:a => {'$ne' => 2}},
1921
+ :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
1167
1922
  assert results[0]['even'] && results[0]['count'] == 1.0
1168
1923
  assert results[1]['odd'] && results[1]['count'] == 3.0
1169
1924
  end
@@ -1171,7 +1926,7 @@ end
1171
1926
 
1172
1927
  context "A collection with two records" do
1173
1928
  setup do
1174
- @collection = @@db.collection('test-collection')
1929
+ @collection = @db.collection('test-collection')
1175
1930
  @collection.remove
1176
1931
  @collection.insert({:name => "Jones"})
1177
1932
  @collection.insert({:name => "Smith"})
@@ -1199,8 +1954,8 @@ end
1199
1954
 
1200
1955
  context "Drop index " do
1201
1956
  setup do
1202
- @@db.drop_collection('test-collection')
1203
- @collection = @@db.collection('test-collection')
1957
+ @db.drop_collection('test-collection')
1958
+ @collection = @db.collection('test-collection')
1204
1959
  end
1205
1960
 
1206
1961
  should "drop an index" do
@@ -1234,10 +1989,10 @@ end
1234
1989
 
1235
1990
  context "Creating indexes " do
1236
1991
  setup do
1237
- @@db.drop_collection('geo')
1238
- @@db.drop_collection('test-collection')
1239
- @collection = @@db.collection('test-collection')
1240
- @geo = @@db.collection('geo')
1992
+ @db.drop_collection('geo')
1993
+ @db.drop_collection('test-collection')
1994
+ @collection = @db.collection('test-collection')
1995
+ @geo = @db.collection('geo')
1241
1996
  end
1242
1997
 
1243
1998
  should "create index using symbols" do
@@ -1272,6 +2027,7 @@ end
1272
2027
  should "create a geoHaystack index" do
1273
2028
  @geo.save({ "_id" => 100, "pos" => { "long" => 126.9, "lat" => 35.2 }, "type" => "restaurant"})
1274
2029
  @geo.create_index([['pos', Mongo::GEOHAYSTACK], ['type', Mongo::ASCENDING]], :bucket_size => 1)
2030
+ assert @geo.index_information['pos_geoHaystack_type_1']
1275
2031
  end
1276
2032
 
1277
2033
  should "create a geo 2dsphere index" do
@@ -1286,31 +2042,37 @@ end
1286
2042
  end
1287
2043
 
1288
2044
  should "drop duplicates" do
1289
- @collection.insert({:a => 1})
1290
- @collection.insert({:a => 1})
1291
- assert_equal 2, @collection.find({:a => 1}).count
1292
- @collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :dropDups => true)
1293
- assert_equal 1, @collection.find({:a => 1}).count
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
1294
2052
  end
1295
2053
 
1296
2054
  should "drop duplicates with ruby-like drop_dups key" do
1297
- @collection.insert({:a => 1})
1298
- @collection.insert({:a => 1})
1299
- assert_equal 2, @collection.find({:a => 1}).count
1300
- @collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true)
1301
- assert_equal 1, @collection.find({:a => 1}).count
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
1302
2062
  end
1303
2063
 
1304
2064
  should "drop duplicates with ensure_index and drop_dups key" do
1305
- @collection.insert({:a => 1})
1306
- @collection.insert({:a => 1})
1307
- assert_equal 2, @collection.find({:a => 1}).count
1308
- @collection.ensure_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true)
1309
- assert_equal 1, @collection.find({:a => 1}).count
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
1310
2072
  end
1311
2073
 
1312
2074
  should "create an index in the background" do
1313
- if @@version > '1.3.1'
2075
+ if @version > '1.3.1'
1314
2076
  @collection.create_index([['b', Mongo::ASCENDING]], :background => true)
1315
2077
  assert @collection.index_information['b_1']['background'] == true
1316
2078
  else
@@ -1333,27 +2095,30 @@ end
1333
2095
  should "raise an error if index name is greater than 128" do
1334
2096
  assert_raise Mongo::OperationFailure do
1335
2097
  @collection.create_index([['a' * 25, 1], ['b' * 25, 1],
1336
- ['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]])
2098
+ ['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]])
1337
2099
  end
1338
2100
  end
1339
2101
 
1340
2102
  should "allow for an alternate name to be specified" do
1341
2103
  @collection.create_index([['a' * 25, 1], ['b' * 25, 1],
1342
- ['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]], :name => 'foo_index')
2104
+ ['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]], :name => 'foo_index')
1343
2105
  assert @collection.index_information['foo_index']
1344
2106
  end
1345
2107
 
1346
2108
  should "generate indexes in the proper order" do
1347
- @collection.expects(:insert_documents) do |sel, coll, safe|
1348
- assert_equal 'b_1_a_1', sel[:name]
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
1349
2118
  end
1350
2119
  @collection.create_index([['b', 1], ['a', 1]])
1351
2120
  end
1352
2121
 
1353
- should "allow multiple calls to create_index" do
1354
-
1355
- end
1356
-
1357
2122
  should "allow creation of multiple indexes" do
1358
2123
  assert @collection.create_index([['a', 1]])
1359
2124
  assert @collection.create_index([['a', 1]])
@@ -1372,8 +2137,8 @@ end
1372
2137
 
1373
2138
  context "Capped collections" do
1374
2139
  setup do
1375
- @@db.drop_collection('log')
1376
- @capped = @@db.create_collection('log', :capped => true, :size => 1024)
2140
+ @db.drop_collection('log')
2141
+ @capped = @db.create_collection('log', :capped => true, :size => LIMITED_MAX_BSON_SIZE)
1377
2142
 
1378
2143
  10.times { |n| @capped.insert({:n => n}) }
1379
2144
  end
@@ -1389,7 +2154,7 @@ end
1389
2154
  end
1390
2155
 
1391
2156
  should "fail tailable cursor on a non-capped collection" do
1392
- col = @@db['regular-collection']
2157
+ col = @db['regular-collection']
1393
2158
  col.insert({:a => 1000})
1394
2159
  tail = Cursor.new(col, :tailable => true, :order => [['$natural', 1]])
1395
2160
  assert_raise OperationFailure do