mongo 0.1.0 → 0.15

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