mongo 1.10.0-java

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 (116) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE +190 -0
  5. data/README.md +149 -0
  6. data/Rakefile +31 -0
  7. data/VERSION +1 -0
  8. data/bin/mongo_console +43 -0
  9. data/ext/jsasl/target/jsasl.jar +0 -0
  10. data/lib/mongo.rb +90 -0
  11. data/lib/mongo/bulk_write_collection_view.rb +380 -0
  12. data/lib/mongo/collection.rb +1164 -0
  13. data/lib/mongo/collection_writer.rb +364 -0
  14. data/lib/mongo/connection.rb +19 -0
  15. data/lib/mongo/connection/node.rb +239 -0
  16. data/lib/mongo/connection/pool.rb +347 -0
  17. data/lib/mongo/connection/pool_manager.rb +325 -0
  18. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  21. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  22. data/lib/mongo/connection/socket/tcp_socket.rb +86 -0
  23. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  24. data/lib/mongo/cursor.rb +719 -0
  25. data/lib/mongo/db.rb +735 -0
  26. data/lib/mongo/exception.rb +88 -0
  27. data/lib/mongo/functional.rb +21 -0
  28. data/lib/mongo/functional/authentication.rb +318 -0
  29. data/lib/mongo/functional/logging.rb +85 -0
  30. data/lib/mongo/functional/read_preference.rb +174 -0
  31. data/lib/mongo/functional/sasl_java.rb +48 -0
  32. data/lib/mongo/functional/uri_parser.rb +374 -0
  33. data/lib/mongo/functional/write_concern.rb +66 -0
  34. data/lib/mongo/gridfs.rb +18 -0
  35. data/lib/mongo/gridfs/grid.rb +112 -0
  36. data/lib/mongo/gridfs/grid_ext.rb +53 -0
  37. data/lib/mongo/gridfs/grid_file_system.rb +163 -0
  38. data/lib/mongo/gridfs/grid_io.rb +484 -0
  39. data/lib/mongo/legacy.rb +140 -0
  40. data/lib/mongo/mongo_client.rb +702 -0
  41. data/lib/mongo/mongo_replica_set_client.rb +523 -0
  42. data/lib/mongo/mongo_sharded_client.rb +159 -0
  43. data/lib/mongo/networking.rb +370 -0
  44. data/lib/mongo/utils.rb +19 -0
  45. data/lib/mongo/utils/conversions.rb +110 -0
  46. data/lib/mongo/utils/core_ext.rb +70 -0
  47. data/lib/mongo/utils/server_version.rb +69 -0
  48. data/lib/mongo/utils/support.rb +80 -0
  49. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  50. data/mongo.gemspec +36 -0
  51. data/test/functional/authentication_test.rb +35 -0
  52. data/test/functional/bulk_api_stress_test.rb +133 -0
  53. data/test/functional/bulk_write_collection_view_test.rb +1129 -0
  54. data/test/functional/client_test.rb +565 -0
  55. data/test/functional/collection_test.rb +2073 -0
  56. data/test/functional/collection_writer_test.rb +83 -0
  57. data/test/functional/conversions_test.rb +163 -0
  58. data/test/functional/cursor_fail_test.rb +63 -0
  59. data/test/functional/cursor_message_test.rb +57 -0
  60. data/test/functional/cursor_test.rb +625 -0
  61. data/test/functional/db_api_test.rb +819 -0
  62. data/test/functional/db_connection_test.rb +27 -0
  63. data/test/functional/db_test.rb +344 -0
  64. data/test/functional/grid_file_system_test.rb +285 -0
  65. data/test/functional/grid_io_test.rb +252 -0
  66. data/test/functional/grid_test.rb +273 -0
  67. data/test/functional/pool_test.rb +62 -0
  68. data/test/functional/safe_test.rb +98 -0
  69. data/test/functional/ssl_test.rb +29 -0
  70. data/test/functional/support_test.rb +62 -0
  71. data/test/functional/timeout_test.rb +58 -0
  72. data/test/functional/uri_test.rb +330 -0
  73. data/test/functional/write_concern_test.rb +118 -0
  74. data/test/helpers/general.rb +50 -0
  75. data/test/helpers/test_unit.rb +317 -0
  76. data/test/replica_set/authentication_test.rb +35 -0
  77. data/test/replica_set/basic_test.rb +174 -0
  78. data/test/replica_set/client_test.rb +341 -0
  79. data/test/replica_set/complex_connect_test.rb +77 -0
  80. data/test/replica_set/connection_test.rb +138 -0
  81. data/test/replica_set/count_test.rb +64 -0
  82. data/test/replica_set/cursor_test.rb +212 -0
  83. data/test/replica_set/insert_test.rb +140 -0
  84. data/test/replica_set/max_values_test.rb +145 -0
  85. data/test/replica_set/pinning_test.rb +55 -0
  86. data/test/replica_set/query_test.rb +73 -0
  87. data/test/replica_set/read_preference_test.rb +214 -0
  88. data/test/replica_set/refresh_test.rb +175 -0
  89. data/test/replica_set/replication_ack_test.rb +94 -0
  90. data/test/replica_set/ssl_test.rb +32 -0
  91. data/test/sharded_cluster/basic_test.rb +197 -0
  92. data/test/shared/authentication/basic_auth_shared.rb +286 -0
  93. data/test/shared/authentication/bulk_api_auth_shared.rb +259 -0
  94. data/test/shared/authentication/gssapi_shared.rb +164 -0
  95. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  96. data/test/shared/ssl_shared.rb +235 -0
  97. data/test/test_helper.rb +56 -0
  98. data/test/threading/basic_test.rb +120 -0
  99. data/test/tools/mongo_config.rb +608 -0
  100. data/test/tools/mongo_config_test.rb +160 -0
  101. data/test/unit/client_test.rb +347 -0
  102. data/test/unit/collection_test.rb +166 -0
  103. data/test/unit/connection_test.rb +325 -0
  104. data/test/unit/cursor_test.rb +299 -0
  105. data/test/unit/db_test.rb +136 -0
  106. data/test/unit/grid_test.rb +76 -0
  107. data/test/unit/mongo_sharded_client_test.rb +48 -0
  108. data/test/unit/node_test.rb +93 -0
  109. data/test/unit/pool_manager_test.rb +142 -0
  110. data/test/unit/read_pref_test.rb +115 -0
  111. data/test/unit/read_test.rb +159 -0
  112. data/test/unit/safe_test.rb +158 -0
  113. data/test/unit/sharding_pool_manager_test.rb +84 -0
  114. data/test/unit/write_concern_test.rb +175 -0
  115. metadata +260 -0
  116. metadata.gz.sig +0 -0
@@ -0,0 +1,27 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'test_helper'
16
+
17
+ class DBConnectionTest < Test::Unit::TestCase
18
+
19
+ def test_no_exceptions
20
+ host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
21
+ port = ENV['MONGO_RUBY_DRIVER_PORT'] || MongoClient::DEFAULT_PORT
22
+ db = MongoClient.new(host, port).db(TEST_DB)
23
+ coll = db.collection('test')
24
+ coll.remove
25
+ db.get_last_error
26
+ end
27
+ end
@@ -0,0 +1,344 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'test_helper'
16
+ require 'digest/md5'
17
+ require 'stringio'
18
+ require 'logger'
19
+
20
+ class TestPKFactory
21
+ def create_pk(row)
22
+ row['_id'] ||= BSON::ObjectId.new
23
+ row
24
+ end
25
+ end
26
+
27
+ class DBTest < Test::Unit::TestCase
28
+
29
+ include Mongo
30
+
31
+ @@client = standard_connection
32
+ @@db = @@client.db(TEST_DB)
33
+ @@version = @@client.server_version
34
+
35
+ def test_close
36
+ @@client.close
37
+ assert !@@client.connected?
38
+ begin
39
+ @@db.collection('test').insert('a' => 1)
40
+ fail "expected 'NilClass' exception"
41
+ rescue => ex
42
+ assert_match(/NilClass/, ex.to_s)
43
+ ensure
44
+ @@db = standard_connection.db(TEST_DB)
45
+ end
46
+ end
47
+
48
+ def test_create_collection
49
+ col = @@db.create_collection('foo')
50
+ assert_equal @@db['foo'].name, col.name
51
+
52
+ col = @@db.create_collection(:foo)
53
+ assert_equal @@db['foo'].name, col.name
54
+
55
+ @@db.drop_collection('foo')
56
+ end
57
+
58
+ def test_get_and_drop_collection
59
+ db = @@client.db(TEST_DB, :strict => true)
60
+ db.create_collection('foo')
61
+ assert db.collection('foo')
62
+ assert db.drop_collection('foo')
63
+
64
+ db.create_collection(:foo)
65
+ assert db.collection(:foo)
66
+ assert db.drop_collection(:foo)
67
+ end
68
+
69
+ def test_logger
70
+ output = StringIO.new
71
+ logger = Logger.new(output)
72
+ logger.level = Logger::DEBUG
73
+ conn = standard_connection(:logger => logger)
74
+ assert_equal logger, conn.logger
75
+
76
+ conn.logger.debug 'testing'
77
+ assert output.string.include?('testing')
78
+ end
79
+
80
+ def test_full_coll_name
81
+ coll = @@db.collection('test')
82
+ assert_equal "#{TEST_DB}.test", @@db.full_collection_name(coll.name)
83
+ end
84
+
85
+ def test_collection_names
86
+ @@db.collection("test").insert("foo" => 5)
87
+ @@db.collection("test.mike").insert("bar" => 0)
88
+
89
+ colls = @@db.collection_names()
90
+ assert colls.include?("test")
91
+ assert colls.include?("test.mike")
92
+ colls.each { |name|
93
+ assert !name.include?("$")
94
+ }
95
+ end
96
+
97
+ def test_collections
98
+ @@db.collection("test.durran").insert("foo" => 5)
99
+ @@db.collection("test.les").insert("bar" => 0)
100
+
101
+ colls = @@db.collections()
102
+ assert_not_nil colls.select { |coll| coll.name == "test.durran" }
103
+ assert_not_nil colls.select { |coll| coll.name == "test.les" }
104
+ assert_equal [], colls.select { |coll| coll.name == "does_not_exist" }
105
+
106
+ assert_kind_of Collection, colls[0]
107
+ end
108
+
109
+ def test_pk_factory
110
+ db = standard_connection.db(TEST_DB, :pk => TestPKFactory.new)
111
+ coll = db.collection('test')
112
+ coll.remove
113
+
114
+ insert_id = coll.insert('name' => 'Fred', 'age' => 42)
115
+ # new id gets added to returned object
116
+ row = coll.find_one({'name' => 'Fred'})
117
+ oid = row['_id']
118
+ assert_not_nil oid
119
+ assert_equal insert_id, oid
120
+
121
+ oid = BSON::ObjectId.new
122
+ data = {'_id' => oid, 'name' => 'Barney', 'age' => 41}
123
+ coll.insert(data)
124
+ row = coll.find_one({'name' => data['name']})
125
+ db_oid = row['_id']
126
+ assert_equal oid, db_oid
127
+ assert_equal data, row
128
+
129
+ coll.remove
130
+ end
131
+
132
+ def test_pk_factory_reset
133
+ conn = standard_connection
134
+ db = conn.db(TEST_DB)
135
+ db.pk_factory = Object.new # first time
136
+ begin
137
+ db.pk_factory = Object.new
138
+ fail "error: expected exception"
139
+ rescue => ex
140
+ assert_match(/Cannot change/, ex.to_s)
141
+ ensure
142
+ conn.close
143
+ end
144
+ end
145
+
146
+ def test_command
147
+ assert_raise OperationFailure do
148
+ @@db.command({:non_command => 1}, :check_response => true)
149
+ end
150
+
151
+ result = @@db.command({:non_command => 1}, :check_response => false)
152
+ assert !Mongo::Support.ok?(result)
153
+ end
154
+
155
+ def test_error
156
+ @@db.reset_error_history
157
+ assert_nil @@db.get_last_error['err']
158
+ assert !@@db.error?
159
+ assert_nil @@db.previous_error
160
+
161
+ @@db.command({:forceerror => 1}, :check_response => false)
162
+ assert @@db.error?
163
+ assert_not_nil @@db.get_last_error['err']
164
+ assert_not_nil @@db.previous_error
165
+
166
+ @@db.command({:forceerror => 1}, :check_response => false)
167
+ assert @@db.error?
168
+ assert @@db.get_last_error['err']
169
+ prev_error = @@db.previous_error
170
+ assert_equal 1, prev_error['nPrev']
171
+ assert_equal prev_error["err"], @@db.get_last_error['err']
172
+
173
+ @@db.collection('test').find_one
174
+ assert_nil @@db.get_last_error['err']
175
+ assert !@@db.error?
176
+ assert @@db.previous_error
177
+ assert_equal 2, @@db.previous_error['nPrev']
178
+
179
+ @@db.reset_error_history
180
+ assert_nil @@db.get_last_error['err']
181
+ assert !@@db.error?
182
+ assert_nil @@db.previous_error
183
+ end
184
+
185
+ def test_check_command_response
186
+ command = {:forceerror => 1}
187
+ raised = false
188
+ begin
189
+ @@db.command(command)
190
+ rescue => ex
191
+ raised = true
192
+ assert ex.message.include?("forced error"),
193
+ "error message does not contain 'forced error'"
194
+ assert_equal 10038, ex.error_code
195
+
196
+ if @@version >= "2.1.0"
197
+ assert_equal 10038, ex.result['code']
198
+ else
199
+ assert_equal 10038, ex.result['assertionCode']
200
+ end
201
+ ensure
202
+ assert raised, "No assertion raised!"
203
+ end
204
+ end
205
+
206
+ def test_arbitrary_command_opts
207
+ with_forced_timeout(@@client) do
208
+ assert_raise ExecutionTimeout do
209
+ cmd = OrderedHash.new
210
+ cmd[:ping] = 1
211
+ cmd[:maxTimeMS] = 100
212
+ @@db.command(cmd)
213
+ end
214
+ end
215
+ end
216
+
217
+ def test_command_with_bson
218
+ normal_response = @@db.command({:buildInfo => 1})
219
+ bson = BSON::BSON_CODER.serialize({:buildInfo => 1}, false, false)
220
+ bson_response = @@db.command({:bson => bson})
221
+ assert_equal normal_response, bson_response
222
+ end
223
+
224
+ def test_last_status
225
+ @@db['test'].remove
226
+ @@db['test'].save("i" => 1)
227
+
228
+ @@db['test'].update({"i" => 1}, {"$set" => {"i" => 2}})
229
+ assert @@db.get_last_error()["updatedExisting"]
230
+
231
+ @@db['test'].update({"i" => 1}, {"$set" => {"i" => 500}})
232
+ assert !@@db.get_last_error()["updatedExisting"]
233
+ end
234
+
235
+ def test_text_port_number_raises_no_errors
236
+ client = standard_connection
237
+ db = client[TEST_DB]
238
+ db.collection('users').remove
239
+ end
240
+
241
+ def test_stored_function_management
242
+ @@db.add_stored_function("sum", "function (x, y) { return x + y; }")
243
+ assert_equal @@db.eval("return sum(2,3);"), 5
244
+ assert @@db.remove_stored_function("sum")
245
+ assert_raise OperationFailure do
246
+ @@db.eval("return sum(2,3);")
247
+ end
248
+ end
249
+
250
+ def test_eval
251
+ @@db.eval("db.system.save({_id:'hello', value: function() { print('hello'); } })")
252
+ assert_equal 'hello', @@db['system'].find_one['_id']
253
+ end
254
+
255
+ def test_eval_nolock
256
+ function = "db.system.save({_id:'hello', value: function(string) { print(string); } })"
257
+ @@db.expects(:command).with do |selector, opts|
258
+ selector[:nolock] == true
259
+ end.returns({ 'ok' => 1, 'retval' => 1 })
260
+ @@db.eval(function, 'hello', :nolock => true)
261
+ end
262
+
263
+ if @@version >= '2.5.3'
264
+ def test_default_admin_roles
265
+ # admin user
266
+ db = Mongo::MongoClient.new()['admin']
267
+ db.logout
268
+ silently { db.add_user('admin', 'pass') }
269
+ db.authenticate('admin', 'pass')
270
+ info = db.command(:usersInfo => 'admin')['users'].first
271
+ assert_equal 'root', info['roles'].first['role']
272
+
273
+ # read-only admin user
274
+ silently { db.add_user('ro-admin', 'pass', true) }
275
+ db.logout
276
+ db.authenticate('ro-admin', 'pass')
277
+ info = db.command(:usersInfo => 'ro-admin')['users'].first
278
+ assert_equal 'readAnyDatabase', info['roles'].first['role']
279
+ db.logout
280
+
281
+ db.authenticate('admin', 'pass')
282
+ db.command(:dropAllUsersFromDatabase => 1)
283
+ db.logout
284
+ end
285
+ end
286
+
287
+ if @@version >= "1.3.5"
288
+ def test_db_stats
289
+ stats = @@db.stats
290
+ assert stats.has_key?('collections')
291
+ assert stats.has_key?('dataSize')
292
+ end
293
+ end
294
+
295
+ context "database profiling" do
296
+ setup do
297
+ @db = @@client[TEST_DB]
298
+ @coll = @db['test']
299
+ @coll.remove
300
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
301
+ end
302
+
303
+ should "set default profiling level" do
304
+ assert_equal :off, @db.profiling_level
305
+ end
306
+
307
+ should "change profiling level" do
308
+ @db.profiling_level = :slow_only
309
+ assert_equal :slow_only, @db.profiling_level
310
+ @db.profiling_level = :off
311
+ assert_equal :off, @db.profiling_level
312
+ @db.profiling_level = :all
313
+ assert_equal :all, @db.profiling_level
314
+ begin
315
+ @db.profiling_level = :medium
316
+ fail "shouldn't be able to do this"
317
+ rescue
318
+ end
319
+ end
320
+
321
+ should "return profiling info" do
322
+ @db.profiling_level = :all
323
+ @coll.find()
324
+ @db.profiling_level = :off
325
+
326
+ info = @db.profiling_info
327
+ assert_kind_of Array, info
328
+ assert info.length >= 1
329
+ first = info.first
330
+ assert_kind_of Time, first['ts']
331
+ assert_kind_of Numeric, first['millis']
332
+ end
333
+
334
+ should "validate collection" do
335
+ doc = @db.validate_collection(@coll.name)
336
+ if @@version >= "1.9.1"
337
+ assert doc['valid']
338
+ else
339
+ assert doc['result']
340
+ end
341
+ end
342
+
343
+ end
344
+ end
@@ -0,0 +1,285 @@
1
+ # Copyright (C) 2009-2013 MongoDB, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'test_helper'
16
+
17
+ class GridFileSystemTest < Test::Unit::TestCase
18
+ context "GridFileSystem:" do
19
+ setup do
20
+ @con = standard_connection
21
+ @db = @con.db(TEST_DB)
22
+ end
23
+
24
+ teardown do
25
+ @db.drop_collection('fs.files')
26
+ @db.drop_collection('fs.chunks')
27
+ end
28
+
29
+ context "Initialization" do
30
+ setup do
31
+ @chunks_data = "CHUNKS" * 50000
32
+ @grid = GridFileSystem.new(@db)
33
+ @opts = {:w => 1}
34
+ @original_opts = @opts.dup
35
+ @grid.open('sample.file', 'w', @opts) do |f|
36
+ f.write @chunks_data
37
+ end
38
+ end
39
+
40
+ should "not modify original opts" do
41
+ assert_equal @original_opts, @opts
42
+ end
43
+ end
44
+
45
+ context "When reading:" do
46
+ setup do
47
+ @chunks_data = "CHUNKS" * 50000
48
+ @grid = GridFileSystem.new(@db)
49
+ @grid.open('sample.file', 'w') do |f|
50
+ f.write @chunks_data
51
+ end
52
+
53
+ @grid = GridFileSystem.new(@db)
54
+ end
55
+
56
+ should "return existence of the file" do
57
+ file = @grid.exist?(:filename => 'sample.file')
58
+ assert_equal 'sample.file', file['filename']
59
+ end
60
+
61
+ should "return nil if the file doesn't exist" do
62
+ assert_nil @grid.exist?(:filename => 'foo.file')
63
+ end
64
+
65
+ should "read sample data" do
66
+ data = @grid.open('sample.file', 'r') { |f| f.read }
67
+ assert_equal data.length, @chunks_data.length
68
+ end
69
+
70
+ should "have a unique index on chunks" do
71
+ assert @db['fs.chunks'].index_information['files_id_1_n_1']['unique']
72
+ end
73
+
74
+ should "have an index on filename" do
75
+ assert @db['fs.files'].index_information['filename_1_uploadDate_-1']
76
+ end
77
+
78
+ should "return an empty string if length is zero" do
79
+ data = @grid.open('sample.file', 'r') { |f| f.read(0) }
80
+ assert_equal '', data
81
+ end
82
+
83
+ should "return the first n bytes" do
84
+ data = @grid.open('sample.file', 'r') {|f| f.read(288888) }
85
+ assert_equal 288888, data.length
86
+ assert_equal @chunks_data[0...288888], data
87
+ end
88
+
89
+ should "return the first n bytes even with an offset" do
90
+ data = @grid.open('sample.file', 'r') do |f|
91
+ f.seek(1000)
92
+ f.read(288888)
93
+ end
94
+ assert_equal 288888, data.length
95
+ assert_equal @chunks_data[1000...289888], data
96
+ end
97
+ end
98
+
99
+ context "When writing:" do
100
+ setup do
101
+ @data = "BYTES" * 50
102
+ @grid = GridFileSystem.new(@db)
103
+ @grid.open('sample', 'w') do |f|
104
+ f.write @data
105
+ end
106
+ end
107
+
108
+ should "read sample data" do
109
+ data = @grid.open('sample', 'r') { |f| f.read }
110
+ assert_equal data.length, @data.length
111
+ end
112
+
113
+ should "return the total number of bytes written" do
114
+ data = 'a' * 300000
115
+ assert_equal 300000, @grid.open('sample', 'w') {|f| f.write(data) }
116
+ end
117
+
118
+ should "more read sample data" do
119
+ data = @grid.open('sample', 'r') { |f| f.read }
120
+ assert_equal data.length, @data.length
121
+ end
122
+
123
+ should "raise exception if file not found" do
124
+ assert_raise GridFileNotFound do
125
+ @grid.open('io', 'r') { |f| f.write('hello') }
126
+ end
127
+ end
128
+
129
+ should "raise exception if not opened for write" do
130
+ assert_raise GridError do
131
+ @grid.open('sample', 'r') { |f| f.write('hello') }
132
+ end
133
+ end
134
+
135
+ context "and when overwriting the file" do
136
+ setup do
137
+ @old = @grid.open('sample', 'r')
138
+
139
+ @new_data = "DATA" * 10
140
+ @grid.open('sample', 'w') do |f|
141
+ f.write @new_data
142
+ end
143
+
144
+ @new = @grid.open('sample', 'r')
145
+ end
146
+
147
+ should "have a newer upload date" do
148
+ assert @new.upload_date > @old.upload_date, "New data is not greater than old date."
149
+ end
150
+
151
+ should "have a different files_id" do
152
+ assert_not_equal @new.files_id, @old.files_id
153
+ end
154
+
155
+ should "contain the new data" do
156
+ assert_equal @new_data, @new.read, "Expected DATA"
157
+ end
158
+
159
+ context "and on a second overwrite" do
160
+ setup do
161
+ @new_data = "NEW" * 1000
162
+ @grid.open('sample', 'w') do |f|
163
+ f.write @new_data
164
+ end
165
+
166
+ @ids = @db['fs.files'].find({'filename' => 'sample'}).map {|file| file['_id']}
167
+ end
168
+
169
+ should "write a third version of the file" do
170
+ assert_equal 3, @db['fs.files'].find({'filename' => 'sample'}).count
171
+ assert_equal 3, @db['fs.chunks'].find({'files_id' => {'$in' => @ids}}).count
172
+ end
173
+
174
+ should "remove all versions and their data on delete" do
175
+ @grid.delete('sample')
176
+ assert_equal 0, @db['fs.files'].find({'filename' => 'sample'}).count
177
+ assert_equal 0, @db['fs.chunks'].find({'files_id' => {'$in' => @ids}}).count
178
+ end
179
+
180
+ should "delete all versions which exceed the number of versions to keep specified by the option :versions" do
181
+ @versions = 1 + rand(4-1)
182
+ @grid.open('sample', 'w', :versions => @versions) do |f|
183
+ f.write @new_data
184
+ end
185
+ @new_ids = @db['fs.files'].find({'filename' => 'sample'}).map {|file| file['_id']}
186
+ assert_equal @versions, @new_ids.length
187
+ id = @new_ids.first
188
+ assert !@ids.include?(id)
189
+ assert_equal @versions, @db['fs.files'].find({'filename' => 'sample'}).count
190
+ end
191
+
192
+ should "delete old versions on write with :delete_old is passed in" do
193
+ @grid.open('sample', 'w', :delete_old => true) do |f|
194
+ f.write @new_data
195
+ end
196
+ @new_ids = @db['fs.files'].find({'filename' => 'sample'}).map {|file| file['_id']}
197
+ assert_equal 1, @new_ids.length
198
+ id = @new_ids.first
199
+ assert !@ids.include?(id)
200
+ assert_equal 1, @db['fs.files'].find({'filename' => 'sample'}).count
201
+ assert_equal 1, @db['fs.chunks'].find({'files_id' => id}).count
202
+ end
203
+ end
204
+ end
205
+ end
206
+
207
+ context "When writing chunks:" do
208
+ setup do
209
+ data = "B" * 50000
210
+ @grid = GridFileSystem.new(@db)
211
+ @grid.open('sample', 'w', :chunk_size => 1000) do |f|
212
+ f.write data
213
+ end
214
+ end
215
+
216
+ should "write the correct number of chunks" do
217
+ file = @db['fs.files'].find_one({:filename => 'sample'})
218
+ chunks = @db['fs.chunks'].find({'files_id' => file['_id']}).to_a
219
+ assert_equal 50, chunks.length
220
+ end
221
+ end
222
+
223
+ context "Positioning:" do
224
+ setup do
225
+ data = 'hello, world' + '1' * 5000 + 'goodbye!' + '2' * 1000 + '!'
226
+ @grid = GridFileSystem.new(@db)
227
+ @grid.open('hello', 'w', :chunk_size => 1000) do |f|
228
+ f.write data
229
+ end
230
+ end
231
+
232
+ should "seek within chunks" do
233
+ @grid.open('hello', 'r') do |f|
234
+ f.seek(0)
235
+ assert_equal 'h', f.read(1)
236
+ f.seek(7)
237
+ assert_equal 'w', f.read(1)
238
+ f.seek(4)
239
+ assert_equal 'o', f.read(1)
240
+ f.seek(0)
241
+ f.seek(7, IO::SEEK_CUR)
242
+ assert_equal 'w', f.read(1)
243
+ f.seek(-2, IO::SEEK_CUR)
244
+ assert_equal ' ', f.read(1)
245
+ f.seek(-4, IO::SEEK_CUR)
246
+ assert_equal 'l', f.read(1)
247
+ f.seek(3, IO::SEEK_CUR)
248
+ assert_equal 'w', f.read(1)
249
+ end
250
+ end
251
+
252
+ should "seek between chunks" do
253
+ @grid.open('hello', 'r') do |f|
254
+ f.seek(1000)
255
+ assert_equal '11111', f.read(5)
256
+
257
+ f.seek(5009)
258
+ assert_equal '111goodbye!222', f.read(14)
259
+
260
+ f.seek(-1, IO::SEEK_END)
261
+ assert_equal '!', f.read(1)
262
+ f.seek(-6, IO::SEEK_END)
263
+ assert_equal '2', f.read(1)
264
+ end
265
+ end
266
+
267
+ should "tell the current position" do
268
+ @grid.open('hello', 'r') do |f|
269
+ assert_equal 0, f.tell
270
+
271
+ f.seek(999)
272
+ assert_equal 999, f.tell
273
+ end
274
+ end
275
+
276
+ should "seek only in read mode" do
277
+ assert_raise GridError do
278
+ silently do
279
+ @grid.open('hello', 'w') { |f| f.seek(0) }
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end
285
+ end