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,321 @@
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 CursorTest < Test::Unit::TestCase
7
+
8
+ include Mongo
9
+
10
+ @@db = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
11
+ ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT).db('ruby-mongo-test')
12
+ @@coll = @@db.collection('test')
13
+
14
+ def setup
15
+ @@coll.clear
16
+ @@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
22
+ @@db.error
23
+ end
24
+
25
+ def test_explain
26
+ cursor = @@coll.find('a' => 1)
27
+ explaination = cursor.explain
28
+ assert_not_nil explaination['cursor']
29
+ assert_kind_of Numeric, explaination['n']
30
+ assert_kind_of Numeric, explaination['millis']
31
+ assert_kind_of Numeric, explaination['nscanned']
32
+ end
33
+
34
+ def test_count
35
+ @@coll.clear
36
+
37
+ assert_equal 0, @@coll.find().count()
38
+
39
+ 10.times do |i|
40
+ @@coll.save("x" => i)
41
+ end
42
+
43
+ assert_equal 10, @@coll.find().count()
44
+ assert_kind_of Integer, @@coll.find().count()
45
+ assert_equal 10, @@coll.find({}, :limit => 5).count()
46
+ assert_equal 10, @@coll.find({}, :skip => 5).count()
47
+
48
+ assert_equal 1, @@coll.find({"x" => 1}).count()
49
+ assert_equal 5, @@coll.find({"x" => {"$lt" => 5}}).count()
50
+
51
+ a = @@coll.find()
52
+ b = a.count()
53
+ a.each do |doc|
54
+ break
55
+ end
56
+ assert_equal b, a.count()
57
+
58
+ assert_equal 0, @@db['acollectionthatdoesn'].count()
59
+ end
60
+
61
+ def test_sort
62
+ @@coll.clear
63
+ 5.times{|x| @@coll.insert({"a" => x}) }
64
+
65
+ assert_kind_of Cursor, @@coll.find().sort({:a => 1})
66
+
67
+ assert_equal 0, @@coll.find().sort({:a => 1}).next_object["a"]
68
+ assert_equal 4, @@coll.find().sort({:a => -1}).next_object["a"]
69
+ assert_equal 0, @@coll.find().sort(["a"]).next_object["a"]
70
+
71
+ assert_kind_of Cursor, @@coll.find().sort({:a => -1, :b => 1})
72
+
73
+ assert_equal 4, @@coll.find().sort({:a => 1}).sort({:a => -1}).next_object["a"]
74
+ assert_equal 0, @@coll.find().sort({:a => -1}).sort({:a => 1}).next_object["a"]
75
+
76
+ cursor = @@coll.find()
77
+ cursor.next_object()
78
+ assert_raise InvalidOperation do
79
+ cursor.sort(["a"])
80
+ end
81
+ end
82
+
83
+ def test_limit
84
+ @@coll.clear
85
+
86
+ 10.times do |i|
87
+ @@coll.save("x" => i)
88
+ end
89
+ assert_equal 10, @@coll.find().count()
90
+
91
+ results = @@coll.find().limit(5).to_a
92
+ assert_equal 5, results.length
93
+ end
94
+
95
+ def test_limit_exceptions
96
+ assert_raise ArgumentError do
97
+ cursor = @@coll.find().limit('not-an-integer')
98
+ end
99
+
100
+ cursor = @@coll.find()
101
+ firstResult = cursor.next_object()
102
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
103
+ cursor.limit(1)
104
+ end
105
+
106
+ cursor = @@coll.find()
107
+ cursor.close
108
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
109
+ cursor.limit(1)
110
+ end
111
+ end
112
+
113
+ def test_skip
114
+ @@coll.clear
115
+
116
+ 10.times do |i|
117
+ @@coll.save("x" => i)
118
+ end
119
+ assert_equal 10, @@coll.find().count()
120
+
121
+ all_results = @@coll.find().to_a
122
+ skip_results = @@coll.find().skip(2).to_a
123
+ assert_equal 10, all_results.length
124
+ assert_equal 8, skip_results.length
125
+
126
+ assert_equal all_results.slice(2...10), skip_results
127
+ end
128
+
129
+ def test_skip_exceptions
130
+ assert_raise ArgumentError do
131
+ cursor = @@coll.find().skip('not-an-integer')
132
+ end
133
+
134
+ cursor = @@coll.find()
135
+ firstResult = cursor.next_object()
136
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
137
+ cursor.skip(1)
138
+ end
139
+
140
+ cursor = @@coll.find()
141
+ cursor.close
142
+ assert_raise InvalidOperation, "Cannot modify the query once it has been run or closed." do
143
+ cursor.skip(1)
144
+ end
145
+ end
146
+
147
+ def test_limit_skip_chaining
148
+ @@coll.clear
149
+ 10.times do |i|
150
+ @@coll.save("x" => i)
151
+ end
152
+
153
+ all_results = @@coll.find().to_a
154
+ limited_skip_results = @@coll.find().limit(5).skip(3).to_a
155
+
156
+ assert_equal all_results.slice(3...8), limited_skip_results
157
+ end
158
+
159
+ def test_close_no_query_sent
160
+ begin
161
+ cursor = @@coll.find('a' => 1)
162
+ cursor.close
163
+ assert cursor.closed?
164
+ rescue => ex
165
+ fail ex.to_s
166
+ end
167
+ end
168
+
169
+ def test_refill_via_get_more
170
+ assert_equal 1, @@coll.count
171
+ 1000.times { |i|
172
+ assert_equal 1 + i, @@coll.count
173
+ @@coll.insert('a' => i)
174
+ }
175
+
176
+ assert_equal 1001, @@coll.count
177
+ count = 0
178
+ @@coll.find.each { |obj|
179
+ count += obj['a']
180
+ }
181
+ assert_equal 1001, @@coll.count
182
+
183
+ # do the same thing again for debugging
184
+ assert_equal 1001, @@coll.count
185
+ count2 = 0
186
+ @@coll.find.each { |obj|
187
+ count2 += obj['a']
188
+ }
189
+ assert_equal 1001, @@coll.count
190
+
191
+ assert_equal count, count2
192
+ assert_equal 499501, count
193
+ end
194
+
195
+ def test_refill_via_get_more_alt_coll
196
+ coll = @@db.collection('test-alt-coll')
197
+ coll.clear
198
+ coll.insert('a' => 1) # collection not created until it's used
199
+ assert_equal 1, coll.count
200
+
201
+ 1000.times { |i|
202
+ assert_equal 1 + i, coll.count
203
+ coll.insert('a' => i)
204
+ }
205
+
206
+ assert_equal 1001, coll.count
207
+ count = 0
208
+ coll.find.each { |obj|
209
+ count += obj['a']
210
+ }
211
+ assert_equal 1001, coll.count
212
+
213
+ # do the same thing again for debugging
214
+ assert_equal 1001, coll.count
215
+ count2 = 0
216
+ coll.find.each { |obj|
217
+ count2 += obj['a']
218
+ }
219
+ assert_equal 1001, coll.count
220
+
221
+ assert_equal count, count2
222
+ assert_equal 499501, count
223
+ end
224
+
225
+ def test_close_after_query_sent
226
+ begin
227
+ cursor = @@coll.find('a' => 1)
228
+ cursor.next_object
229
+ cursor.close
230
+ assert cursor.closed?
231
+ rescue => ex
232
+ fail ex.to_s
233
+ end
234
+ end
235
+
236
+ def test_kill_cursors
237
+ @@coll.drop
238
+
239
+ client_cursors = @@db.db_command("cursorInfo" => 1)["clientCursors_size"]
240
+ by_location = @@db.db_command("cursorInfo" => 1)["byLocation_size"]
241
+
242
+ 10000.times do |i|
243
+ @@coll.insert("i" => i)
244
+ end
245
+
246
+ assert_equal(client_cursors,
247
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
248
+ assert_equal(by_location,
249
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
250
+
251
+ 10.times do |i|
252
+ @@coll.find_one()
253
+ end
254
+
255
+ assert_equal(client_cursors,
256
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
257
+ assert_equal(by_location,
258
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
259
+
260
+ 10.times do |i|
261
+ a = @@coll.find()
262
+ a.next_object()
263
+ a.close()
264
+ end
265
+
266
+ assert_equal(client_cursors,
267
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
268
+ assert_equal(by_location,
269
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
270
+
271
+ a = @@coll.find()
272
+ a.next_object()
273
+
274
+ assert_not_equal(client_cursors,
275
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
276
+ assert_not_equal(by_location,
277
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
278
+
279
+ a.close()
280
+
281
+ assert_equal(client_cursors,
282
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
283
+ assert_equal(by_location,
284
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
285
+
286
+ a = @@coll.find({}, :limit => 10).next_object()
287
+
288
+ assert_equal(client_cursors,
289
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
290
+ assert_equal(by_location,
291
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
292
+
293
+ @@coll.find() do |cursor|
294
+ cursor.next_object()
295
+ end
296
+
297
+ assert_equal(client_cursors,
298
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
299
+ assert_equal(by_location,
300
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
301
+
302
+ @@coll.find() { |cursor|
303
+ cursor.next_object()
304
+ }
305
+
306
+ assert_equal(client_cursors,
307
+ @@db.db_command("cursorInfo" => 1)["clientCursors_size"])
308
+ assert_equal(by_location,
309
+ @@db.db_command("cursorInfo" => 1)["byLocation_size"])
310
+ end
311
+
312
+ def test_count_with_fields
313
+ @@coll.clear
314
+ @@coll.save("x" => 1)
315
+
316
+ @@coll.find({}, :fields => ["a"]).each do |doc|
317
+ fail "shouldn't have any results here"
318
+ end
319
+ assert_equal(0, @@coll.find({}, :fields => ["a"]).count())
320
+ end
321
+ end
@@ -0,0 +1,196 @@
1
+ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
2
+ require 'digest/md5'
3
+ require 'mongo'
4
+ require 'test/unit'
5
+
6
+ class TestPKFactory
7
+ def create_pk(row)
8
+ row['_id'] ||= Mongo::ObjectID.new
9
+ row
10
+ end
11
+ end
12
+
13
+ # NOTE: assumes Mongo is running
14
+ class DBTest < Test::Unit::TestCase
15
+
16
+ include Mongo
17
+
18
+ @@host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
19
+ @@port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
20
+ @@db = Connection.new(@@host, @@port).db('ruby-mongo-test')
21
+ @@users = @@db.collection('system.users')
22
+
23
+ def setup
24
+ @spongebob = 'spongebob'
25
+ @spongebob_password = 'squarepants'
26
+ @@users.clear
27
+ @@users.insert(:user => @spongebob, :pwd => @@db.send(:hash_password, @spongebob, @spongebob_password))
28
+ end
29
+
30
+ def teardown
31
+ @@users.clear if @@users
32
+ @@db.error
33
+ end
34
+
35
+ def test_close
36
+ @@db.close
37
+ assert !@@db.connected?
38
+ begin
39
+ @@db.collection('test').insert('a' => 1)
40
+ fail "expected 'NilClass' exception"
41
+ rescue => ex
42
+ assert_match /NilClass/, ex.to_s
43
+ ensure
44
+ @@db = Connection.new(@@host, @@port).db('ruby-mongo-test')
45
+ @@users = @@db.collection('system.users')
46
+ end
47
+ end
48
+
49
+ def test_full_coll_name
50
+ coll = @@db.collection('test')
51
+ assert_equal 'ruby-mongo-test.test', @@db.full_coll_name(coll.name)
52
+ end
53
+
54
+ def test_collection_names
55
+ @@db.collection("test").insert("foo" => 5)
56
+ @@db.collection("test.mike").insert("bar" => 0)
57
+
58
+ colls = @@db.collection_names()
59
+ assert colls.include?("test")
60
+ assert colls.include?("test.mike")
61
+ colls.each { |name|
62
+ assert !name.include?("$")
63
+ }
64
+ end
65
+
66
+ def test_collections
67
+ @@db.collection("test.durran").insert("foo" => 5)
68
+ @@db.collection("test.les").insert("bar" => 0)
69
+
70
+ colls = @@db.collections()
71
+ assert_not_nil colls.select { |coll| coll.name == "test.durran" }
72
+ assert_not_nil colls.select { |coll| coll.name == "test.les" }
73
+ assert_equal [], colls.select { |coll| coll.name == "does_not_exist" }
74
+
75
+ assert_kind_of Collection, colls[0]
76
+ end
77
+
78
+ def test_pair
79
+ @@db.close
80
+ @@users = nil
81
+ @@db = Connection.new({:left => "this-should-fail", :right => [@@host, @@port]}).db('ruby-mongo-test')
82
+ assert @@db.connected?
83
+ ensure
84
+ @@db = Connection.new(@@host, @@port).db('ruby-mongo-test') unless @@db.connected?
85
+ @@users = @@db.collection('system.users')
86
+ end
87
+
88
+ def test_pk_factory
89
+ db = Connection.new(@@host, @@port).db('ruby-mongo-test', :pk => TestPKFactory.new)
90
+ coll = db.collection('test')
91
+ coll.clear
92
+
93
+ insert_id = coll.insert('name' => 'Fred', 'age' => 42)
94
+ # new id gets added to returned object
95
+ row = coll.find_one({'name' => 'Fred'})
96
+ oid = row['_id']
97
+ assert_not_nil oid
98
+ assert_equal insert_id, oid
99
+
100
+ oid = ObjectID.new
101
+ data = {'_id' => oid, 'name' => 'Barney', 'age' => 41}
102
+ coll.insert(data)
103
+ row = coll.find_one({'name' => data['name']})
104
+ db_oid = row['_id']
105
+ assert_equal oid, db_oid
106
+ assert_equal data, row
107
+
108
+ coll.clear
109
+ end
110
+
111
+ def test_pk_factory_reset
112
+ db = Connection.new(@@host, @@port).db('ruby-mongo-test')
113
+ db.pk_factory = Object.new # first time
114
+ begin
115
+ db.pk_factory = Object.new
116
+ fail "error: expected exception"
117
+ rescue => ex
118
+ assert_match /can not change PK factory/, ex.to_s
119
+ ensure
120
+ db.close
121
+ end
122
+ end
123
+
124
+ def test_authenticate
125
+ assert !@@db.authenticate('nobody', 'nopassword')
126
+ assert !@@db.authenticate(@spongebob, 'squareliederhosen')
127
+ assert @@db.authenticate(@spongebob, @spongebob_password)
128
+ end
129
+
130
+ def test_logout
131
+ @@db.logout # only testing that we don't throw exception
132
+ end
133
+
134
+ def test_auto_connect
135
+ @@db.close
136
+ db = Connection.new(@@host, @@port, :auto_reconnect => true).db('ruby-mongo-test')
137
+ assert db.connected?
138
+ assert db.auto_reconnect?
139
+ db.close
140
+ assert !db.connected?
141
+ assert db.auto_reconnect?
142
+ db.collection('test').insert('a' => 1)
143
+ assert db.connected?
144
+ ensure
145
+ @@db = Connection.new(@@host, @@port).db('ruby-mongo-test')
146
+ @@users = @@db.collection('system.users')
147
+ end
148
+
149
+ def test_error
150
+ @@db.reset_error_history
151
+ assert_nil @@db.error
152
+ assert !@@db.error?
153
+ assert_nil @@db.previous_error
154
+
155
+ @@db.send(:db_command, :forceerror => 1)
156
+ assert @@db.error?
157
+ assert_not_nil @@db.error
158
+ assert_not_nil @@db.previous_error
159
+
160
+ @@db.send(:db_command, :forceerror => 1)
161
+ assert @@db.error?
162
+ assert @@db.error
163
+ prev_error = @@db.previous_error
164
+ assert_equal 1, prev_error['nPrev']
165
+ assert_equal prev_error["err"], @@db.error
166
+
167
+ @@db.collection('test').find_one
168
+ assert_nil @@db.error
169
+ assert !@@db.error?
170
+ assert @@db.previous_error
171
+ assert_equal 2, @@db.previous_error['nPrev']
172
+
173
+ @@db.reset_error_history
174
+ assert_nil @@db.error
175
+ assert !@@db.error?
176
+ assert_nil @@db.previous_error
177
+ end
178
+
179
+ def test_last_status
180
+ @@db['test'].clear
181
+ @@db['test'].save("i" => 1)
182
+
183
+ @@db['test'].update({"i" => 1}, {"$set" => {"i" => 2}})
184
+ assert @@db.last_status()["updatedExisting"]
185
+
186
+ @@db['test'].update({"i" => 1}, {"$set" => {"i" => 500}})
187
+ assert !@@db.last_status()["updatedExisting"]
188
+ end
189
+
190
+ def test_text_port_number
191
+ db = DB.new('ruby-mongo-test', [[@@host, @@port.to_s]])
192
+ # If there is no error, all is well
193
+ db.collection('users').clear
194
+ end
195
+
196
+ end