mongo-lyon 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. data/LICENSE.txt +190 -0
  2. data/README.md +344 -0
  3. data/Rakefile +202 -0
  4. data/bin/mongo_console +34 -0
  5. data/docs/1.0_UPGRADE.md +21 -0
  6. data/docs/CREDITS.md +123 -0
  7. data/docs/FAQ.md +116 -0
  8. data/docs/GridFS.md +158 -0
  9. data/docs/HISTORY.md +225 -0
  10. data/docs/REPLICA_SETS.md +72 -0
  11. data/docs/TUTORIAL.md +247 -0
  12. data/docs/WRITE_CONCERN.md +28 -0
  13. data/lib/mongo.rb +77 -0
  14. data/lib/mongo/collection.rb +872 -0
  15. data/lib/mongo/connection.rb +875 -0
  16. data/lib/mongo/cursor.rb +449 -0
  17. data/lib/mongo/db.rb +607 -0
  18. data/lib/mongo/exceptions.rb +68 -0
  19. data/lib/mongo/gridfs/grid.rb +106 -0
  20. data/lib/mongo/gridfs/grid_ext.rb +57 -0
  21. data/lib/mongo/gridfs/grid_file_system.rb +145 -0
  22. data/lib/mongo/gridfs/grid_io.rb +394 -0
  23. data/lib/mongo/gridfs/grid_io_fix.rb +38 -0
  24. data/lib/mongo/repl_set_connection.rb +342 -0
  25. data/lib/mongo/util/conversions.rb +89 -0
  26. data/lib/mongo/util/core_ext.rb +60 -0
  27. data/lib/mongo/util/pool.rb +185 -0
  28. data/lib/mongo/util/server_version.rb +71 -0
  29. data/lib/mongo/util/support.rb +82 -0
  30. data/lib/mongo/util/uri_parser.rb +181 -0
  31. data/lib/mongo/version.rb +3 -0
  32. data/mongo.gemspec +34 -0
  33. data/test/auxillary/1.4_features.rb +166 -0
  34. data/test/auxillary/authentication_test.rb +68 -0
  35. data/test/auxillary/autoreconnect_test.rb +41 -0
  36. data/test/auxillary/repl_set_auth_test.rb +58 -0
  37. data/test/auxillary/slave_connection_test.rb +36 -0
  38. data/test/auxillary/threaded_authentication_test.rb +101 -0
  39. data/test/bson/binary_test.rb +15 -0
  40. data/test/bson/bson_test.rb +614 -0
  41. data/test/bson/byte_buffer_test.rb +190 -0
  42. data/test/bson/hash_with_indifferent_access_test.rb +38 -0
  43. data/test/bson/json_test.rb +17 -0
  44. data/test/bson/object_id_test.rb +154 -0
  45. data/test/bson/ordered_hash_test.rb +197 -0
  46. data/test/collection_test.rb +893 -0
  47. data/test/connection_test.rb +303 -0
  48. data/test/conversions_test.rb +120 -0
  49. data/test/cursor_fail_test.rb +75 -0
  50. data/test/cursor_message_test.rb +43 -0
  51. data/test/cursor_test.rb +457 -0
  52. data/test/db_api_test.rb +715 -0
  53. data/test/db_connection_test.rb +15 -0
  54. data/test/db_test.rb +287 -0
  55. data/test/grid_file_system_test.rb +244 -0
  56. data/test/grid_io_test.rb +120 -0
  57. data/test/grid_test.rb +200 -0
  58. data/test/load/thin/load.rb +24 -0
  59. data/test/load/unicorn/load.rb +23 -0
  60. data/test/replica_sets/connect_test.rb +86 -0
  61. data/test/replica_sets/connection_string_test.rb +32 -0
  62. data/test/replica_sets/count_test.rb +35 -0
  63. data/test/replica_sets/insert_test.rb +53 -0
  64. data/test/replica_sets/pooled_insert_test.rb +55 -0
  65. data/test/replica_sets/query_secondaries.rb +96 -0
  66. data/test/replica_sets/query_test.rb +51 -0
  67. data/test/replica_sets/replication_ack_test.rb +66 -0
  68. data/test/replica_sets/rs_test_helper.rb +27 -0
  69. data/test/safe_test.rb +68 -0
  70. data/test/support/hash_with_indifferent_access.rb +199 -0
  71. data/test/support/keys.rb +45 -0
  72. data/test/support_test.rb +19 -0
  73. data/test/test_helper.rb +83 -0
  74. data/test/threading/threading_with_large_pool_test.rb +90 -0
  75. data/test/threading_test.rb +87 -0
  76. data/test/tools/auth_repl_set_manager.rb +14 -0
  77. data/test/tools/repl_set_manager.rb +266 -0
  78. data/test/unit/collection_test.rb +130 -0
  79. data/test/unit/connection_test.rb +98 -0
  80. data/test/unit/cursor_test.rb +99 -0
  81. data/test/unit/db_test.rb +96 -0
  82. data/test/unit/grid_test.rb +49 -0
  83. data/test/unit/pool_test.rb +9 -0
  84. data/test/unit/repl_set_connection_test.rb +72 -0
  85. data/test/unit/safe_test.rb +125 -0
  86. data/test/uri_test.rb +91 -0
  87. metadata +202 -0
@@ -0,0 +1,15 @@
1
+ require './test/test_helper'
2
+
3
+ class DBConnectionTest < Test::Unit::TestCase
4
+
5
+ include Mongo
6
+
7
+ def test_no_exceptions
8
+ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
9
+ port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
10
+ db = Connection.new(host, port).db(MONGO_TEST_DB)
11
+ coll = db.collection('test')
12
+ coll.remove
13
+ db.get_last_error
14
+ end
15
+ end
data/test/db_test.rb ADDED
@@ -0,0 +1,287 @@
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'] ||= BSON::ObjectId.new
9
+ row
10
+ end
11
+ end
12
+
13
+ class DBTest < Test::Unit::TestCase
14
+
15
+ include Mongo
16
+
17
+ @@conn = standard_connection
18
+ @@db = @@conn.db(MONGO_TEST_DB)
19
+ @@users = @@db.collection('system.users')
20
+ @@version = @@conn.server_version
21
+
22
+ def test_close
23
+ @@conn.close
24
+ assert !@@conn.connected?
25
+ begin
26
+ @@db.collection('test').insert('a' => 1)
27
+ fail "expected 'NilClass' exception"
28
+ rescue => ex
29
+ assert_match /NilClass/, ex.to_s
30
+ ensure
31
+ @@db = standard_connection.db(MONGO_TEST_DB)
32
+ @@users = @@db.collection('system.users')
33
+ end
34
+ end
35
+
36
+ def test_logger
37
+ output = StringIO.new
38
+ logger = Logger.new(output)
39
+ logger.level = Logger::DEBUG
40
+ conn = standard_connection(:logger => logger)
41
+ assert_equal logger, conn.logger
42
+
43
+ conn.logger.debug 'testing'
44
+ assert output.string.include?('testing')
45
+ end
46
+
47
+ def test_full_coll_name
48
+ coll = @@db.collection('test')
49
+ assert_equal "#{MONGO_TEST_DB}.test", @@db.full_collection_name(coll.name)
50
+ end
51
+
52
+ def test_collection_names
53
+ @@db.collection("test").insert("foo" => 5)
54
+ @@db.collection("test.mike").insert("bar" => 0)
55
+
56
+ colls = @@db.collection_names()
57
+ assert colls.include?("test")
58
+ assert colls.include?("test.mike")
59
+ colls.each { |name|
60
+ assert !name.include?("$")
61
+ }
62
+ end
63
+
64
+ def test_collections
65
+ @@db.collection("test.durran").insert("foo" => 5)
66
+ @@db.collection("test.les").insert("bar" => 0)
67
+
68
+ colls = @@db.collections()
69
+ assert_not_nil colls.select { |coll| coll.name == "test.durran" }
70
+ assert_not_nil colls.select { |coll| coll.name == "test.les" }
71
+ assert_equal [], colls.select { |coll| coll.name == "does_not_exist" }
72
+
73
+ assert_kind_of Collection, colls[0]
74
+ end
75
+
76
+ def test_pk_factory
77
+ db = standard_connection.db(MONGO_TEST_DB, :pk => TestPKFactory.new)
78
+ coll = db.collection('test')
79
+ coll.remove
80
+
81
+ insert_id = coll.insert('name' => 'Fred', 'age' => 42)
82
+ # new id gets added to returned object
83
+ row = coll.find_one({'name' => 'Fred'})
84
+ oid = row['_id']
85
+ assert_not_nil oid
86
+ assert_equal insert_id, oid
87
+
88
+ oid = BSON::ObjectId.new
89
+ data = {'_id' => oid, 'name' => 'Barney', 'age' => 41}
90
+ coll.insert(data)
91
+ row = coll.find_one({'name' => data['name']})
92
+ db_oid = row['_id']
93
+ assert_equal oid, db_oid
94
+ assert_equal data, row
95
+
96
+ coll.remove
97
+ end
98
+
99
+ def test_pk_factory_reset
100
+ conn = standard_connection
101
+ db = conn.db(MONGO_TEST_DB)
102
+ db.pk_factory = Object.new # first time
103
+ begin
104
+ db.pk_factory = Object.new
105
+ fail "error: expected exception"
106
+ rescue => ex
107
+ assert_match /Cannot change/, ex.to_s
108
+ ensure
109
+ conn.close
110
+ end
111
+ end
112
+
113
+ def test_authenticate
114
+ @@db.add_user('spongebob', 'squarepants')
115
+ assert_raise Mongo::AuthenticationError do
116
+ assert !@@db.authenticate('nobody', 'nopassword')
117
+ end
118
+ assert_raise Mongo::AuthenticationError do
119
+ assert !@@db.authenticate('spongebob' , 'squareliederhosen')
120
+ end
121
+ assert @@db.authenticate('spongebob', 'squarepants')
122
+ @@db.logout
123
+ @@db.remove_user('spongebob')
124
+ end
125
+
126
+ def test_authenticate_with_connection_uri
127
+ @@db.add_user('spongebob', 'squarepants')
128
+ assert Mongo::Connection.from_uri("mongodb://spongebob:squarepants@#{host_port}/#{@@db.name}")
129
+
130
+ assert_raise Mongo::AuthenticationError do
131
+ Mongo::Connection.from_uri("mongodb://wrong:info@#{host_port}/#{@@db.name}")
132
+ end
133
+ end
134
+
135
+ def test_logout
136
+ assert @@db.logout
137
+ end
138
+
139
+ def test_command
140
+ assert_raise OperationFailure do
141
+ @@db.command({:non_command => 1}, :check_response => true)
142
+ end
143
+
144
+ result = @@db.command({:non_command => 1}, :check_response => false)
145
+ assert !Mongo::Support.ok?(result)
146
+ end
147
+
148
+ def test_error
149
+ @@db.reset_error_history
150
+ assert_nil @@db.get_last_error['err']
151
+ assert !@@db.error?
152
+ assert_nil @@db.previous_error
153
+
154
+ @@db.command({:forceerror => 1}, :check_response => false)
155
+ assert @@db.error?
156
+ assert_not_nil @@db.get_last_error['err']
157
+ assert_not_nil @@db.previous_error
158
+
159
+ @@db.command({:forceerror => 1}, :check_response => false)
160
+ assert @@db.error?
161
+ assert @@db.get_last_error['err']
162
+ prev_error = @@db.previous_error
163
+ assert_equal 1, prev_error['nPrev']
164
+ assert_equal prev_error["err"], @@db.get_last_error['err']
165
+
166
+ @@db.collection('test').find_one
167
+ assert_nil @@db.get_last_error['err']
168
+ assert !@@db.error?
169
+ assert @@db.previous_error
170
+ assert_equal 2, @@db.previous_error['nPrev']
171
+
172
+ @@db.reset_error_history
173
+ assert_nil @@db.get_last_error['err']
174
+ assert !@@db.error?
175
+ assert_nil @@db.previous_error
176
+ end
177
+
178
+ def test_check_command_response
179
+ command = {:forceerror => 1}
180
+ assert_raise OperationFailure do
181
+ @@db.command(command)
182
+ end
183
+ end
184
+
185
+ def test_last_status
186
+ @@db['test'].remove
187
+ @@db['test'].save("i" => 1)
188
+
189
+ @@db['test'].update({"i" => 1}, {"$set" => {"i" => 2}})
190
+ assert @@db.get_last_error()["updatedExisting"]
191
+
192
+ @@db['test'].update({"i" => 1}, {"$set" => {"i" => 500}})
193
+ assert !@@db.get_last_error()["updatedExisting"]
194
+ end
195
+
196
+ def test_text_port_number_raises_no_errors
197
+ conn = standard_connection
198
+ db = conn[MONGO_TEST_DB]
199
+ db.collection('users').remove
200
+ end
201
+
202
+ def test_user_management
203
+ @@db.add_user("bob", "secret")
204
+ assert @@db.authenticate("bob", "secret")
205
+ @@db.logout
206
+ assert @@db.remove_user("bob")
207
+ assert_raise Mongo::AuthenticationError do
208
+ @@db.authenticate("bob", "secret")
209
+ end
210
+ end
211
+
212
+ def test_remove_non_existant_user
213
+ assert !@@db.remove_user("joe")
214
+ end
215
+
216
+ def test_stored_function_management
217
+ @@db.add_stored_function("sum", "function (x, y) { return x + y; }")
218
+ assert_equal @@db.eval("return sum(2,3);"), 5
219
+ assert @@db.remove_stored_function("sum")
220
+ assert_raise OperationFailure do
221
+ @@db.eval("return sum(2,3);")
222
+ end
223
+ end
224
+
225
+ def test_eval
226
+ @@db.eval("db.system.save({_id:'hello', value: function() { print('hello'); } })")
227
+ assert_equal 'hello', @@db['system'].find_one['_id']
228
+ end
229
+
230
+ if @@version >= "1.3.5"
231
+ def test_db_stats
232
+ stats = @@db.stats
233
+ assert stats.has_key?('collections')
234
+ assert stats.has_key?('dataSize')
235
+ end
236
+ end
237
+
238
+ context "database profiling" do
239
+ setup do
240
+ @db = @@conn[MONGO_TEST_DB]
241
+ @coll = @db['test']
242
+ @coll.remove
243
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
244
+ end
245
+
246
+ should "set default profiling level" do
247
+ assert_equal :off, @db.profiling_level
248
+ end
249
+
250
+ should "change profiling level" do
251
+ @db.profiling_level = :slow_only
252
+ assert_equal :slow_only, @db.profiling_level
253
+ @db.profiling_level = :off
254
+ assert_equal :off, @db.profiling_level
255
+ @db.profiling_level = :all
256
+ assert_equal :all, @db.profiling_level
257
+ begin
258
+ @db.profiling_level = :medium
259
+ fail "shouldn't be able to do this"
260
+ rescue
261
+ end
262
+ end
263
+
264
+ should "return profiling info" do
265
+ @db.profiling_level = :all
266
+ @coll.find()
267
+ @db.profiling_level = :off
268
+
269
+ info = @db.profiling_info
270
+ assert_kind_of Array, info
271
+ assert info.length >= 1
272
+ first = info.first
273
+ assert_kind_of String, first['info']
274
+ assert_kind_of Time, first['ts']
275
+ assert_kind_of Numeric, first['millis']
276
+ end
277
+
278
+ should "validate collection" do
279
+ doc = @db.validate_collection(@coll.name)
280
+ assert_not_nil doc
281
+ result = doc['result']
282
+ assert_not_nil result
283
+ assert_match /firstExtent/, result
284
+ end
285
+
286
+ end
287
+ end
@@ -0,0 +1,244 @@
1
+ require './test/test_helper'
2
+ include Mongo
3
+
4
+ class GridFileSystemTest < Test::Unit::TestCase
5
+ context "GridFileSystem:" do
6
+ setup do
7
+ @con = standard_connection
8
+ @db = @con.db(MONGO_TEST_DB)
9
+ end
10
+
11
+ teardown do
12
+ @db.drop_collection('fs.files')
13
+ @db.drop_collection('fs.chunks')
14
+ end
15
+
16
+ context "When reading:" do
17
+ setup do
18
+ @chunks_data = "CHUNKS" * 50000
19
+ @grid = GridFileSystem.new(@db)
20
+ @grid.open('sample.file', 'w') do |f|
21
+ f.write @chunks_data
22
+ end
23
+
24
+ @grid = GridFileSystem.new(@db)
25
+ end
26
+
27
+ should "return existence of the file" do
28
+ file = @grid.exist?(:filename => 'sample.file')
29
+ assert_equal 'sample.file', file['filename']
30
+ end
31
+
32
+ should "return nil if the file doesn't exist" do
33
+ assert_nil @grid.exist?(:filename => 'foo.file')
34
+ end
35
+
36
+ should "read sample data" do
37
+ data = @grid.open('sample.file', 'r') { |f| f.read }
38
+ assert_equal data.length, @chunks_data.length
39
+ end
40
+
41
+ should "have a unique index on chunks" do
42
+ assert @db['fs.chunks'].index_information['files_id_1_n_1']['unique']
43
+ end
44
+
45
+ should "have an index on filename" do
46
+ assert @db['fs.files'].index_information['filename_1_uploadDate_-1']
47
+ end
48
+
49
+ should "return an empty string if length is zero" do
50
+ data = @grid.open('sample.file', 'r') { |f| f.read(0) }
51
+ assert_equal '', data
52
+ end
53
+
54
+ should "return the first n bytes" do
55
+ data = @grid.open('sample.file', 'r') {|f| f.read(288888) }
56
+ assert_equal 288888, data.length
57
+ assert_equal @chunks_data[0...288888], data
58
+ end
59
+
60
+ should "return the first n bytes even with an offset" do
61
+ data = @grid.open('sample.file', 'r') do |f|
62
+ f.seek(1000)
63
+ f.read(288888)
64
+ end
65
+ assert_equal 288888, data.length
66
+ assert_equal @chunks_data[1000...289888], data
67
+ end
68
+ end
69
+
70
+ context "When writing:" do
71
+ setup do
72
+ @data = "BYTES" * 50
73
+ @grid = GridFileSystem.new(@db)
74
+ @grid.open('sample', 'w') do |f|
75
+ f.write @data
76
+ end
77
+ end
78
+
79
+ should "read sample data" do
80
+ data = @grid.open('sample', 'r') { |f| f.read }
81
+ assert_equal data.length, @data.length
82
+ end
83
+
84
+ should "return the total number of bytes written" do
85
+ data = 'a' * 300000
86
+ assert_equal 300000, @grid.open('sample', 'w') {|f| f.write(data) }
87
+ end
88
+
89
+ should "more read sample data" do
90
+ data = @grid.open('sample', 'r') { |f| f.read }
91
+ assert_equal data.length, @data.length
92
+ end
93
+
94
+ should "raise exception if file not found" do
95
+ assert_raise GridFileNotFound do
96
+ @grid.open('io', 'r') { |f| f.write('hello') }
97
+ end
98
+ end
99
+
100
+ should "raise exception if not opened for write" do
101
+ assert_raise GridError do
102
+ @grid.open('sample', 'r') { |f| f.write('hello') }
103
+ end
104
+ end
105
+
106
+ context "and when overwriting the file" do
107
+ setup do
108
+ @old = @grid.open('sample', 'r')
109
+
110
+ @new_data = "DATA" * 10
111
+ sleep(2)
112
+ @grid.open('sample', 'w') do |f|
113
+ f.write @new_data
114
+ end
115
+
116
+ @new = @grid.open('sample', 'r')
117
+ end
118
+
119
+ should "have a newer upload date" do
120
+ assert @new.upload_date > @old.upload_date, "New data is not greater than old date."
121
+ end
122
+
123
+ should "have a different files_id" do
124
+ assert_not_equal @new.files_id, @old.files_id
125
+ end
126
+
127
+ should "contain the new data" do
128
+ assert_equal @new_data, @new.read, "Expected DATA"
129
+ end
130
+
131
+ context "and on a second overwrite" do
132
+ setup do
133
+ sleep(2)
134
+ @new_data = "NEW" * 1000
135
+ @grid.open('sample', 'w') do |f|
136
+ f.write @new_data
137
+ end
138
+
139
+ @ids = @db['fs.files'].find({'filename' => 'sample'}).map {|file| file['_id']}
140
+ end
141
+
142
+ should "write a third version of the file" do
143
+ assert_equal 3, @db['fs.files'].find({'filename' => 'sample'}).count
144
+ assert_equal 3, @db['fs.chunks'].find({'files_id' => {'$in' => @ids}}).count
145
+ end
146
+
147
+ should "remove all versions and their data on delete" do
148
+ @grid.delete('sample')
149
+ assert_equal 0, @db['fs.files'].find({'filename' => 'sample'}).count
150
+ assert_equal 0, @db['fs.chunks'].find({'files_id' => {'$in' => @ids}}).count
151
+ end
152
+
153
+ should "delete old versions on write with :delete_old is passed in" do
154
+ @grid.open('sample', 'w', :delete_old => true) do |f|
155
+ f.write @new_data
156
+ end
157
+ @new_ids = @db['fs.files'].find({'filename' => 'sample'}).map {|file| file['_id']}
158
+ assert_equal 1, @new_ids.length
159
+ id = @new_ids.first
160
+ assert !@ids.include?(id)
161
+ assert_equal 1, @db['fs.files'].find({'filename' => 'sample'}).count
162
+ assert_equal 1, @db['fs.chunks'].find({'files_id' => id}).count
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ context "When writing chunks:" do
169
+ setup do
170
+ data = "B" * 50000
171
+ @grid = GridFileSystem.new(@db)
172
+ @grid.open('sample', 'w', :chunk_size => 1000) do |f|
173
+ f.write data
174
+ end
175
+ end
176
+
177
+ should "write the correct number of chunks" do
178
+ file = @db['fs.files'].find_one({:filename => 'sample'})
179
+ chunks = @db['fs.chunks'].find({'files_id' => file['_id']}).to_a
180
+ assert_equal 50, chunks.length
181
+ end
182
+ end
183
+
184
+ context "Positioning:" do
185
+ setup do
186
+ data = 'hello, world' + '1' * 5000 + 'goodbye!' + '2' * 1000 + '!'
187
+ @grid = GridFileSystem.new(@db)
188
+ @grid.open('hello', 'w', :chunk_size => 1000) do |f|
189
+ f.write data
190
+ end
191
+ end
192
+
193
+ should "seek within chunks" do
194
+ @grid.open('hello', 'r') do |f|
195
+ f.seek(0)
196
+ assert_equal 'h', f.read(1)
197
+ f.seek(7)
198
+ assert_equal 'w', f.read(1)
199
+ f.seek(4)
200
+ assert_equal 'o', f.read(1)
201
+ f.seek(0)
202
+ f.seek(7, IO::SEEK_CUR)
203
+ assert_equal 'w', f.read(1)
204
+ f.seek(-2, IO::SEEK_CUR)
205
+ assert_equal ' ', f.read(1)
206
+ f.seek(-4, IO::SEEK_CUR)
207
+ assert_equal 'l', f.read(1)
208
+ f.seek(3, IO::SEEK_CUR)
209
+ assert_equal 'w', f.read(1)
210
+ end
211
+ end
212
+
213
+ should "seek between chunks" do
214
+ @grid.open('hello', 'r') do |f|
215
+ f.seek(1000)
216
+ assert_equal '11111', f.read(5)
217
+
218
+ f.seek(5009)
219
+ assert_equal '111goodbye!222', f.read(14)
220
+
221
+ f.seek(-1, IO::SEEK_END)
222
+ assert_equal '!', f.read(1)
223
+ f.seek(-6, IO::SEEK_END)
224
+ assert_equal '2', f.read(1)
225
+ end
226
+ end
227
+
228
+ should "tell the current position" do
229
+ @grid.open('hello', 'r') do |f|
230
+ assert_equal 0, f.tell
231
+
232
+ f.seek(999)
233
+ assert_equal 999, f.tell
234
+ end
235
+ end
236
+
237
+ should "seek only in read mode" do
238
+ assert_raise GridError do
239
+ @grid.open('hello', 'w') {|f| f.seek(0) }
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end