mongo-find_replace 0.18.3

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