mongo 0.0.1

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.
@@ -0,0 +1,54 @@
1
+ # --
2
+ # Copyright (C) 2008-2009 10gen Inc.
3
+ #
4
+ # This program is free software: you can redistribute it and/or modify it
5
+ # under the terms of the GNU Affero General Public License, version 3, as
6
+ # published by the Free Software Foundation.
7
+ #
8
+ # This program is distributed in the hope that it will be useful, but WITHOUT
9
+ # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
+ # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
11
+ # for more details.
12
+ #
13
+ # You should have received a copy of the GNU Affero General Public License
14
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
+ # ++
16
+
17
+ # A hash in which the order of keys are preserved.
18
+ class OrderedHash < Hash
19
+
20
+ attr_accessor :ordered_keys
21
+
22
+ def keys
23
+ @ordered_keys || []
24
+ end
25
+
26
+ def []=(key, value)
27
+ @ordered_keys ||= []
28
+ @ordered_keys << key unless @ordered_keys.include?(key)
29
+ super(key, value)
30
+ end
31
+
32
+ def each
33
+ @ordered_keys ||= []
34
+ @ordered_keys.each { |k| yield k, self[k] }
35
+ end
36
+
37
+ def values
38
+ collect { |k, v| v }
39
+ end
40
+
41
+ def merge(other)
42
+ oh = self.dup
43
+ oh.merge!(other)
44
+ oh
45
+ end
46
+
47
+ def merge!(other)
48
+ @ordered_keys ||= []
49
+ @ordered_keys += other.keys # unordered if not an OrderedHash
50
+ @ordered_keys.uniq!
51
+ super(other)
52
+ end
53
+
54
+ end
@@ -0,0 +1,59 @@
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 AdminTest < Test::Unit::TestCase
7
+
8
+ include XGen::Mongo::Driver
9
+
10
+ def setup
11
+ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
12
+ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
13
+ @db = Mongo.new(host, port).db('ruby-mongo-test')
14
+ # Insert some data to make sure the database itself exists.
15
+ @coll = @db.collection('test')
16
+ @coll.clear
17
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
18
+ @coll_full_name = 'ruby-mongo-test.test'
19
+ @admin = @db.admin
20
+ end
21
+
22
+ def teardown
23
+ unless @db.socket.closed?
24
+ @admin.profiling_level = :off
25
+ @coll.clear unless @coll == nil
26
+ end
27
+ end
28
+
29
+ def test_default_profiling_level
30
+ assert_equal :off, @admin.profiling_level
31
+ end
32
+
33
+ def test_change_profiling_level
34
+ @admin.profiling_level = :slow_only
35
+ assert_equal :slow_only, @admin.profiling_level
36
+ @admin.profiling_level = :off
37
+ assert_equal :off, @admin.profiling_level
38
+ end
39
+
40
+ def test_profiling_info
41
+ # Perform at least one query while profiling so we have something to see.
42
+ @admin.profiling_level = :all
43
+ @coll.find()
44
+ @admin.profiling_level = :off
45
+
46
+ info = @admin.profiling_info
47
+ assert_kind_of Array, info
48
+ assert info.length >= 1
49
+ first = info.first
50
+ assert_kind_of String, first['info']
51
+ assert_kind_of Time, first['ts']
52
+ assert_kind_of Numeric, first['millis']
53
+ end
54
+
55
+ def test_validate_collection
56
+ assert @admin.validate_collection(@coll.name)
57
+ end
58
+
59
+ end
@@ -0,0 +1,79 @@
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 BSONTest < Test::Unit::TestCase
7
+
8
+ include XGen::Mongo::Driver
9
+
10
+ def setup
11
+ @b = BSON.new
12
+ end
13
+
14
+ def test_string
15
+ doc = {'doc' => 'hello, world'}
16
+ @b.serialize(doc)
17
+ assert_equal doc, @b.deserialize
18
+ end
19
+
20
+ def test_code
21
+ doc = {'$where' => 'this.a.b < this.b'}
22
+ @b.serialize(doc)
23
+ assert_equal doc, @b.deserialize
24
+ end
25
+
26
+ def test_number
27
+ doc = {'doc' => 41.99}
28
+ @b.serialize(doc)
29
+ assert_equal doc, @b.deserialize
30
+ end
31
+
32
+ def test_int
33
+ doc = {'doc' => 42}
34
+ @b.serialize(doc)
35
+ assert_equal doc, @b.deserialize
36
+ end
37
+
38
+ def test_object
39
+ doc = {'doc' => {'age' => 42, 'name' => 'Spongebob', 'shoe_size' => 9.5}}
40
+ @b.serialize(doc)
41
+ assert_equal doc, @b.deserialize
42
+ end
43
+
44
+ def test_oid
45
+ doc = {'doc' => ObjectID.new}
46
+ @b.serialize(doc)
47
+ assert_equal doc, @b.deserialize
48
+ end
49
+
50
+ def test_array
51
+ doc = {'doc' => [1, 2, 'a', 'b']}
52
+ @b.serialize(doc)
53
+ assert_equal doc, @b.deserialize
54
+ end
55
+
56
+ def test_regex
57
+ doc = {'doc' => /foobar/i}
58
+ @b.serialize(doc)
59
+ assert_equal doc, @b.deserialize
60
+ end
61
+
62
+ def test_boolean
63
+ doc = {'doc' => true}
64
+ @b.serialize(doc)
65
+ assert_equal doc, @b.deserialize
66
+ end
67
+
68
+ def test_date
69
+ doc = {'date' => Time.now}
70
+ @b.serialize(doc)
71
+ doc2 = @b.deserialize
72
+ # Mongo only stores seconds, so comparing raw Time objects will fail
73
+ # because the fractional seconds will be different.
74
+ assert_equal doc['date'].to_i, doc2['date'].to_i
75
+ end
76
+
77
+ def test_null
78
+ end
79
+ end
@@ -0,0 +1,69 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'mongo'
3
+ require 'test/unit'
4
+
5
+ class ByteBufferTest < Test::Unit::TestCase
6
+
7
+ def setup
8
+ @buf = ByteBuffer.new
9
+ end
10
+
11
+ def test_nil_get_returns_one_byte
12
+ @buf.put_array([1, 2, 3, 4])
13
+ @buf.rewind
14
+ assert_equal 1, @buf.get
15
+ end
16
+
17
+ def test_one_get_returns_array_length_one
18
+ @buf.put_array([1, 2, 3, 4])
19
+ @buf.rewind
20
+ assert_equal [1], @buf.get(1)
21
+ end
22
+
23
+ def test_zero_get_returns_empty_array
24
+ @buf.put_array([1, 2, 3, 4])
25
+ @buf.rewind
26
+ assert_equal [], @buf.get(0)
27
+ end
28
+
29
+ def test_empty
30
+ assert_equal 0, @buf.length
31
+ end
32
+
33
+ def test_length
34
+ @buf.put_int 3
35
+ assert_equal 4, @buf.length
36
+ end
37
+
38
+ def test_default_order
39
+ assert_equal :little_endian, @buf.order
40
+ end
41
+
42
+ def test_long_length
43
+ @buf.put_long 1027
44
+ assert_equal 8, @buf.length
45
+ end
46
+
47
+ def test_get_long
48
+ @buf.put_long 1027
49
+ @buf.rewind
50
+ assert_equal 1027, @buf.get_long
51
+ end
52
+
53
+ def test_get_double
54
+ @buf.put_double 41.2
55
+ @buf.rewind
56
+ assert_equal 41.2, @buf.get_double
57
+ end
58
+
59
+ def test_rewrite
60
+ @buf.put_int(0)
61
+ @buf.rewind
62
+ @buf.put_int(1027)
63
+ assert_equal 4, @buf.length
64
+ @buf.rewind
65
+ assert_equal 1027, @buf.get_int
66
+ assert_equal 4, @buf.position
67
+ end
68
+
69
+ end
@@ -0,0 +1,357 @@
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
+
8
+ include XGen::Mongo::Driver
9
+
10
+ def setup
11
+ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
12
+ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Mongo::DEFAULT_PORT
13
+ @db = Mongo.new(host, port).db('ruby-mongo-test')
14
+ @coll = @db.collection('test')
15
+ @coll.clear
16
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
17
+ @coll_full_name = 'ruby-mongo-test.test'
18
+ end
19
+
20
+ def teardown
21
+ @coll.clear unless @coll == nil || @db.socket.closed?
22
+ end
23
+
24
+ def test_clear
25
+ assert_equal 1, @coll.count
26
+ @coll.clear
27
+ assert_equal 0, @coll.count
28
+ end
29
+
30
+ def test_insert
31
+ @coll.insert('a' => 2)
32
+ @coll.insert('b' => 3)
33
+
34
+ assert_equal 3, @coll.count
35
+ docs = @coll.find().to_a
36
+ assert_equal 3, docs.length
37
+ assert docs.detect { |row| row['a'] == 1 }
38
+ assert docs.detect { |row| row['a'] == 2 }
39
+ assert docs.detect { |row| row['b'] == 3 }
40
+
41
+ @coll << {'b' => 4}
42
+ docs = @coll.find().to_a
43
+ assert_equal 4, docs.length
44
+ assert docs.detect { |row| row['b'] == 4 }
45
+ end
46
+
47
+ def test_find_simple
48
+ @r2 = @coll.insert('a' => 2)
49
+ @r3 = @coll.insert('b' => 3)
50
+ # Check sizes
51
+ docs = @coll.find().to_a
52
+ assert_equal 3, docs.size
53
+ assert_equal 3, @coll.count
54
+
55
+ # Find by other value
56
+ docs = @coll.find('a' => @r1['a']).to_a
57
+ assert_equal 1, docs.size
58
+ doc = docs.first
59
+ assert_equal doc['_id'], @r1['_id']
60
+ assert_equal doc['a'], @r1['a']
61
+ end
62
+
63
+ def test_find_advanced
64
+ @coll.insert('a' => 2)
65
+ @coll.insert('b' => 3)
66
+
67
+ # Find by advanced query (less than)
68
+ docs = @coll.find('a' => { '$lt' => 10 }).to_a
69
+ assert_equal 2, docs.size
70
+ assert docs.detect { |row| row['a'] == 1 }
71
+ assert docs.detect { |row| row['a'] == 2 }
72
+
73
+ # Find by advanced query (greater than)
74
+ docs = @coll.find('a' => { '$gt' => 1 }).to_a
75
+ assert_equal 1, docs.size
76
+ assert docs.detect { |row| row['a'] == 2 }
77
+
78
+ # Find by advanced query (less than or equal to)
79
+ docs = @coll.find('a' => { '$lte' => 1 }).to_a
80
+ assert_equal 1, docs.size
81
+ assert docs.detect { |row| row['a'] == 1 }
82
+
83
+ # Find by advanced query (greater than or equal to)
84
+ docs = @coll.find('a' => { '$gte' => 1 }).to_a
85
+ assert_equal 2, docs.size
86
+ assert docs.detect { |row| row['a'] == 1 }
87
+ assert docs.detect { |row| row['a'] == 2 }
88
+
89
+ # Find by advanced query (between)
90
+ docs = @coll.find('a' => { '$gt' => 1, '$lt' => 3 }).to_a
91
+ assert_equal 1, docs.size
92
+ assert docs.detect { |row| row['a'] == 2 }
93
+
94
+ # Find by advanced query (in clause)
95
+ docs = @coll.find('a' => {'$in' => [1,2]}).to_a
96
+ assert_equal 2, docs.size
97
+ assert docs.detect { |row| row['a'] == 1 }
98
+ assert docs.detect { |row| row['a'] == 2 }
99
+
100
+ # Find by advanced query (regexp)
101
+ docs = @coll.find('a' => /[1|2]/).to_a
102
+ assert_equal 2, docs.size
103
+ assert docs.detect { |row| row['a'] == 1 }
104
+ assert docs.detect { |row| row['a'] == 2 }
105
+ end
106
+
107
+ def test_find_sorting
108
+ @coll.clear
109
+ @coll.insert('a' => 1, 'b' => 2)
110
+ @coll.insert('a' => 2, 'b' => 1)
111
+ @coll.insert('a' => 3, 'b' => 2)
112
+ @coll.insert('a' => 4, 'b' => 1)
113
+
114
+ # Sorting (ascending)
115
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => {'a' => 1}).to_a
116
+ assert_equal 4, docs.size
117
+ assert_equal 1, docs[0]['a']
118
+ assert_equal 2, docs[1]['a']
119
+ assert_equal 3, docs[2]['a']
120
+ assert_equal 4, docs[3]['a']
121
+
122
+ # Sorting (descending)
123
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => {'a' => -1}).to_a
124
+ assert_equal 4, docs.size
125
+ assert_equal 4, docs[0]['a']
126
+ assert_equal 3, docs[1]['a']
127
+ assert_equal 2, docs[2]['a']
128
+ assert_equal 1, docs[3]['a']
129
+
130
+ # Sorting using array of names; assumes ascending order.
131
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => ['a']).to_a
132
+ assert_equal 4, docs.size
133
+ assert_equal 1, docs[0]['a']
134
+ assert_equal 2, docs[1]['a']
135
+ assert_equal 3, docs[2]['a']
136
+ assert_equal 4, docs[3]['a']
137
+
138
+ # Sorting using single name; assumes ascending order.
139
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => 'a').to_a
140
+ assert_equal 4, docs.size
141
+ assert_equal 1, docs[0]['a']
142
+ assert_equal 2, docs[1]['a']
143
+ assert_equal 3, docs[2]['a']
144
+ assert_equal 4, docs[3]['a']
145
+
146
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => ['b', 'a']).to_a
147
+ assert_equal 4, docs.size
148
+ assert_equal 2, docs[0]['a']
149
+ assert_equal 4, docs[1]['a']
150
+ assert_equal 1, docs[2]['a']
151
+ assert_equal 3, docs[3]['a']
152
+
153
+ # Sorting using empty array; no order guarantee but should not blow up.
154
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => []).to_a
155
+ assert_equal 4, docs.size
156
+
157
+ # Sorting using ordered hash. You can use an unordered one, but then the
158
+ # order of the keys won't be guaranteed thus your sort won't make sense.
159
+ oh = OrderedHash.new
160
+ oh['a'] = -1
161
+ docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
162
+ assert_equal 4, docs.size
163
+ assert_equal 4, docs[0]['a']
164
+ assert_equal 3, docs[1]['a']
165
+ assert_equal 2, docs[2]['a']
166
+ assert_equal 1, docs[3]['a']
167
+
168
+ # TODO this will not pass due to known Mongo bug #898
169
+ # oh = OrderedHash.new
170
+ # oh['b'] = -1
171
+ # oh['a'] = 1
172
+ # docs = @coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
173
+ # assert_equal 4, docs.size
174
+ # assert_equal 1, docs[0]['a']
175
+ # assert_equal 3, docs[1]['a']
176
+ # assert_equal 2, docs[2]['a']
177
+ # assert_equal 4, docs[3]['a']
178
+ end
179
+
180
+ def test_find_limits
181
+ @coll.insert('b' => 2)
182
+ @coll.insert('c' => 3)
183
+ @coll.insert('d' => 4)
184
+
185
+ docs = @coll.find({}, :limit => 1).to_a
186
+ assert_equal 1, docs.size
187
+ docs = @coll.find({}, :limit => 2).to_a
188
+ assert_equal 2, docs.size
189
+ docs = @coll.find({}, :limit => 3).to_a
190
+ assert_equal 3, docs.size
191
+ docs = @coll.find({}, :limit => 4).to_a
192
+ assert_equal 4, docs.size
193
+ docs = @coll.find({}).to_a
194
+ assert_equal 4, docs.size
195
+ docs = @coll.find({}, :limit => 99).to_a
196
+ assert_equal 4, docs.size
197
+ end
198
+
199
+ def test_close
200
+ @db.close
201
+ assert @db.socket.closed?
202
+ begin
203
+ @coll.insert('a' => 1)
204
+ fail "expected IOError exception"
205
+ rescue IOError => ex
206
+ assert_match /closed stream/, ex.to_s
207
+ end
208
+ end
209
+
210
+ def test_drop_collection
211
+ assert @db.drop_collection(@coll.name), "drop of collection #{@coll.name} failed"
212
+ assert !@db.collection_names.include?(@coll_full_name)
213
+ @coll = nil
214
+ end
215
+
216
+ def test_collection_names
217
+ names = @db.collection_names
218
+ assert names.length >= 1
219
+ assert names.include?(@coll_full_name)
220
+
221
+ coll2 = @db.collection('test2')
222
+ coll2.insert('a' => 1) # collection not created until it's used
223
+ names = @db.collection_names
224
+ assert names.length >= 2
225
+ assert names.include?(@coll_full_name)
226
+ assert names.include?('ruby-mongo-test.test2')
227
+ ensure
228
+ @db.drop_collection('test2')
229
+ end
230
+
231
+ def test_collections_info
232
+ cursor = @db.collections_info
233
+ rows = cursor.to_a
234
+ assert rows.length >= 1
235
+ row = rows.detect { |r| r['name'] == @coll_full_name }
236
+ assert_not_nil row
237
+ assert_equal @coll.name, row['options']['create']
238
+ end
239
+
240
+ def test_collection_options
241
+ @db.drop_collection('foobar')
242
+ @db.strict = true
243
+
244
+ begin
245
+ coll = @db.create_collection('foobar', :capped => true, :size => 1024)
246
+ options = coll.options()
247
+ assert_equal 'foobar', options['create']
248
+ assert_equal true, options['capped']
249
+ assert_equal 1024, options['size']
250
+ rescue => ex
251
+ @db.drop_collection('foobar')
252
+ fail "did not expect exception \"#{ex}\""
253
+ end
254
+ end
255
+
256
+ def test_full_coll_name
257
+ assert_equal @coll_full_name, @db.full_coll_name(@coll.name)
258
+ end
259
+
260
+ def test_index_information
261
+ @db.create_index(@coll.name, 'index_name', ['a'])
262
+ list = @db.index_information(@coll.name)
263
+ assert_equal 1, list.length
264
+
265
+ info = list[0]
266
+ assert_equal 'index_name', info[:name]
267
+ assert_equal 1, info[:keys]['a']
268
+ end
269
+
270
+ def test_array
271
+ @coll << {'b' => [1, 2, 3]}
272
+ rows = @coll.find({}, {:fields => ['b']}).to_a
273
+ assert_equal 1, rows.length
274
+ assert_equal [1, 2, 3], rows[0]['b']
275
+ end
276
+
277
+ def test_regex
278
+ regex = /foobar/i
279
+ @coll << {'b' => regex}
280
+ rows = @coll.find({}, {:fields => ['b']}).to_a
281
+ assert_equal 1, rows.length
282
+ assert_equal regex, rows[0]['b']
283
+ end
284
+
285
+ def test_strict
286
+ assert !@db.strict?
287
+ @db.strict = true
288
+ assert @db.strict?
289
+ end
290
+
291
+ def test_strict_access_collection
292
+ @db.strict = true
293
+ begin
294
+ @db.collection('does-not-exist')
295
+ fail "expected exception"
296
+ rescue => ex
297
+ assert_equal "Collection does-not-exist doesn't exist. Currently in strict mode.", ex.to_s
298
+ ensure
299
+ @db.strict = false
300
+ @db.drop_collection('does-not-exist')
301
+ end
302
+ end
303
+
304
+ def test_strict_create_collection
305
+ @db.drop_collection('foobar')
306
+ @db.strict = true
307
+
308
+ begin
309
+ @db.create_collection('foobar')
310
+ assert true
311
+ rescue => ex
312
+ fail "did not expect exception \"#{ex}\""
313
+ end
314
+
315
+ # Now the collection exists. This time we should see an exception.
316
+ begin
317
+ @db.create_collection('foobar')
318
+ fail "expected exception"
319
+ rescue => ex
320
+ assert_equal "Collection foobar already exists. Currently in strict mode.", ex.to_s
321
+ ensure
322
+ @db.strict = false
323
+ @db.drop_collection('foobar')
324
+ end
325
+ end
326
+
327
+ def test_to_a
328
+ cursor = @coll.find()
329
+ rows = cursor.to_a
330
+
331
+ # Make sure we get back exactly the same array the next time we ask
332
+ rows2 = cursor.to_a
333
+ assert_same rows, rows2
334
+
335
+ # Make sure we can still iterate after calling to_a
336
+ rows_with_each = cursor.collect{|row| row}
337
+ assert_equal rows, rows_with_each
338
+
339
+ # Make sure we can iterate more than once after calling to_a
340
+ end
341
+
342
+ def test_to_a_after_each
343
+ cursor = @coll.find
344
+ cursor.each { |row| row }
345
+ begin
346
+ cursor.to_a
347
+ fail "expected \"can't call\" error"
348
+ rescue => ex
349
+ assert_equal "can't call Cursor#to_a after calling Cursor#each", ex.to_s
350
+ end
351
+ end
352
+
353
+ def test_ismaster
354
+ assert @db.master?
355
+ end
356
+
357
+ end