jmongo 1.0.3 → 1.1.0

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