mongo 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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