jonbell-mongo 1.3.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/LICENSE.txt +190 -0
  2. data/README.md +333 -0
  3. data/Rakefile +215 -0
  4. data/bin/mongo_console +21 -0
  5. data/docs/CREDITS.md +123 -0
  6. data/docs/FAQ.md +116 -0
  7. data/docs/GridFS.md +158 -0
  8. data/docs/HISTORY.md +263 -0
  9. data/docs/RELEASES.md +33 -0
  10. data/docs/REPLICA_SETS.md +72 -0
  11. data/docs/TUTORIAL.md +247 -0
  12. data/docs/WRITE_CONCERN.md +28 -0
  13. data/lib/mongo.rb +97 -0
  14. data/lib/mongo/collection.rb +895 -0
  15. data/lib/mongo/connection.rb +926 -0
  16. data/lib/mongo/cursor.rb +474 -0
  17. data/lib/mongo/db.rb +617 -0
  18. data/lib/mongo/exceptions.rb +71 -0
  19. data/lib/mongo/gridfs/grid.rb +107 -0
  20. data/lib/mongo/gridfs/grid_ext.rb +57 -0
  21. data/lib/mongo/gridfs/grid_file_system.rb +146 -0
  22. data/lib/mongo/gridfs/grid_io.rb +485 -0
  23. data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
  24. data/lib/mongo/repl_set_connection.rb +356 -0
  25. data/lib/mongo/util/conversions.rb +89 -0
  26. data/lib/mongo/util/core_ext.rb +60 -0
  27. data/lib/mongo/util/pool.rb +177 -0
  28. data/lib/mongo/util/server_version.rb +71 -0
  29. data/lib/mongo/util/support.rb +82 -0
  30. data/lib/mongo/util/uri_parser.rb +185 -0
  31. data/mongo.gemspec +34 -0
  32. data/test/auxillary/1.4_features.rb +166 -0
  33. data/test/auxillary/authentication_test.rb +68 -0
  34. data/test/auxillary/autoreconnect_test.rb +41 -0
  35. data/test/auxillary/fork_test.rb +30 -0
  36. data/test/auxillary/repl_set_auth_test.rb +58 -0
  37. data/test/auxillary/slave_connection_test.rb +36 -0
  38. data/test/auxillary/threaded_authentication_test.rb +101 -0
  39. data/test/bson/binary_test.rb +15 -0
  40. data/test/bson/bson_test.rb +654 -0
  41. data/test/bson/byte_buffer_test.rb +208 -0
  42. data/test/bson/hash_with_indifferent_access_test.rb +38 -0
  43. data/test/bson/json_test.rb +17 -0
  44. data/test/bson/object_id_test.rb +154 -0
  45. data/test/bson/ordered_hash_test.rb +210 -0
  46. data/test/bson/timestamp_test.rb +24 -0
  47. data/test/collection_test.rb +910 -0
  48. data/test/connection_test.rb +324 -0
  49. data/test/conversions_test.rb +119 -0
  50. data/test/cursor_fail_test.rb +75 -0
  51. data/test/cursor_message_test.rb +43 -0
  52. data/test/cursor_test.rb +483 -0
  53. data/test/db_api_test.rb +738 -0
  54. data/test/db_connection_test.rb +15 -0
  55. data/test/db_test.rb +315 -0
  56. data/test/grid_file_system_test.rb +259 -0
  57. data/test/grid_io_test.rb +209 -0
  58. data/test/grid_test.rb +258 -0
  59. data/test/load/thin/load.rb +24 -0
  60. data/test/load/unicorn/load.rb +23 -0
  61. data/test/replica_sets/connect_test.rb +112 -0
  62. data/test/replica_sets/connection_string_test.rb +32 -0
  63. data/test/replica_sets/count_test.rb +35 -0
  64. data/test/replica_sets/insert_test.rb +53 -0
  65. data/test/replica_sets/pooled_insert_test.rb +55 -0
  66. data/test/replica_sets/query_secondaries.rb +108 -0
  67. data/test/replica_sets/query_test.rb +51 -0
  68. data/test/replica_sets/replication_ack_test.rb +66 -0
  69. data/test/replica_sets/rs_test_helper.rb +27 -0
  70. data/test/safe_test.rb +68 -0
  71. data/test/support/hash_with_indifferent_access.rb +186 -0
  72. data/test/support/keys.rb +45 -0
  73. data/test/support_test.rb +18 -0
  74. data/test/test_helper.rb +102 -0
  75. data/test/threading/threading_with_large_pool_test.rb +90 -0
  76. data/test/threading_test.rb +87 -0
  77. data/test/tools/auth_repl_set_manager.rb +14 -0
  78. data/test/tools/repl_set_manager.rb +266 -0
  79. data/test/unit/collection_test.rb +130 -0
  80. data/test/unit/connection_test.rb +85 -0
  81. data/test/unit/cursor_test.rb +109 -0
  82. data/test/unit/db_test.rb +94 -0
  83. data/test/unit/grid_test.rb +49 -0
  84. data/test/unit/pool_test.rb +9 -0
  85. data/test/unit/repl_set_connection_test.rb +59 -0
  86. data/test/unit/safe_test.rb +125 -0
  87. data/test/uri_test.rb +91 -0
  88. metadata +224 -0
@@ -0,0 +1,24 @@
1
+ require './test/test_helper'
2
+
3
+ class TiumestampTest < Test::Unit::TestCase
4
+ include Mongo
5
+
6
+ def test_timestamp_equality
7
+ t1 = Timestamp.new(5000, 200)
8
+ t2 = Timestamp.new(5000, 200)
9
+ assert_equal t2, t1
10
+ end
11
+
12
+ def test_implements_array_for_backward_compatibility
13
+ ts = Timestamp.new(5000, 200)
14
+ assert_equal 200, ts[0]
15
+ assert_equal 5000, ts[1]
16
+
17
+ array = ts.map {|t| t }
18
+ assert_equal 2, array.length
19
+
20
+ assert_equal 200, array[0]
21
+ assert_equal 5000, array[1]
22
+ end
23
+
24
+ end
@@ -0,0 +1,910 @@
1
+ require './test/test_helper'
2
+
3
+ class TestCollection < Test::Unit::TestCase
4
+ @@connection ||= standard_connection(:op_timeout => 2)
5
+ @@db = @@connection.db(MONGO_TEST_DB)
6
+ @@test = @@db.collection("test")
7
+ @@version = @@connection.server_version
8
+
9
+ def setup
10
+ @@test.remove
11
+ end
12
+
13
+ def test_optional_pk_factory
14
+ @coll_default_pk = @@db.collection('stuff')
15
+ assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
16
+ @coll_default_pk = @@db.create_collection('more-stuff')
17
+ assert_equal BSON::ObjectId, @coll_default_pk.pk_factory
18
+
19
+ # Create a db with a pk_factory.
20
+ @db = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
21
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT).db(MONGO_TEST_DB, :pk => Object.new)
22
+ @coll = @db.collection('coll-with-pk')
23
+ assert @coll.pk_factory.is_a?(Object)
24
+
25
+ @coll = @db.create_collection('created_coll_with_pk')
26
+ assert @coll.pk_factory.is_a?(Object)
27
+ end
28
+
29
+ class TestPK
30
+ def self.create_pk
31
+ end
32
+ end
33
+
34
+ def test_pk_factory_on_collection
35
+ @coll = Collection.new('foo', @@db, TestPK)
36
+ assert_equal TestPK, @coll.pk_factory
37
+
38
+
39
+ @coll2 = Collection.new('foo', @@db, :pk => TestPK)
40
+ assert_equal TestPK, @coll2.pk_factory
41
+ end
42
+
43
+ def test_valid_names
44
+ assert_raise Mongo::InvalidNSName do
45
+ @@db["te$t"]
46
+ end
47
+
48
+ assert_raise Mongo::InvalidNSName do
49
+ @@db['$main']
50
+ end
51
+
52
+ assert @@db['$cmd']
53
+ assert @@db['oplog.$main']
54
+ end
55
+
56
+ def test_collection
57
+ assert_kind_of Collection, @@db["test"]
58
+ assert_equal @@db["test"].name(), @@db.collection("test").name()
59
+ assert_equal @@db["test"].name(), @@db[:test].name()
60
+
61
+ assert_kind_of Collection, @@db["test"]["foo"]
62
+ assert_equal @@db["test"]["foo"].name(), @@db.collection("test.foo").name()
63
+ assert_equal @@db["test"]["foo"].name(), @@db["test.foo"].name()
64
+
65
+ @@db["test"]["foo"].remove
66
+ @@db["test"]["foo"].insert("x" => 5)
67
+ assert_equal 5, @@db.collection("test.foo").find_one()["x"]
68
+ end
69
+
70
+ def test_rename_collection
71
+ @@db.drop_collection('foo1')
72
+ @@db.drop_collection('bar1')
73
+
74
+ @col = @@db.create_collection('foo1')
75
+ assert_equal 'foo1', @col.name
76
+
77
+ @col.rename('bar1')
78
+ assert_equal 'bar1', @col.name
79
+ end
80
+
81
+ def test_nil_id
82
+ assert_equal 5, @@test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
83
+ assert_equal 5, @@test.save({"_id" => 5, "foo" => "baz"}, {:safe => true})
84
+ assert_equal nil, @@test.find_one("foo" => "bar")
85
+ assert_equal "baz", @@test.find_one(:_id => 5)["foo"]
86
+ assert_raise OperationFailure do
87
+ @@test.insert({"_id" => 5, "foo" => "bar"}, {:safe => true})
88
+ end
89
+
90
+ assert_equal nil, @@test.insert({"_id" => nil, "foo" => "bar"}, {:safe => true})
91
+ assert_equal nil, @@test.save({"_id" => nil, "foo" => "baz"}, {:safe => true})
92
+ assert_equal nil, @@test.find_one("foo" => "bar")
93
+ assert_equal "baz", @@test.find_one(:_id => nil)["foo"]
94
+ assert_raise OperationFailure do
95
+ @@test.insert({"_id" => nil, "foo" => "bar"}, {:safe => true})
96
+ end
97
+ assert_raise OperationFailure do
98
+ @@test.insert({:_id => nil, "foo" => "bar"}, {:safe => true})
99
+ end
100
+ end
101
+
102
+ if @@version > "1.1"
103
+ def setup_for_distinct
104
+ @@test.remove
105
+ @@test.insert([{:a => 0, :b => {:c => "a"}},
106
+ {:a => 1, :b => {:c => "b"}},
107
+ {:a => 1, :b => {:c => "c"}},
108
+ {:a => 2, :b => {:c => "a"}},
109
+ {:a => 3},
110
+ {:a => 3}])
111
+ end
112
+
113
+ def test_distinct_queries
114
+ setup_for_distinct
115
+ assert_equal [0, 1, 2, 3], @@test.distinct(:a).sort
116
+ assert_equal ["a", "b", "c"], @@test.distinct("b.c").sort
117
+ end
118
+
119
+ if @@version >= "1.2"
120
+ def test_filter_collection_with_query
121
+ setup_for_distinct
122
+ assert_equal [2, 3], @@test.distinct(:a, {:a => {"$gt" => 1}}).sort
123
+ end
124
+
125
+ def test_filter_nested_objects
126
+ setup_for_distinct
127
+ assert_equal ["a", "b"], @@test.distinct("b.c", {"b.c" => {"$ne" => "c"}}).sort
128
+ end
129
+ end
130
+ end
131
+
132
+ def test_safe_insert
133
+ @@test.create_index("hello", :unique => true)
134
+ a = {"hello" => "world"}
135
+ @@test.insert(a)
136
+ @@test.insert(a)
137
+ assert(@@db.get_last_error['err'].include?("11000"))
138
+
139
+ assert_raise OperationFailure do
140
+ @@test.insert(a, :safe => true)
141
+ end
142
+ end
143
+
144
+ def test_maximum_insert_size
145
+ docs = []
146
+ 16.times do
147
+ docs << {'foo' => 'a' * 1_000_000}
148
+ end
149
+
150
+ assert_raise InvalidOperation do
151
+ @@test.insert(docs)
152
+ end
153
+ end
154
+
155
+ if @@version >= "1.5.1"
156
+ def test_safe_mode_with_advanced_safe_with_invalid_options
157
+ assert_raise_error ArgumentError, "Unknown key(s): wtime" do
158
+ @@test.insert({:foo => 1}, :safe => {:w => 2, :wtime => 1, :fsync => true})
159
+ end
160
+ assert_raise_error ArgumentError, "Unknown key(s): wtime" do
161
+ @@test.update({:foo => 1}, {:foo => 2}, :safe => {:w => 2, :wtime => 1, :fsync => true})
162
+ end
163
+
164
+ assert_raise_error ArgumentError, "Unknown key(s): wtime" do
165
+ @@test.remove({:foo => 2}, :safe => {:w => 2, :wtime => 1, :fsync => true})
166
+ end
167
+ end
168
+ end
169
+
170
+ def test_update
171
+ id1 = @@test.save("x" => 5)
172
+ @@test.update({}, {"$inc" => {"x" => 1}})
173
+ assert_equal 1, @@test.count()
174
+ assert_equal 6, @@test.find_one(:_id => id1)["x"]
175
+
176
+ id2 = @@test.save("x" => 1)
177
+ @@test.update({"x" => 6}, {"$inc" => {"x" => 1}})
178
+ assert_equal 7, @@test.find_one(:_id => id1)["x"]
179
+ assert_equal 1, @@test.find_one(:_id => id2)["x"]
180
+ end
181
+
182
+ if @@version >= "1.1.3"
183
+ def test_multi_update
184
+ @@test.save("num" => 10)
185
+ @@test.save("num" => 10)
186
+ @@test.save("num" => 10)
187
+ assert_equal 3, @@test.count
188
+
189
+ @@test.update({"num" => 10}, {"$set" => {"num" => 100}}, :multi => true)
190
+ @@test.find.each do |doc|
191
+ assert_equal 100, doc["num"]
192
+ end
193
+ end
194
+ end
195
+
196
+ def test_upsert
197
+ @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
198
+ @@test.update({"page" => "/"}, {"$inc" => {"count" => 1}}, :upsert => true)
199
+
200
+ assert_equal 1, @@test.count()
201
+ assert_equal 2, @@test.find_one()["count"]
202
+ end
203
+
204
+ if @@version < "1.1.3"
205
+ def test_safe_update
206
+ @@test.create_index("x")
207
+ @@test.insert("x" => 5)
208
+
209
+ @@test.update({}, {"$inc" => {"x" => 1}})
210
+ assert @@db.error?
211
+
212
+ # Can't change an index.
213
+ assert_raise OperationFailure do
214
+ @@test.update({}, {"$inc" => {"x" => 1}}, :safe => true)
215
+ end
216
+ @@test.drop
217
+ end
218
+ else
219
+ def test_safe_update
220
+ @@test.create_index("x", :unique => true)
221
+ @@test.insert("x" => 5)
222
+ @@test.insert("x" => 10)
223
+
224
+ # Can update an indexed collection.
225
+ @@test.update({}, {"$inc" => {"x" => 1}})
226
+ assert !@@db.error?
227
+
228
+ # Can't duplicate an index.
229
+ assert_raise OperationFailure do
230
+ @@test.update({}, {"x" => 10}, :safe => true)
231
+ end
232
+ @@test.drop
233
+ end
234
+ end
235
+
236
+ def test_safe_save
237
+ @@test.create_index("hello", :unique => true)
238
+
239
+ @@test.save("hello" => "world")
240
+ @@test.save("hello" => "world")
241
+
242
+ assert_raise OperationFailure do
243
+ @@test.save({"hello" => "world"}, :safe => true)
244
+ end
245
+ @@test.drop
246
+ end
247
+
248
+ def test_mocked_safe_remove
249
+ @conn = standard_connection
250
+ @db = @conn[MONGO_TEST_DB]
251
+ @test = @db['test-safe-remove']
252
+ @test.save({:a => 20})
253
+ @conn.stubs(:receive).returns([[{'ok' => 0, 'err' => 'failed'}], 1, 0])
254
+
255
+ assert_raise OperationFailure do
256
+ @test.remove({}, :safe => true)
257
+ end
258
+ @test.drop
259
+ end
260
+
261
+ def test_safe_remove
262
+ @conn = standard_connection
263
+ @db = @conn[MONGO_TEST_DB]
264
+ @test = @db['test-safe-remove']
265
+ @test.save({:a => 50})
266
+ assert_equal 1, @test.remove({}, :safe => true)["n"]
267
+ @test.drop
268
+ end
269
+
270
+ def test_remove_return_value
271
+ assert_equal true, @@test.remove({})
272
+ end
273
+
274
+ def test_count
275
+ @@test.drop
276
+
277
+ assert_equal 0, @@test.count
278
+ @@test.save("x" => 1)
279
+ @@test.save("x" => 2)
280
+ assert_equal 2, @@test.count
281
+ end
282
+
283
+ # Note: #size is just an alias for #count.
284
+ def test_size
285
+ @@test.drop
286
+
287
+ assert_equal 0, @@test.count
288
+ assert_equal @@test.size, @@test.count
289
+ @@test.save("x" => 1)
290
+ @@test.save("x" => 2)
291
+ assert_equal @@test.size, @@test.count
292
+ end
293
+
294
+ def test_no_timeout_option
295
+ @@test.drop
296
+
297
+ assert_raise ArgumentError, "Timeout can be set to false only when #find is invoked with a block." do
298
+ @@test.find({}, :timeout => false)
299
+ end
300
+
301
+ @@test.find({}, :timeout => false) do |cursor|
302
+ assert_equal 0, cursor.count
303
+ end
304
+
305
+ @@test.save("x" => 1)
306
+ @@test.save("x" => 2)
307
+ @@test.find({}, :timeout => false) do |cursor|
308
+ assert_equal 2, cursor.count
309
+ end
310
+ end
311
+
312
+ def test_defualt_timeout
313
+ cursor = @@test.find
314
+ assert_equal true, cursor.timeout
315
+ end
316
+
317
+ def test_fields_as_hash
318
+ @@test.save(:a => 1, :b => 1, :c => 1)
319
+
320
+ doc = @@test.find_one({:a => 1}, :fields => {:b => 0})
321
+ assert_nil doc['b']
322
+ assert doc['a']
323
+ assert doc['c']
324
+
325
+ doc = @@test.find_one({:a => 1}, :fields => {:a => 1, :b => 1})
326
+ assert_nil doc['c']
327
+ assert doc['a']
328
+ assert doc['b']
329
+
330
+
331
+ assert_raise Mongo::OperationFailure do
332
+ @@test.find_one({:a => 1}, :fields => {:a => 1, :b => 0})
333
+ end
334
+ end
335
+
336
+ if @@version >= "1.5.1"
337
+ def test_fields_with_slice
338
+ @@test.save({:foo => [1, 2, 3, 4, 5, 6], :test => 'slice'})
339
+
340
+ doc = @@test.find_one({:test => 'slice'}, :fields => {'foo' => {'$slice' => [0, 3]}})
341
+ assert_equal [1, 2, 3], doc['foo']
342
+ @@test.remove
343
+ end
344
+ end
345
+
346
+ def test_find_one
347
+ id = @@test.save("hello" => "world", "foo" => "bar")
348
+
349
+ assert_equal "world", @@test.find_one()["hello"]
350
+ assert_equal @@test.find_one(id), @@test.find_one()
351
+ assert_equal @@test.find_one(nil), @@test.find_one()
352
+ assert_equal @@test.find_one({}), @@test.find_one()
353
+ assert_equal @@test.find_one("hello" => "world"), @@test.find_one()
354
+ assert_equal @@test.find_one(BSON::OrderedHash["hello", "world"]), @@test.find_one()
355
+
356
+ assert @@test.find_one(nil, :fields => ["hello"]).include?("hello")
357
+ assert !@@test.find_one(nil, :fields => ["foo"]).include?("hello")
358
+ assert_equal ["_id"], @@test.find_one(nil, :fields => []).keys()
359
+
360
+ assert_equal nil, @@test.find_one("hello" => "foo")
361
+ assert_equal nil, @@test.find_one(BSON::OrderedHash["hello", "foo"])
362
+ assert_equal nil, @@test.find_one(ObjectId.new)
363
+
364
+ assert_raise TypeError do
365
+ @@test.find_one(6)
366
+ end
367
+ end
368
+
369
+ def test_insert_adds_id
370
+ doc = {"hello" => "world"}
371
+ @@test.insert(doc)
372
+ assert(doc.include?(:_id))
373
+
374
+ docs = [{"hello" => "world"}, {"hello" => "world"}]
375
+ @@test.insert(docs)
376
+ docs.each do |d|
377
+ assert(d.include?(:_id))
378
+ end
379
+ end
380
+
381
+ def test_save_adds_id
382
+ doc = {"hello" => "world"}
383
+ @@test.save(doc)
384
+ assert(doc.include?(:_id))
385
+ end
386
+
387
+ def test_optional_find_block
388
+ 10.times do |i|
389
+ @@test.save("i" => i)
390
+ end
391
+
392
+ x = nil
393
+ @@test.find("i" => 2) { |cursor|
394
+ x = cursor.count()
395
+ }
396
+ assert_equal 1, x
397
+
398
+ i = 0
399
+ @@test.find({}, :skip => 5) do |cursor|
400
+ cursor.each do |doc|
401
+ i = i + 1
402
+ end
403
+ end
404
+ assert_equal 5, i
405
+
406
+ c = nil
407
+ @@test.find() do |cursor|
408
+ c = cursor
409
+ end
410
+ assert c.closed?
411
+ end
412
+
413
+ if @@version > "1.1.1"
414
+ def test_map_reduce
415
+ @@test << { "user_id" => 1 }
416
+ @@test << { "user_id" => 2 }
417
+
418
+ m = "function() { emit(this.user_id, 1); }"
419
+ r = "function(k,vals) { return 1; }"
420
+ res = @@test.map_reduce(m, r, :out => 'foo');
421
+ assert res.find_one({"_id" => 1})
422
+ assert res.find_one({"_id" => 2})
423
+ end
424
+
425
+ def test_map_reduce_with_code_objects
426
+ @@test << { "user_id" => 1 }
427
+ @@test << { "user_id" => 2 }
428
+
429
+ m = Code.new("function() { emit(this.user_id, 1); }")
430
+ r = Code.new("function(k,vals) { return 1; }")
431
+ res = @@test.map_reduce(m, r, :out => 'foo');
432
+ assert res.find_one({"_id" => 1})
433
+ assert res.find_one({"_id" => 2})
434
+ end
435
+
436
+ def test_map_reduce_with_options
437
+ @@test.remove
438
+ @@test << { "user_id" => 1 }
439
+ @@test << { "user_id" => 2 }
440
+ @@test << { "user_id" => 3 }
441
+
442
+ m = Code.new("function() { emit(this.user_id, 1); }")
443
+ r = Code.new("function(k,vals) { return 1; }")
444
+ res = @@test.map_reduce(m, r, :query => {"user_id" => {"$gt" => 1}}, :out => 'foo');
445
+ assert_equal 2, res.count
446
+ assert res.find_one({"_id" => 2})
447
+ assert res.find_one({"_id" => 3})
448
+ end
449
+
450
+ def test_map_reduce_with_raw_response
451
+ m = Code.new("function() { emit(this.user_id, 1); }")
452
+ r = Code.new("function(k,vals) { return 1; }")
453
+ res = @@test.map_reduce(m, r, :raw => true, :out => 'foo')
454
+ assert res["result"]
455
+ assert res["counts"]
456
+ assert res["timeMillis"]
457
+ end
458
+
459
+ def test_map_reduce_with_output_collection
460
+ output_collection = "test-map-coll"
461
+ m = Code.new("function() { emit(this.user_id, 1); }")
462
+ r = Code.new("function(k,vals) { return 1; }")
463
+ res = @@test.map_reduce(m, r, :raw => true, :out => output_collection)
464
+ assert_equal output_collection, res["result"]
465
+ assert res["counts"]
466
+ assert res["timeMillis"]
467
+ end
468
+
469
+
470
+ if @@version >= "1.8.0"
471
+ def test_map_reduce_with_collection_merge
472
+ @@test << {:user_id => 1}
473
+ @@test << {:user_id => 2}
474
+ output_collection = "test-map-coll"
475
+ m = Code.new("function() { emit(this.user_id, {count: 1}); }")
476
+ r = Code.new("function(k,vals) { var sum = 0;" +
477
+ " vals.forEach(function(v) { sum += v.count;} ); return {count: sum}; }")
478
+ res = @@test.map_reduce(m, r, :out => output_collection)
479
+
480
+ @@test.remove
481
+ @@test << {:user_id => 3}
482
+ res = @@test.map_reduce(m, r, :out => {:merge => output_collection})
483
+ assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 1}
484
+
485
+ @@test.remove
486
+ @@test << {:user_id => 3}
487
+ res = @@test.map_reduce(m, r, :out => {:reduce => output_collection})
488
+ assert res.find.to_a.any? {|doc| doc["_id"] == 3 && doc["value"]["count"] == 2}
489
+
490
+ assert_raise ArgumentError do
491
+ @@test.map_reduce(m, r, :out => {:inline => 1})
492
+ end
493
+
494
+ @@test.map_reduce(m, r, :raw => true, :out => {:inline => 1})
495
+ assert res["results"]
496
+ end
497
+ end
498
+ end
499
+
500
+ if @@version > "1.3.0"
501
+ def test_find_and_modify
502
+ @@test << { :a => 1, :processed => false }
503
+ @@test << { :a => 2, :processed => false }
504
+ @@test << { :a => 3, :processed => false }
505
+
506
+ @@test.find_and_modify(:query => {}, :sort => [['a', -1]], :update => {"$set" => {:processed => true}})
507
+
508
+ assert @@test.find_one({:a => 3})['processed']
509
+ end
510
+
511
+ def test_find_and_modify_with_invalid_options
512
+ @@test << { :a => 1, :processed => false }
513
+ @@test << { :a => 2, :processed => false }
514
+ @@test << { :a => 3, :processed => false }
515
+
516
+ assert_raise Mongo::OperationFailure do
517
+ @@test.find_and_modify(:blimey => {})
518
+ end
519
+ end
520
+ end
521
+
522
+ if @@version >= "1.3.5"
523
+ def test_coll_stats
524
+ @@test << {:n => 1}
525
+ @@test.create_index("n")
526
+
527
+ assert_equal "#{MONGO_TEST_DB}.test", @@test.stats['ns']
528
+ end
529
+ end
530
+
531
+ def test_saving_dates_pre_epoch
532
+ begin
533
+ @@test.save({'date' => Time.utc(1600)})
534
+ assert_in_delta Time.utc(1600), @@test.find_one()["date"], 2
535
+ rescue ArgumentError
536
+ # See note in test_date_before_epoch (BSONTest)
537
+ end
538
+ end
539
+
540
+ def test_save_symbol_find_string
541
+ @@test.save(:foo => :mike)
542
+
543
+ assert_equal :mike, @@test.find_one(:foo => :mike)["foo"]
544
+ assert_equal :mike, @@test.find_one("foo" => :mike)["foo"]
545
+
546
+ # TODO enable these tests conditionally based on server version (if >1.0)
547
+ # assert_equal :mike, @@test.find_one(:foo => "mike")["foo"]
548
+ # assert_equal :mike, @@test.find_one("foo" => "mike")["foo"]
549
+ end
550
+
551
+ def test_limit_and_skip
552
+ 10.times do |i|
553
+ @@test.save(:foo => i)
554
+ end
555
+
556
+ assert_equal 5, @@test.find({}, :skip => 5).next_document()["foo"]
557
+ assert_equal nil, @@test.find({}, :skip => 10).next_document()
558
+
559
+ assert_equal 5, @@test.find({}, :limit => 5).to_a.length
560
+
561
+ assert_equal 3, @@test.find({}, :skip => 3, :limit => 5).next_document()["foo"]
562
+ assert_equal 5, @@test.find({}, :skip => 3, :limit => 5).to_a.length
563
+ end
564
+
565
+ def test_large_limit
566
+ 2000.times do |i|
567
+ @@test.insert("x" => i, "y" => "mongomongo" * 1000)
568
+ end
569
+
570
+ assert_equal 2000, @@test.count
571
+
572
+ i = 0
573
+ y = 0
574
+ @@test.find({}, :limit => 1900).each do |doc|
575
+ i += 1
576
+ y += doc["x"]
577
+ end
578
+
579
+ assert_equal 1900, i
580
+ assert_equal 1804050, y
581
+ end
582
+
583
+ def test_small_limit
584
+ @@test.insert("x" => "hello world")
585
+ @@test.insert("x" => "goodbye world")
586
+
587
+ assert_equal 2, @@test.count
588
+
589
+ x = 0
590
+ @@test.find({}, :limit => 1).each do |doc|
591
+ x += 1
592
+ assert_equal "hello world", doc["x"]
593
+ end
594
+
595
+ assert_equal 1, x
596
+ end
597
+
598
+ def test_find_with_transformer
599
+ klass = Struct.new(:id, :a)
600
+ transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
601
+ cursor = @@test.find({}, :transformer => transformer)
602
+ assert_equal(transformer, cursor.transformer)
603
+ end
604
+
605
+ def test_find_one_with_transformer
606
+ klass = Struct.new(:id, :a)
607
+ transformer = Proc.new { |doc| klass.new(doc['_id'], doc['a']) }
608
+ id = @@test.insert('a' => 1)
609
+ doc = @@test.find_one(id, :transformer => transformer)
610
+ assert_instance_of(klass, doc)
611
+ end
612
+
613
+ def test_ensure_index
614
+ @@test.drop_indexes
615
+ @@test.insert("x" => "hello world")
616
+ assert_equal 1, @@test.index_information.keys.count #default index
617
+
618
+ @@test.ensure_index([["x", Mongo::DESCENDING]], {})
619
+ assert_equal 2, @@test.index_information.keys.count
620
+ assert @@test.index_information.keys.include? "x_-1"
621
+
622
+ @@test.ensure_index([["x", Mongo::ASCENDING]])
623
+ assert @@test.index_information.keys.include? "x_1"
624
+
625
+ @@test.ensure_index([["type", 1], ["date", -1]])
626
+ assert @@test.index_information.keys.include? "type_1_date_-1"
627
+
628
+ @@test.drop_index("x_1")
629
+ assert_equal 3, @@test.index_information.keys.count
630
+ @@test.drop_index("x_-1")
631
+ assert_equal 2, @@test.index_information.keys.count
632
+
633
+ @@test.ensure_index([["x", Mongo::DESCENDING]], {})
634
+ assert_equal 3, @@test.index_information.keys.count
635
+ assert @@test.index_information.keys.include? "x_-1"
636
+
637
+ # Make sure that drop_index expires cache properly
638
+ @@test.ensure_index([['a', 1]])
639
+ assert @@test.index_information.keys.include?("a_1")
640
+ @@test.drop_index("a_1")
641
+ assert !@@test.index_information.keys.include?("a_1")
642
+ @@test.ensure_index([['a', 1]])
643
+ assert @@test.index_information.keys.include?("a_1")
644
+ @@test.drop_index("a_1")
645
+ end
646
+
647
+ def test_ensure_index_timeout
648
+ @@db.cache_time = 2
649
+ coll = @@db['ensure_test']
650
+ coll.expects(:generate_indexes).twice
651
+ coll.ensure_index([['a', 1]])
652
+
653
+ # These will be cached
654
+ coll.ensure_index([['a', 1]])
655
+ coll.ensure_index([['a', 1]])
656
+ coll.ensure_index([['a', 1]])
657
+ coll.ensure_index([['a', 1]])
658
+
659
+ sleep(3)
660
+ # This won't be, so generate_indexes will be called twice
661
+ coll.ensure_index([['a', 1]])
662
+ end
663
+
664
+ context "Grouping" do
665
+ setup do
666
+ @@test.remove
667
+ @@test.save("a" => 1)
668
+ @@test.save("b" => 1)
669
+ @initial = {"count" => 0}
670
+ @reduce_function = "function (obj, prev) { prev.count += inc_value; }"
671
+ end
672
+
673
+ should "fail if missing required options" do
674
+ assert_raise MongoArgumentError do
675
+ @@test.group(:initial => {})
676
+ end
677
+
678
+ assert_raise MongoArgumentError do
679
+ @@test.group(:reduce => "foo")
680
+ end
681
+ end
682
+
683
+ should "group results using eval form" do
684
+ assert_equal 1, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 0.5}))[0]["count"]
685
+ assert_equal 2, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}))[0]["count"]
686
+ assert_equal 4, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 2}))[0]["count"]
687
+ end
688
+
689
+ should "finalize grouped results" do
690
+ @finalize = "function(doc) {doc.f = doc.count + 200; }"
691
+ assert_equal 202, @@test.group(:initial => @initial, :reduce => Code.new(@reduce_function, {"inc_value" => 1}), :finalize => @finalize)[0]["f"]
692
+ end
693
+ end
694
+
695
+ context "Grouping with key" do
696
+ setup do
697
+ @@test.remove
698
+ @@test.save("a" => 1, "pop" => 100)
699
+ @@test.save("a" => 1, "pop" => 100)
700
+ @@test.save("a" => 2, "pop" => 100)
701
+ @@test.save("a" => 2, "pop" => 100)
702
+ @initial = {"count" => 0, "foo" => 1}
703
+ @reduce_function = "function (obj, prev) { prev.count += obj.pop; }"
704
+ end
705
+
706
+ should "group" do
707
+ result = @@test.group(:key => :a, :initial => @initial, :reduce => @reduce_function)
708
+ assert result.all? { |r| r['count'] == 200 }
709
+ end
710
+ end
711
+
712
+ context "Grouping with a key function" do
713
+ setup do
714
+ @@test.remove
715
+ @@test.save("a" => 1)
716
+ @@test.save("a" => 2)
717
+ @@test.save("a" => 3)
718
+ @@test.save("a" => 4)
719
+ @@test.save("a" => 5)
720
+ @initial = {"count" => 0}
721
+ @keyf = "function (doc) { if(doc.a % 2 == 0) { return {even: true}; } else {return {odd: true}} };"
722
+ @reduce = "function (obj, prev) { prev.count += 1; }"
723
+ end
724
+
725
+ should "group results" do
726
+ results = @@test.group(:keyf => @keyf, :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
727
+ assert results[0]['even'] && results[0]['count'] == 2.0
728
+ assert results[1]['odd'] && results[1]['count'] == 3.0
729
+ end
730
+
731
+ should "group filtered results" do
732
+ results = @@test.group(:keyf => @keyf, :cond => {:a => {'$ne' => 2}},
733
+ :initial => @initial, :reduce => @reduce).sort {|a, b| a['count'] <=> b['count']}
734
+ assert results[0]['even'] && results[0]['count'] == 1.0
735
+ assert results[1]['odd'] && results[1]['count'] == 3.0
736
+ end
737
+ end
738
+
739
+ context "A collection with two records" do
740
+ setup do
741
+ @collection = @@db.collection('test-collection')
742
+ @collection.insert({:name => "Jones"})
743
+ @collection.insert({:name => "Smith"})
744
+ end
745
+
746
+ should "have two records" do
747
+ assert_equal 2, @collection.size
748
+ end
749
+
750
+ should "remove the two records" do
751
+ @collection.remove()
752
+ assert_equal 0, @collection.size
753
+ end
754
+
755
+ should "remove all records if an empty document is specified" do
756
+ @collection.remove({})
757
+ assert_equal 0, @collection.find.count
758
+ end
759
+
760
+ should "remove only matching records" do
761
+ @collection.remove({:name => "Jones"})
762
+ assert_equal 1, @collection.size
763
+ end
764
+ end
765
+
766
+ context "Creating indexes " do
767
+ setup do
768
+ @@db.drop_collection('geo')
769
+ @@db.drop_collection('test-collection')
770
+ @collection = @@db.collection('test-collection')
771
+ @geo = @@db.collection('geo')
772
+ end
773
+
774
+ should "create index using symbols" do
775
+ @collection.create_index :foo, :name => :bar
776
+ @geo.create_index :goo, :name => :baz
777
+ assert @collection.index_information['bar']
778
+ @collection.drop_index :bar
779
+ assert_nil @collection.index_information['bar']
780
+ assert @geo.index_information['baz']
781
+ @geo.drop_index(:baz)
782
+ assert_nil @geo.index_information['baz']
783
+ end
784
+
785
+ should "create a geospatial index" do
786
+ @geo.save({'loc' => [-100, 100]})
787
+ @geo.create_index([['loc', Mongo::GEO2D]])
788
+ assert @geo.index_information['loc_2d']
789
+ end
790
+
791
+ should "create a unique index" do
792
+ @collection.create_index([['a', Mongo::ASCENDING]], :unique => true)
793
+ assert @collection.index_information['a_1']['unique'] == true
794
+ end
795
+
796
+ should "drop duplicates" do
797
+ @collection.insert({:a => 1})
798
+ @collection.insert({:a => 1})
799
+ assert_equal 2, @collection.find({:a => 1}).count
800
+ @collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :dropDups => true)
801
+ assert_equal 1, @collection.find({:a => 1}).count
802
+ end
803
+
804
+ should "drop duplicates with ruby-like drop_dups key" do
805
+ @collection.insert({:a => 1})
806
+ @collection.insert({:a => 1})
807
+ assert_equal 2, @collection.find({:a => 1}).count
808
+ @collection.create_index([['a', Mongo::ASCENDING]], :unique => true, :drop_dups => true)
809
+ assert_equal 1, @collection.find({:a => 1}).count
810
+ end
811
+
812
+ should "create an index in the background" do
813
+ if @@version > '1.3.1'
814
+ @collection.create_index([['b', Mongo::ASCENDING]], :background => true)
815
+ assert @collection.index_information['b_1']['background'] == true
816
+ else
817
+ assert true
818
+ end
819
+ end
820
+
821
+ should "require an array of arrays" do
822
+ assert_raise MongoArgumentError do
823
+ @collection.create_index(['c', Mongo::ASCENDING])
824
+ end
825
+ end
826
+
827
+ should "enforce proper index types" do
828
+ assert_raise MongoArgumentError do
829
+ @collection.create_index([['c', 'blah']])
830
+ end
831
+ end
832
+
833
+ should "raise an error if index name is greater than 128" do
834
+ assert_raise Mongo::OperationFailure do
835
+ @collection.create_index([['a' * 25, 1], ['b' * 25, 1],
836
+ ['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]])
837
+ end
838
+ end
839
+
840
+ should "allow for an alternate name to be specified" do
841
+ @collection.create_index([['a' * 25, 1], ['b' * 25, 1],
842
+ ['c' * 25, 1], ['d' * 25, 1], ['e' * 25, 1]], :name => 'foo_index')
843
+ assert @collection.index_information['foo_index']
844
+ end
845
+
846
+ should "generate indexes in the proper order" do
847
+ @collection.expects(:insert_documents) do |sel, coll, safe|
848
+ assert_equal 'b_1_a_1', sel[:name]
849
+ end
850
+ @collection.create_index([['b', 1], ['a', 1]])
851
+ end
852
+
853
+ should "allow multiple calls to create_index" do
854
+
855
+ end
856
+
857
+ should "allow creation of multiple indexes" do
858
+ assert @collection.create_index([['a', 1]])
859
+ assert @collection.create_index([['a', 1]])
860
+ end
861
+
862
+ context "with an index created" do
863
+ setup do
864
+ @collection.create_index([['b', 1], ['a', 1]])
865
+ end
866
+
867
+ should "return properly ordered index information" do
868
+ assert @collection.index_information['b_1_a_1']
869
+ end
870
+ end
871
+ end
872
+
873
+ context "Capped collections" do
874
+ setup do
875
+ @@db.drop_collection('log')
876
+ @capped = @@db.create_collection('log', :capped => true, :size => 1024)
877
+
878
+ 10.times { |n| @capped.insert({:n => n}) }
879
+ end
880
+
881
+ should "find using a standard cursor" do
882
+ cursor = @capped.find
883
+ 10.times do
884
+ assert cursor.next_document
885
+ end
886
+ assert_nil cursor.next_document
887
+ @capped.insert({:n => 100})
888
+ assert_nil cursor.next_document
889
+ end
890
+
891
+ should "fail tailable cursor on a non-capped collection" do
892
+ col = @@db['regular-collection']
893
+ col.insert({:a => 1000})
894
+ tail = Cursor.new(col, :tailable => true, :order => [['$natural', 1]])
895
+ assert_raise OperationFailure do
896
+ tail.next_document
897
+ end
898
+ end
899
+
900
+ should "find using a tailable cursor" do
901
+ tail = Cursor.new(@capped, :tailable => true, :order => [['$natural', 1]])
902
+ 10.times do
903
+ assert tail.next_document
904
+ end
905
+ assert_nil tail.next_document
906
+ @capped.insert({:n => 100})
907
+ assert tail.next_document
908
+ end
909
+ end
910
+ end