jmongo 1.0.3 → 1.1.0

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