mongo 0.1.0 → 0.15

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 (89) hide show
  1. data/README.rdoc +268 -71
  2. data/Rakefile +27 -62
  3. data/bin/bson_benchmark.rb +59 -0
  4. data/bin/mongo_console +3 -3
  5. data/bin/run_test_script +19 -0
  6. data/bin/standard_benchmark +109 -0
  7. data/examples/admin.rb +41 -0
  8. data/examples/benchmarks.rb +42 -0
  9. data/examples/blog.rb +76 -0
  10. data/examples/capped.rb +23 -0
  11. data/examples/cursor.rb +47 -0
  12. data/examples/gridfs.rb +87 -0
  13. data/examples/index_test.rb +125 -0
  14. data/examples/info.rb +30 -0
  15. data/examples/queries.rb +69 -0
  16. data/examples/simple.rb +23 -0
  17. data/examples/strict.rb +34 -0
  18. data/examples/types.rb +35 -0
  19. data/lib/mongo.rb +9 -2
  20. data/lib/mongo/admin.rb +65 -68
  21. data/lib/mongo/collection.rb +379 -117
  22. data/lib/mongo/connection.rb +151 -0
  23. data/lib/mongo/cursor.rb +271 -216
  24. data/lib/mongo/db.rb +500 -315
  25. data/lib/mongo/errors.rb +26 -0
  26. data/lib/mongo/gridfs.rb +16 -0
  27. data/lib/mongo/gridfs/chunk.rb +92 -0
  28. data/lib/mongo/gridfs/grid_store.rb +464 -0
  29. data/lib/mongo/message.rb +16 -0
  30. data/lib/mongo/message/get_more_message.rb +24 -13
  31. data/lib/mongo/message/insert_message.rb +29 -11
  32. data/lib/mongo/message/kill_cursors_message.rb +23 -12
  33. data/lib/mongo/message/message.rb +74 -62
  34. data/lib/mongo/message/message_header.rb +35 -24
  35. data/lib/mongo/message/msg_message.rb +21 -9
  36. data/lib/mongo/message/opcodes.rb +26 -15
  37. data/lib/mongo/message/query_message.rb +63 -43
  38. data/lib/mongo/message/remove_message.rb +29 -12
  39. data/lib/mongo/message/update_message.rb +30 -13
  40. data/lib/mongo/query.rb +97 -89
  41. data/lib/mongo/types/binary.rb +25 -21
  42. data/lib/mongo/types/code.rb +30 -0
  43. data/lib/mongo/types/dbref.rb +19 -23
  44. data/lib/mongo/types/objectid.rb +130 -116
  45. data/lib/mongo/types/regexp_of_holding.rb +27 -31
  46. data/lib/mongo/util/bson.rb +273 -160
  47. data/lib/mongo/util/byte_buffer.rb +32 -28
  48. data/lib/mongo/util/ordered_hash.rb +88 -42
  49. data/lib/mongo/util/xml_to_ruby.rb +18 -15
  50. data/mongo-ruby-driver.gemspec +103 -0
  51. data/test/mongo-qa/_common.rb +8 -0
  52. data/test/mongo-qa/admin +26 -0
  53. data/test/mongo-qa/capped +22 -0
  54. data/test/mongo-qa/count1 +18 -0
  55. data/test/mongo-qa/dbs +22 -0
  56. data/test/mongo-qa/find +10 -0
  57. data/test/mongo-qa/find1 +15 -0
  58. data/test/mongo-qa/gridfs_in +16 -0
  59. data/test/mongo-qa/gridfs_out +17 -0
  60. data/test/mongo-qa/indices +49 -0
  61. data/test/mongo-qa/remove +25 -0
  62. data/test/mongo-qa/stress1 +35 -0
  63. data/test/mongo-qa/test1 +11 -0
  64. data/test/mongo-qa/update +18 -0
  65. data/{tests → test}/test_admin.rb +25 -16
  66. data/test/test_bson.rb +268 -0
  67. data/{tests → test}/test_byte_buffer.rb +0 -0
  68. data/test/test_chunk.rb +84 -0
  69. data/test/test_collection.rb +282 -0
  70. data/test/test_connection.rb +101 -0
  71. data/test/test_cursor.rb +321 -0
  72. data/test/test_db.rb +196 -0
  73. data/test/test_db_api.rb +798 -0
  74. data/{tests → test}/test_db_connection.rb +4 -3
  75. data/test/test_grid_store.rb +284 -0
  76. data/{tests → test}/test_message.rb +1 -1
  77. data/test/test_objectid.rb +105 -0
  78. data/{tests → test}/test_ordered_hash.rb +55 -0
  79. data/{tests → test}/test_round_trip.rb +13 -9
  80. data/test/test_threading.rb +37 -0
  81. metadata +74 -32
  82. data/bin/validate +0 -51
  83. data/lib/mongo/mongo.rb +0 -74
  84. data/lib/mongo/types/undefined.rb +0 -31
  85. data/tests/test_bson.rb +0 -135
  86. data/tests/test_cursor.rb +0 -66
  87. data/tests/test_db.rb +0 -51
  88. data/tests/test_db_api.rb +0 -349
  89. data/tests/test_objectid.rb +0 -88
@@ -0,0 +1,798 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ # NOTE: assumes Mongo is running
6
+ class DBAPITest < Test::Unit::TestCase
7
+ include Mongo
8
+
9
+ @@db = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
10
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT).db('ruby-mongo-test')
11
+ @@coll = @@db.collection('test')
12
+
13
+ def setup
14
+ @@coll.clear
15
+ @r1 = {'a' => 1}
16
+ @@coll.insert(@r1) # collection not created until it's used
17
+ @@coll_full_name = 'ruby-mongo-test.test'
18
+ end
19
+
20
+ def teardown
21
+ @@coll.clear
22
+ @@db.error
23
+ end
24
+
25
+ def test_clear
26
+ assert_equal 1, @@coll.count
27
+ @@coll.clear
28
+ assert_equal 0, @@coll.count
29
+ end
30
+
31
+ def test_insert
32
+ assert_kind_of ObjectID, @@coll.insert('a' => 2)
33
+ assert_kind_of ObjectID, @@coll.insert('b' => 3)
34
+
35
+ assert_equal 3, @@coll.count
36
+ docs = @@coll.find().to_a
37
+ assert_equal 3, docs.length
38
+ assert docs.detect { |row| row['a'] == 1 }
39
+ assert docs.detect { |row| row['a'] == 2 }
40
+ assert docs.detect { |row| row['b'] == 3 }
41
+
42
+ @@coll << {'b' => 4}
43
+ docs = @@coll.find().to_a
44
+ assert_equal 4, docs.length
45
+ assert docs.detect { |row| row['b'] == 4 }
46
+ end
47
+
48
+ def test_save_ordered_hash
49
+ oh = OrderedHash.new
50
+ oh['a'] = -1
51
+ oh['b'] = 'foo'
52
+
53
+ oid = @@coll.save(oh)
54
+ assert_equal 'foo', @@coll.find_one(oid)['b']
55
+
56
+ oh = OrderedHash['a' => 1, 'b' => 'foo']
57
+ oid = @@coll.save(oh)
58
+ assert_equal 'foo', @@coll.find_one(oid)['b']
59
+ end
60
+
61
+ def test_insert_multiple
62
+ ids = @@coll.insert([{'a' => 2}, {'b' => 3}])
63
+
64
+ ids.each do |i|
65
+ assert_kind_of ObjectID, i
66
+ end
67
+
68
+ assert_equal 3, @@coll.count
69
+ docs = @@coll.find().to_a
70
+ assert_equal 3, docs.length
71
+ assert docs.detect { |row| row['a'] == 1 }
72
+ assert docs.detect { |row| row['a'] == 2 }
73
+ assert docs.detect { |row| row['b'] == 3 }
74
+ end
75
+
76
+ def test_count_on_nonexisting
77
+ @@db.drop_collection('foo')
78
+ assert_equal 0, @@db.collection('foo').count()
79
+ end
80
+
81
+ def test_find_simple
82
+ @r2 = @@coll.insert('a' => 2)
83
+ @r3 = @@coll.insert('b' => 3)
84
+ # Check sizes
85
+ docs = @@coll.find().to_a
86
+ assert_equal 3, docs.size
87
+ assert_equal 3, @@coll.count
88
+
89
+ # Find by other value
90
+ docs = @@coll.find('a' => @r1['a']).to_a
91
+ assert_equal 1, docs.size
92
+ doc = docs.first
93
+ # Can't compare _id values because at insert, an _id was added to @r1 by
94
+ # the database but we don't know what it is without re-reading the record
95
+ # (which is what we are doing right now).
96
+ # assert_equal doc['_id'], @r1['_id']
97
+ assert_equal doc['a'], @r1['a']
98
+ end
99
+
100
+ def test_find_advanced
101
+ @@coll.insert('a' => 2)
102
+ @@coll.insert('b' => 3)
103
+
104
+ # Find by advanced query (less than)
105
+ docs = @@coll.find('a' => { '$lt' => 10 }).to_a
106
+ assert_equal 2, docs.size
107
+ assert docs.detect { |row| row['a'] == 1 }
108
+ assert docs.detect { |row| row['a'] == 2 }
109
+
110
+ # Find by advanced query (greater than)
111
+ docs = @@coll.find('a' => { '$gt' => 1 }).to_a
112
+ assert_equal 1, docs.size
113
+ assert docs.detect { |row| row['a'] == 2 }
114
+
115
+ # Find by advanced query (less than or equal to)
116
+ docs = @@coll.find('a' => { '$lte' => 1 }).to_a
117
+ assert_equal 1, docs.size
118
+ assert docs.detect { |row| row['a'] == 1 }
119
+
120
+ # Find by advanced query (greater than or equal to)
121
+ docs = @@coll.find('a' => { '$gte' => 1 }).to_a
122
+ assert_equal 2, docs.size
123
+ assert docs.detect { |row| row['a'] == 1 }
124
+ assert docs.detect { |row| row['a'] == 2 }
125
+
126
+ # Find by advanced query (between)
127
+ docs = @@coll.find('a' => { '$gt' => 1, '$lt' => 3 }).to_a
128
+ assert_equal 1, docs.size
129
+ assert docs.detect { |row| row['a'] == 2 }
130
+
131
+ # Find by advanced query (in clause)
132
+ docs = @@coll.find('a' => {'$in' => [1,2]}).to_a
133
+ assert_equal 2, docs.size
134
+ assert docs.detect { |row| row['a'] == 1 }
135
+ assert docs.detect { |row| row['a'] == 2 }
136
+
137
+ # Find by advanced query (regexp)
138
+ docs = @@coll.find('a' => /[1|2]/).to_a
139
+ assert_equal 2, docs.size
140
+ assert docs.detect { |row| row['a'] == 1 }
141
+ assert docs.detect { |row| row['a'] == 2 }
142
+ end
143
+
144
+ def test_find_sorting
145
+ @@coll.clear
146
+ @@coll.insert('a' => 1, 'b' => 2)
147
+ @@coll.insert('a' => 2, 'b' => 1)
148
+ @@coll.insert('a' => 3, 'b' => 2)
149
+ @@coll.insert('a' => 4, 'b' => 1)
150
+
151
+ # Sorting (ascending)
152
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => {'a' => 1}).to_a
153
+ assert_equal 4, docs.size
154
+ assert_equal 1, docs[0]['a']
155
+ assert_equal 2, docs[1]['a']
156
+ assert_equal 3, docs[2]['a']
157
+ assert_equal 4, docs[3]['a']
158
+
159
+ # Sorting (descending)
160
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => {'a' => -1}).to_a
161
+ assert_equal 4, docs.size
162
+ assert_equal 4, docs[0]['a']
163
+ assert_equal 3, docs[1]['a']
164
+ assert_equal 2, docs[2]['a']
165
+ assert_equal 1, docs[3]['a']
166
+
167
+ # Sorting using array of names; assumes ascending order.
168
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => ['a']).to_a
169
+ assert_equal 4, docs.size
170
+ assert_equal 1, docs[0]['a']
171
+ assert_equal 2, docs[1]['a']
172
+ assert_equal 3, docs[2]['a']
173
+ assert_equal 4, docs[3]['a']
174
+
175
+ # Sorting using single name; assumes ascending order.
176
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => 'a').to_a
177
+ assert_equal 4, docs.size
178
+ assert_equal 1, docs[0]['a']
179
+ assert_equal 2, docs[1]['a']
180
+ assert_equal 3, docs[2]['a']
181
+ assert_equal 4, docs[3]['a']
182
+
183
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => ['b', 'a']).to_a
184
+ assert_equal 4, docs.size
185
+ assert_equal 2, docs[0]['a']
186
+ assert_equal 4, docs[1]['a']
187
+ assert_equal 1, docs[2]['a']
188
+ assert_equal 3, docs[3]['a']
189
+
190
+ # Sorting using empty array; no order guarantee (Mongo bug #898) but
191
+ # should not blow up.
192
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => []).to_a
193
+ assert_equal 4, docs.size
194
+
195
+ # Sorting using array of hashes; no order guarantee (Mongo bug #898) but
196
+ # should not blow up.
197
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => [{'b' => 1}, {'a' => -1}]).to_a
198
+ assert_equal 4, docs.size
199
+
200
+ # Sorting using ordered hash. You can use an unordered one, but then the
201
+ # order of the keys won't be guaranteed thus your sort won't make sense.
202
+ oh = OrderedHash.new
203
+ oh['a'] = -1
204
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
205
+ assert_equal 4, docs.size
206
+ assert_equal 4, docs[0]['a']
207
+ assert_equal 3, docs[1]['a']
208
+ assert_equal 2, docs[2]['a']
209
+ assert_equal 1, docs[3]['a']
210
+
211
+ # TODO this will not pass due to known Mongo bug #898
212
+ # oh = OrderedHash.new
213
+ # oh['b'] = -1
214
+ # oh['a'] = 1
215
+ # docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
216
+ # assert_equal 4, docs.size
217
+ # assert_equal 1, docs[0]['a']
218
+ # assert_equal 3, docs[1]['a']
219
+ # assert_equal 2, docs[2]['a']
220
+ # assert_equal 4, docs[3]['a']
221
+ end
222
+
223
+ def test_find_limits
224
+ @@coll.insert('b' => 2)
225
+ @@coll.insert('c' => 3)
226
+ @@coll.insert('d' => 4)
227
+
228
+ docs = @@coll.find({}, :limit => 1).to_a
229
+ assert_equal 1, docs.size
230
+ docs = @@coll.find({}, :limit => 2).to_a
231
+ assert_equal 2, docs.size
232
+ docs = @@coll.find({}, :limit => 3).to_a
233
+ assert_equal 3, docs.size
234
+ docs = @@coll.find({}, :limit => 4).to_a
235
+ assert_equal 4, docs.size
236
+ docs = @@coll.find({}).to_a
237
+ assert_equal 4, docs.size
238
+ docs = @@coll.find({}, :limit => 99).to_a
239
+ assert_equal 4, docs.size
240
+ end
241
+
242
+ def test_find_one_no_records
243
+ @@coll.clear
244
+ x = @@coll.find_one('a' => 1)
245
+ assert_nil x
246
+ end
247
+
248
+ def test_drop_collection
249
+ assert @@db.drop_collection(@@coll.name), "drop of collection #{@@coll.name} failed"
250
+ assert !@@db.collection_names.include?(@@coll.name)
251
+ end
252
+
253
+ def test_other_drop
254
+ assert @@db.collection_names.include?(@@coll.name)
255
+ @@coll.drop
256
+ assert !@@db.collection_names.include?(@@coll.name)
257
+ end
258
+
259
+ def test_collection_names
260
+ names = @@db.collection_names
261
+ assert names.length >= 1
262
+ assert names.include?(@@coll.name)
263
+
264
+ coll2 = @@db.collection('test2')
265
+ coll2.insert('a' => 1) # collection not created until it's used
266
+ names = @@db.collection_names
267
+ assert names.length >= 2
268
+ assert names.include?(@@coll.name)
269
+ assert names.include?('ruby-mongo-test.test2')
270
+ ensure
271
+ @@db.drop_collection('test2')
272
+ end
273
+
274
+ def test_collections_info
275
+ cursor = @@db.collections_info
276
+ rows = cursor.to_a
277
+ assert rows.length >= 1
278
+ row = rows.detect { |r| r['name'] == @@coll_full_name }
279
+ assert_not_nil row
280
+ end
281
+
282
+ def test_collection_options
283
+ @@db.drop_collection('foobar')
284
+ @@db.strict = true
285
+
286
+ begin
287
+ coll = @@db.create_collection('foobar', :capped => true, :size => 1024)
288
+ options = coll.options()
289
+ assert_equal 'foobar', options['create']
290
+ assert_equal true, options['capped']
291
+ assert_equal 1024, options['size']
292
+ rescue => ex
293
+ @@db.drop_collection('foobar')
294
+ fail "did not expect exception \"#{ex}\""
295
+ ensure
296
+ @@db.strict = false
297
+ end
298
+ end
299
+
300
+ def test_index_information
301
+ assert_equal @@coll.index_information.length, 1
302
+
303
+ name = @@db.create_index(@@coll.name, 'a')
304
+ info = @@db.index_information(@@coll.name)
305
+ assert_equal name, "a_1"
306
+ assert_equal @@coll.index_information, info
307
+ assert_equal 2, info.length
308
+
309
+ assert info.has_key?(name)
310
+ assert_equal info[name], [["a", ASCENDING]]
311
+ ensure
312
+ @@db.drop_index(@@coll.name, name)
313
+ end
314
+
315
+ def test_index_create_with_symbol
316
+ assert_equal @@coll.index_information.length, 1
317
+
318
+ name = @@db.create_index(@@coll.name, :a)
319
+ info = @@db.index_information(@@coll.name)
320
+ assert_equal name, "a_1"
321
+ assert_equal @@coll.index_information, info
322
+ assert_equal 2, info.length
323
+
324
+ assert info.has_key?(name)
325
+ assert_equal info[name], [["a", ASCENDING]]
326
+ ensure
327
+ @@db.drop_index(@@coll.name, name)
328
+ end
329
+
330
+ def test_multiple_index_cols
331
+ name = @@db.create_index(@@coll.name, [['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]])
332
+ info = @@db.index_information(@@coll.name)
333
+ assert_equal 2, info.length
334
+
335
+ assert_equal name, 'a_-1_b_1_c_-1'
336
+ assert info.has_key?(name)
337
+ assert_equal [['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]], info[name]
338
+ ensure
339
+ @@db.drop_index(@@coll.name, name)
340
+ end
341
+
342
+ def test_multiple_index_cols_with_symbols
343
+ name = @@db.create_index(@@coll.name, [[:a, DESCENDING], [:b, ASCENDING], [:c, DESCENDING]])
344
+ info = @@db.index_information(@@coll.name)
345
+ assert_equal 2, info.length
346
+
347
+ assert_equal name, 'a_-1_b_1_c_-1'
348
+ assert info.has_key?(name)
349
+ assert_equal [['a', DESCENDING], ['b', ASCENDING], ['c', DESCENDING]], info[name]
350
+ ensure
351
+ @@db.drop_index(@@coll.name, name)
352
+ end
353
+
354
+ def test_unique_index
355
+ @@db.drop_collection("blah")
356
+ test = @@db.collection("blah")
357
+ test.create_index("hello")
358
+
359
+ test.insert("hello" => "world")
360
+ test.insert("hello" => "mike")
361
+ test.insert("hello" => "world")
362
+ assert !@@db.error?
363
+
364
+ @@db.drop_collection("blah")
365
+ test = @@db.collection("blah")
366
+ test.create_index("hello", unique=true)
367
+
368
+ test.insert("hello" => "world")
369
+ test.insert("hello" => "mike")
370
+ test.insert("hello" => "world")
371
+ assert @@db.error?
372
+ end
373
+
374
+ def test_index_on_subfield
375
+ @@db.drop_collection("blah")
376
+ test = @@db.collection("blah")
377
+
378
+ test.insert("hello" => {"a" => 4, "b" => 5})
379
+ test.insert("hello" => {"a" => 7, "b" => 2})
380
+ test.insert("hello" => {"a" => 4, "b" => 10})
381
+ assert !@@db.error?
382
+
383
+ @@db.drop_collection("blah")
384
+ test = @@db.collection("blah")
385
+ test.create_index("hello.a", unique=true)
386
+
387
+ test.insert("hello" => {"a" => 4, "b" => 5})
388
+ test.insert("hello" => {"a" => 7, "b" => 2})
389
+ test.insert("hello" => {"a" => 4, "b" => 10})
390
+ assert @@db.error?
391
+ end
392
+
393
+ def test_array
394
+ @@coll << {'b' => [1, 2, 3]}
395
+ rows = @@coll.find({}, {:fields => ['b']}).to_a
396
+ assert_equal 1, rows.length
397
+ assert_equal [1, 2, 3], rows[0]['b']
398
+ end
399
+
400
+ def test_regex
401
+ regex = /foobar/i
402
+ @@coll << {'b' => regex}
403
+ rows = @@coll.find({}, {:fields => ['b']}).to_a
404
+ assert_equal 1, rows.length
405
+ assert_equal regex, rows[0]['b']
406
+ end
407
+
408
+ def test_non_oid_id
409
+ # Note: can't use Time.new because that will include fractional seconds,
410
+ # which Mongo does not store.
411
+ t = Time.at(1234567890)
412
+ @@coll << {'_id' => t}
413
+ rows = @@coll.find({'_id' => t}).to_a
414
+ assert_equal 1, rows.length
415
+ assert_equal t, rows[0]['_id']
416
+ end
417
+
418
+ def test_strict
419
+ assert !@@db.strict?
420
+ @@db.strict = true
421
+ assert @@db.strict?
422
+ ensure
423
+ @@db.strict = false
424
+ end
425
+
426
+ def test_strict_access_collection
427
+ @@db.strict = true
428
+ begin
429
+ @@db.collection('does-not-exist')
430
+ fail "expected exception"
431
+ rescue => ex
432
+ assert_equal "Collection does-not-exist doesn't exist. Currently in strict mode.", ex.to_s
433
+ ensure
434
+ @@db.strict = false
435
+ @@db.drop_collection('does-not-exist')
436
+ end
437
+ end
438
+
439
+ def test_strict_create_collection
440
+ @@db.drop_collection('foobar')
441
+ @@db.strict = true
442
+
443
+ begin
444
+ @@db.create_collection('foobar')
445
+ assert true
446
+ rescue => ex
447
+ fail "did not expect exception \"#{ex}\""
448
+ end
449
+
450
+ # Now the collection exists. This time we should see an exception.
451
+ begin
452
+ @@db.create_collection('foobar')
453
+ fail "expected exception"
454
+ rescue => ex
455
+ assert_equal "Collection foobar already exists. Currently in strict mode.", ex.to_s
456
+ ensure
457
+ @@db.strict = false
458
+ @@db.drop_collection('foobar')
459
+ end
460
+
461
+ # Now we're not in strict mode - should succeed
462
+ @@db.create_collection('foobar')
463
+ @@db.create_collection('foobar')
464
+ @@db.drop_collection('foobar')
465
+ end
466
+
467
+ def test_to_a
468
+ cursor = @@coll.find()
469
+ rows = cursor.to_a
470
+
471
+ assert_raise InvalidOperation do
472
+ cursor.to_a
473
+ end
474
+
475
+ cursor.each { |doc| fail "should be no docs in each now" }
476
+ end
477
+
478
+ def test_to_a_after_each
479
+ cursor = @@coll.find
480
+ cursor.each { |row| row }
481
+ assert_raise InvalidOperation do
482
+ cursor.to_a
483
+ end
484
+ end
485
+
486
+ def test_ismaster
487
+ assert @@db.master?
488
+ end
489
+
490
+ def test_master
491
+ assert_equal "#{@@db.host}:#{@@db.port}", @@db.master
492
+ end
493
+
494
+ def test_where
495
+ @@coll.insert('a' => 2)
496
+ @@coll.insert('a' => 3)
497
+
498
+ assert_equal 3, @@coll.count
499
+ assert_equal 1, @@coll.find('$where' => Code.new('this.a > 2')).count()
500
+ assert_equal 2, @@coll.find('$where' => Code.new('this.a > i', {'i' => 1})).count()
501
+ end
502
+
503
+ def test_eval
504
+ assert_equal 3, @@db.eval('function (x) {return x;}', 3)
505
+
506
+ assert_equal nil, @@db.eval("function (x) {db.test_eval.save({y:x});}", 5)
507
+ assert_equal 5, @@db.collection('test_eval').find_one['y']
508
+
509
+ assert_equal 5, @@db.eval("function (x, y) {return x + y;}", 2, 3)
510
+ assert_equal 5, @@db.eval("function () {return 5;}")
511
+ assert_equal 5, @@db.eval("2 + 3;")
512
+
513
+ assert_equal 5, @@db.eval(Code.new("2 + 3;"))
514
+ assert_equal 2, @@db.eval(Code.new("return i;", {"i" => 2}))
515
+ assert_equal 5, @@db.eval(Code.new("i + 3;", {"i" => 2}))
516
+
517
+ assert_raise OperationFailure do
518
+ @@db.eval("5 ++ 5;")
519
+ end
520
+ end
521
+
522
+ def test_hint
523
+ name = @@coll.create_index('a')
524
+ begin
525
+ assert_nil @@coll.hint
526
+ assert_equal 1, @@coll.find({'a' => 1}, :hint => 'a').to_a.size
527
+ assert_equal 1, @@coll.find({'a' => 1}, :hint => ['a']).to_a.size
528
+ assert_equal 1, @@coll.find({'a' => 1}, :hint => {'a' => 1}).to_a.size
529
+
530
+ @@coll.hint = 'a'
531
+ assert_equal({'a' => 1}, @@coll.hint)
532
+ assert_equal 1, @@coll.find('a' => 1).to_a.size
533
+
534
+ @@coll.hint = ['a']
535
+ assert_equal({'a' => 1}, @@coll.hint)
536
+ assert_equal 1, @@coll.find('a' => 1).to_a.size
537
+
538
+ @@coll.hint = {'a' => 1}
539
+ assert_equal({'a' => 1}, @@coll.hint)
540
+ assert_equal 1, @@coll.find('a' => 1).to_a.size
541
+
542
+ @@coll.hint = nil
543
+ assert_nil @@coll.hint
544
+ assert_equal 1, @@coll.find('a' => 1).to_a.size
545
+ ensure
546
+ @@coll.drop_index(name)
547
+ end
548
+ end
549
+
550
+ def test_hash_default_value_id
551
+ val = Hash.new(0)
552
+ val["x"] = 5
553
+ @@coll.insert val
554
+ id = @@coll.find_one("x" => 5)["_id"]
555
+ assert id != 0
556
+ end
557
+
558
+ def test_group
559
+ @@db.drop_collection("test")
560
+ test = @@db.collection("test")
561
+
562
+ assert_equal [], test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")
563
+ assert_equal [], test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)
564
+
565
+ test.insert("a" => 2)
566
+ test.insert("b" => 5)
567
+ test.insert("a" => 1)
568
+
569
+ assert_equal 3, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
570
+ assert_equal 3, test.group([], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)[0]["count"]
571
+ assert_equal 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }")[0]["count"]
572
+ assert_equal 1, test.group([], {"a" => {"$gt" => 1}}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)[0]["count"]
573
+
574
+ test.insert("a" => 2, "b" => 3)
575
+ expected = [{"a" => 2, "count" => 2},
576
+ {"a" => nil, "count" => 1},
577
+ {"a" => 1, "count" => 1}]
578
+ assert_equal expected, test.group(["a"], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }")
579
+ assert_equal expected, test.group(["a"], {}, {"count" => 0}, "function (obj, prev) { prev.count++; }", true)
580
+
581
+ assert_raise OperationFailure do
582
+ test.group([], {}, {}, "5 ++ 5")
583
+ end
584
+ assert_raise OperationFailure do
585
+ test.group([], {}, {}, "5 ++ 5", true)
586
+ end
587
+ end
588
+
589
+ def test_deref
590
+ @@coll.clear
591
+
592
+ assert_equal nil, @@db.dereference(DBRef.new("test", ObjectID.new))
593
+ @@coll.insert({"x" => "hello"})
594
+ key = @@coll.find_one()["_id"]
595
+ assert_equal "hello", @@db.dereference(DBRef.new("test", key))["x"]
596
+
597
+ assert_equal nil, @@db.dereference(DBRef.new("test", 4))
598
+ obj = {"_id" => 4}
599
+ @@coll.insert(obj)
600
+ assert_equal obj, @@db.dereference(DBRef.new("test", 4))
601
+
602
+ @@coll.clear
603
+ @@coll.insert({"x" => "hello"})
604
+ assert_equal nil, @@db.dereference(DBRef.new("test", nil))
605
+ end
606
+
607
+ def test_save
608
+ @@coll.clear
609
+
610
+ a = {"hello" => "world"}
611
+
612
+ id = @@coll.save(a)
613
+ assert_kind_of ObjectID, id
614
+ assert_equal 1, @@coll.count
615
+
616
+ assert_equal id, @@coll.save(a)
617
+ assert_equal 1, @@coll.count
618
+
619
+ assert_equal "world", @@coll.find_one()["hello"]
620
+
621
+ a["hello"] = "mike"
622
+ @@coll.save(a)
623
+ assert_equal 1, @@coll.count
624
+
625
+ assert_equal "mike", @@coll.find_one()["hello"]
626
+
627
+ @@coll.save({"hello" => "world"})
628
+ assert_equal 2, @@coll.count
629
+ end
630
+
631
+ def test_save_long
632
+ @@coll.clear
633
+ @@coll.insert("x" => 9223372036854775807)
634
+ assert_equal 9223372036854775807, @@coll.find_one()["x"]
635
+ end
636
+
637
+ def test_find_by_oid
638
+ @@coll.clear
639
+
640
+ @@coll.save("hello" => "mike")
641
+ id = @@coll.save("hello" => "world")
642
+ assert_kind_of ObjectID, id
643
+
644
+ assert_equal "world", @@coll.find_one(:_id => id)["hello"]
645
+ @@coll.find(:_id => id).to_a.each do |doc|
646
+ assert_equal "world", doc["hello"]
647
+ end
648
+
649
+ id = ObjectID.from_string(id.to_s)
650
+ assert_equal "world", @@coll.find_one(:_id => id)["hello"]
651
+ end
652
+
653
+ def test_save_with_object_that_has_id_but_does_not_actually_exist_in_collection
654
+ @@coll.clear
655
+
656
+ a = {'_id' => '1', 'hello' => 'world'}
657
+ @@coll.save(a)
658
+ assert_equal(1, @@coll.count)
659
+ assert_equal("world", @@coll.find_one()["hello"])
660
+
661
+ a["hello"] = "mike"
662
+ @@coll.save(a)
663
+ assert_equal(1, @@coll.count)
664
+ assert_equal("mike", @@coll.find_one()["hello"])
665
+ end
666
+
667
+ def test_invalid_key_names
668
+ @@coll.clear
669
+
670
+ @@coll.insert({"hello" => "world"})
671
+ @@coll.insert({"hello" => {"hello" => "world"}})
672
+
673
+ assert_raise InvalidName do
674
+ @@coll.insert({"$hello" => "world"})
675
+ end
676
+ assert_raise InvalidName do
677
+ @@coll.insert({"hello" => {"$hello" => "world"}})
678
+ end
679
+
680
+ @@coll.insert({"he$llo" => "world"})
681
+ @@coll.insert({"hello" => {"hell$o" => "world"}})
682
+
683
+ assert_raise InvalidName do
684
+ @@coll.insert({".hello" => "world"})
685
+ end
686
+ assert_raise InvalidName do
687
+ @@coll.insert({"hello" => {".hello" => "world"}})
688
+ end
689
+ assert_raise InvalidName do
690
+ @@coll.insert({"hello." => "world"})
691
+ end
692
+ assert_raise InvalidName do
693
+ @@coll.insert({"hello" => {"hello." => "world"}})
694
+ end
695
+ assert_raise InvalidName do
696
+ @@coll.insert({"hel.lo" => "world"})
697
+ end
698
+ assert_raise InvalidName do
699
+ @@coll.insert({"hello" => {"hel.lo" => "world"}})
700
+ end
701
+ end
702
+
703
+ def test_collection_names
704
+ assert_raise TypeError do
705
+ @@db.collection(5)
706
+ end
707
+ assert_raise InvalidName do
708
+ @@db.collection("")
709
+ end
710
+ assert_raise InvalidName do
711
+ @@db.collection("te$t")
712
+ end
713
+ assert_raise InvalidName do
714
+ @@db.collection(".test")
715
+ end
716
+ assert_raise InvalidName do
717
+ @@db.collection("test.")
718
+ end
719
+ assert_raise InvalidName do
720
+ @@db.collection("tes..t")
721
+ end
722
+ end
723
+
724
+ def test_rename_collection
725
+ @@db.drop_collection("foo")
726
+ @@db.drop_collection("bar")
727
+ a = @@db.collection("foo")
728
+ b = @@db.collection("bar")
729
+
730
+ assert_raise TypeError do
731
+ a.rename(5)
732
+ end
733
+ assert_raise InvalidName do
734
+ a.rename("")
735
+ end
736
+ assert_raise InvalidName do
737
+ a.rename("te$t")
738
+ end
739
+ assert_raise InvalidName do
740
+ a.rename(".test")
741
+ end
742
+ assert_raise InvalidName do
743
+ a.rename("test.")
744
+ end
745
+ assert_raise InvalidName do
746
+ a.rename("tes..t")
747
+ end
748
+
749
+ assert_equal 0, a.count()
750
+ assert_equal 0, b.count()
751
+
752
+ a.insert("x" => 1)
753
+ a.insert("x" => 2)
754
+
755
+ assert_equal 2, a.count()
756
+
757
+ a.rename("bar")
758
+
759
+ assert_equal 0, a.count()
760
+ assert_equal 2, b.count()
761
+
762
+ assert_equal 1, b.find().to_a()[0]["x"]
763
+ assert_equal 2, b.find().to_a()[1]["x"]
764
+
765
+ b.rename(:foo)
766
+
767
+ assert_equal 2, a.count()
768
+ assert_equal 0, b.count()
769
+ end
770
+
771
+ # doesn't really test functionality, just that the option is set correctly
772
+ def test_snapshot
773
+ @@db.collection("test").find({}, :snapshot => true).to_a
774
+ assert_raise RuntimeError do
775
+ @@db.collection("test").find({}, :snapshot => true, :sort => 'a').to_a
776
+ end
777
+ end
778
+
779
+ def test_encodings
780
+ if RUBY_VERSION >= '1.9'
781
+ ascii = "hello world"
782
+ utf8 = "hello world".encode("UTF-8")
783
+ iso8859 = "hello world".encode("ISO-8859-1")
784
+
785
+ assert_equal "US-ASCII", ascii.encoding.name
786
+ assert_equal "UTF-8", utf8.encoding.name
787
+ assert_equal "ISO-8859-1", iso8859.encoding.name
788
+
789
+ @@coll.clear
790
+ @@coll.save("ascii" => ascii, "utf8" => utf8, "iso8859" => iso8859)
791
+ doc = @@coll.find_one()
792
+
793
+ assert_equal "UTF-8", doc["ascii"].encoding.name
794
+ assert_equal "UTF-8", doc["utf8"].encoding.name
795
+ assert_equal "UTF-8", doc["iso8859"].encoding.name
796
+ end
797
+ end
798
+ end