mongo-find_replace 0.18.3

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 (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