mongo 1.3.0 → 1.12.5

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 (185) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/{LICENSE.txt → LICENSE} +1 -1
  4. data/README.md +122 -271
  5. data/Rakefile +25 -209
  6. data/VERSION +1 -0
  7. data/bin/mongo_console +31 -9
  8. data/lib/mongo/bulk_write_collection_view.rb +387 -0
  9. data/lib/mongo/collection.rb +576 -269
  10. data/lib/mongo/collection_writer.rb +364 -0
  11. data/lib/mongo/connection/node.rb +249 -0
  12. data/lib/mongo/connection/pool.rb +340 -0
  13. data/lib/mongo/connection/pool_manager.rb +320 -0
  14. data/lib/mongo/connection/sharding_pool_manager.rb +67 -0
  15. data/lib/mongo/connection/socket/socket_util.rb +37 -0
  16. data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
  17. data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
  18. data/lib/mongo/connection/socket/unix_socket.rb +39 -0
  19. data/lib/mongo/connection/socket.rb +18 -0
  20. data/lib/mongo/connection.rb +7 -875
  21. data/lib/mongo/cursor.rb +403 -117
  22. data/lib/mongo/db.rb +444 -243
  23. data/lib/mongo/exception.rb +145 -0
  24. data/lib/mongo/functional/authentication.rb +455 -0
  25. data/lib/mongo/functional/logging.rb +85 -0
  26. data/lib/mongo/functional/read_preference.rb +183 -0
  27. data/lib/mongo/functional/scram.rb +556 -0
  28. data/lib/mongo/functional/uri_parser.rb +409 -0
  29. data/lib/mongo/functional/write_concern.rb +66 -0
  30. data/lib/mongo/functional.rb +20 -0
  31. data/lib/mongo/gridfs/grid.rb +30 -24
  32. data/lib/mongo/gridfs/grid_ext.rb +6 -10
  33. data/lib/mongo/gridfs/grid_file_system.rb +38 -20
  34. data/lib/mongo/gridfs/grid_io.rb +84 -75
  35. data/lib/mongo/gridfs.rb +18 -0
  36. data/lib/mongo/legacy.rb +140 -0
  37. data/lib/mongo/mongo_client.rb +697 -0
  38. data/lib/mongo/mongo_replica_set_client.rb +535 -0
  39. data/lib/mongo/mongo_sharded_client.rb +159 -0
  40. data/lib/mongo/networking.rb +372 -0
  41. data/lib/mongo/{util → utils}/conversions.rb +29 -8
  42. data/lib/mongo/{util → utils}/core_ext.rb +28 -18
  43. data/lib/mongo/{util → utils}/server_version.rb +4 -6
  44. data/lib/mongo/{util → utils}/support.rb +29 -31
  45. data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
  46. data/lib/mongo/utils.rb +19 -0
  47. data/lib/mongo.rb +51 -50
  48. data/mongo.gemspec +29 -32
  49. data/test/functional/authentication_test.rb +39 -0
  50. data/test/functional/bulk_api_stress_test.rb +133 -0
  51. data/test/functional/bulk_write_collection_view_test.rb +1198 -0
  52. data/test/functional/client_test.rb +627 -0
  53. data/test/functional/collection_test.rb +2175 -0
  54. data/test/functional/collection_writer_test.rb +83 -0
  55. data/test/{conversions_test.rb → functional/conversions_test.rb} +47 -3
  56. data/test/functional/cursor_fail_test.rb +57 -0
  57. data/test/functional/cursor_message_test.rb +56 -0
  58. data/test/functional/cursor_test.rb +683 -0
  59. data/test/functional/db_api_test.rb +835 -0
  60. data/test/functional/db_connection_test.rb +25 -0
  61. data/test/functional/db_test.rb +348 -0
  62. data/test/functional/grid_file_system_test.rb +285 -0
  63. data/test/{grid_io_test.rb → functional/grid_io_test.rb} +72 -11
  64. data/test/{grid_test.rb → functional/grid_test.rb} +88 -15
  65. data/test/functional/pool_test.rb +136 -0
  66. data/test/functional/safe_test.rb +98 -0
  67. data/test/functional/ssl_test.rb +29 -0
  68. data/test/functional/support_test.rb +62 -0
  69. data/test/functional/timeout_test.rb +60 -0
  70. data/test/functional/uri_test.rb +446 -0
  71. data/test/functional/write_concern_test.rb +118 -0
  72. data/test/helpers/general.rb +50 -0
  73. data/test/helpers/test_unit.rb +476 -0
  74. data/test/replica_set/authentication_test.rb +37 -0
  75. data/test/replica_set/basic_test.rb +189 -0
  76. data/test/replica_set/client_test.rb +393 -0
  77. data/test/replica_set/connection_test.rb +138 -0
  78. data/test/replica_set/count_test.rb +66 -0
  79. data/test/replica_set/cursor_test.rb +220 -0
  80. data/test/replica_set/insert_test.rb +157 -0
  81. data/test/replica_set/max_values_test.rb +151 -0
  82. data/test/replica_set/pinning_test.rb +105 -0
  83. data/test/replica_set/query_test.rb +73 -0
  84. data/test/replica_set/read_preference_test.rb +219 -0
  85. data/test/replica_set/refresh_test.rb +211 -0
  86. data/test/replica_set/replication_ack_test.rb +95 -0
  87. data/test/replica_set/ssl_test.rb +32 -0
  88. data/test/sharded_cluster/basic_test.rb +203 -0
  89. data/test/shared/authentication/basic_auth_shared.rb +260 -0
  90. data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
  91. data/test/shared/authentication/gssapi_shared.rb +176 -0
  92. data/test/shared/authentication/sasl_plain_shared.rb +96 -0
  93. data/test/shared/authentication/scram_shared.rb +92 -0
  94. data/test/shared/ssl_shared.rb +235 -0
  95. data/test/test_helper.rb +53 -94
  96. data/test/threading/basic_test.rb +120 -0
  97. data/test/tools/mongo_config.rb +708 -0
  98. data/test/tools/mongo_config_test.rb +160 -0
  99. data/test/unit/client_test.rb +381 -0
  100. data/test/unit/collection_test.rb +89 -53
  101. data/test/unit/connection_test.rb +282 -32
  102. data/test/unit/cursor_test.rb +206 -8
  103. data/test/unit/db_test.rb +55 -13
  104. data/test/unit/grid_test.rb +43 -16
  105. data/test/unit/mongo_sharded_client_test.rb +48 -0
  106. data/test/unit/node_test.rb +93 -0
  107. data/test/unit/pool_manager_test.rb +111 -0
  108. data/test/unit/read_pref_test.rb +406 -0
  109. data/test/unit/read_test.rb +159 -0
  110. data/test/unit/safe_test.rb +69 -36
  111. data/test/unit/sharding_pool_manager_test.rb +84 -0
  112. data/test/unit/write_concern_test.rb +175 -0
  113. data.tar.gz.sig +3 -0
  114. metadata +227 -216
  115. metadata.gz.sig +0 -0
  116. data/docs/CREDITS.md +0 -123
  117. data/docs/FAQ.md +0 -116
  118. data/docs/GridFS.md +0 -158
  119. data/docs/HISTORY.md +0 -244
  120. data/docs/RELEASES.md +0 -33
  121. data/docs/REPLICA_SETS.md +0 -72
  122. data/docs/TUTORIAL.md +0 -247
  123. data/docs/WRITE_CONCERN.md +0 -28
  124. data/lib/mongo/exceptions.rb +0 -71
  125. data/lib/mongo/gridfs/grid_io_fix.rb +0 -38
  126. data/lib/mongo/repl_set_connection.rb +0 -342
  127. data/lib/mongo/test.rb +0 -20
  128. data/lib/mongo/util/pool.rb +0 -177
  129. data/lib/mongo/util/uri_parser.rb +0 -185
  130. data/test/async/collection_test.rb +0 -224
  131. data/test/async/connection_test.rb +0 -24
  132. data/test/async/cursor_test.rb +0 -162
  133. data/test/async/worker_pool_test.rb +0 -99
  134. data/test/auxillary/1.4_features.rb +0 -166
  135. data/test/auxillary/authentication_test.rb +0 -68
  136. data/test/auxillary/autoreconnect_test.rb +0 -41
  137. data/test/auxillary/fork_test.rb +0 -30
  138. data/test/auxillary/repl_set_auth_test.rb +0 -58
  139. data/test/auxillary/slave_connection_test.rb +0 -36
  140. data/test/auxillary/threaded_authentication_test.rb +0 -101
  141. data/test/bson/binary_test.rb +0 -15
  142. data/test/bson/bson_test.rb +0 -649
  143. data/test/bson/byte_buffer_test.rb +0 -208
  144. data/test/bson/hash_with_indifferent_access_test.rb +0 -38
  145. data/test/bson/json_test.rb +0 -17
  146. data/test/bson/object_id_test.rb +0 -154
  147. data/test/bson/ordered_hash_test.rb +0 -204
  148. data/test/bson/timestamp_test.rb +0 -24
  149. data/test/collection_test.rb +0 -910
  150. data/test/connection_test.rb +0 -309
  151. data/test/cursor_fail_test.rb +0 -75
  152. data/test/cursor_message_test.rb +0 -43
  153. data/test/cursor_test.rb +0 -483
  154. data/test/db_api_test.rb +0 -726
  155. data/test/db_connection_test.rb +0 -15
  156. data/test/db_test.rb +0 -287
  157. data/test/grid_file_system_test.rb +0 -243
  158. data/test/load/resque/load.rb +0 -21
  159. data/test/load/resque/processor.rb +0 -26
  160. data/test/load/thin/load.rb +0 -24
  161. data/test/load/unicorn/load.rb +0 -23
  162. data/test/load/unicorn/unicorn.rb +0 -29
  163. data/test/replica_sets/connect_test.rb +0 -94
  164. data/test/replica_sets/connection_string_test.rb +0 -32
  165. data/test/replica_sets/count_test.rb +0 -35
  166. data/test/replica_sets/insert_test.rb +0 -53
  167. data/test/replica_sets/pooled_insert_test.rb +0 -55
  168. data/test/replica_sets/query_secondaries.rb +0 -96
  169. data/test/replica_sets/query_test.rb +0 -51
  170. data/test/replica_sets/replication_ack_test.rb +0 -66
  171. data/test/replica_sets/rs_test_helper.rb +0 -27
  172. data/test/safe_test.rb +0 -68
  173. data/test/support/hash_with_indifferent_access.rb +0 -186
  174. data/test/support/keys.rb +0 -45
  175. data/test/support_test.rb +0 -18
  176. data/test/threading/threading_with_large_pool_test.rb +0 -90
  177. data/test/threading_test.rb +0 -87
  178. data/test/tools/auth_repl_set_manager.rb +0 -14
  179. data/test/tools/load.rb +0 -58
  180. data/test/tools/repl_set_manager.rb +0 -266
  181. data/test/tools/sharding_manager.rb +0 -202
  182. data/test/tools/test.rb +0 -4
  183. data/test/unit/pool_test.rb +0 -9
  184. data/test/unit/repl_set_connection_test.rb +0 -59
  185. data/test/uri_test.rb +0 -91
@@ -0,0 +1,25 @@
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
+ db = standard_connection.db(TEST_DB)
21
+ coll = db.collection('test')
22
+ coll.remove
23
+ db.get_last_error
24
+ end
25
+ end
@@ -0,0 +1,348 @@
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
+ def setup
32
+ @client = standard_connection
33
+ @db = @client.db(TEST_DB)
34
+ @version = @client.server_version
35
+ end
36
+
37
+ def test_close
38
+ @client.close
39
+ assert !@client.connected?
40
+ begin
41
+ @db.collection('test').insert('a' => 1)
42
+ fail "expected 'NilClass' exception"
43
+ rescue => ex
44
+ assert_match(/NilClass/, ex.to_s)
45
+ ensure
46
+ @db = standard_connection.db(TEST_DB)
47
+ end
48
+ end
49
+
50
+ def test_create_collection
51
+ col = @db.create_collection('foo')
52
+ assert_equal @db['foo'].name, col.name
53
+
54
+ col = @db.create_collection(:foo)
55
+ assert_equal @db['foo'].name, col.name
56
+
57
+ @db.drop_collection('foo')
58
+ end
59
+
60
+ def test_get_and_drop_collection
61
+ db = @client.db(TEST_DB, :strict => true)
62
+ db.create_collection('foo')
63
+ assert db.collection('foo')
64
+ assert db.drop_collection('foo')
65
+
66
+ db.create_collection(:foo)
67
+ assert db.collection(:foo)
68
+ # Use a string because of SERVER-16260
69
+ assert db.drop_collection('foo')
70
+ end
71
+
72
+ def test_logger
73
+ output = StringIO.new
74
+ logger = Logger.new(output)
75
+ logger.level = Logger::DEBUG
76
+ conn = standard_connection(:logger => logger)
77
+ assert_equal logger, conn.logger
78
+
79
+ conn.logger.debug 'testing'
80
+ assert output.string.include?('testing')
81
+ end
82
+
83
+ def test_full_coll_name
84
+ coll = @db.collection('test')
85
+ assert_equal "#{TEST_DB}.test", @db.full_collection_name(coll.name)
86
+ end
87
+
88
+ def test_collection_names
89
+ @db.collection("test").insert("foo" => 5)
90
+ @db.collection("test.mike").insert("bar" => 0)
91
+
92
+ colls = @db.collection_names()
93
+ assert colls.include?("test")
94
+ assert colls.include?("test.mike")
95
+ colls.each { |name|
96
+ assert !name.include?("$")
97
+ }
98
+ end
99
+
100
+ def test_collections
101
+ @db.collection("test.durran").insert("foo" => 5)
102
+ @db.collection("test.les").insert("bar" => 0)
103
+
104
+ colls = @db.collections()
105
+ assert_not_nil colls.select { |coll| coll.name == "test.durran" }
106
+ assert_not_nil colls.select { |coll| coll.name == "test.les" }
107
+ assert_equal [], colls.select { |coll| coll.name == "does_not_exist" }
108
+
109
+ assert_kind_of Collection, colls[0]
110
+ end
111
+
112
+ def test_pk_factory
113
+ db = standard_connection.db(TEST_DB, :pk => TestPKFactory.new)
114
+ coll = db.collection('test')
115
+ coll.remove
116
+
117
+ insert_id = coll.insert('name' => 'Fred', 'age' => 42)
118
+ # new id gets added to returned object
119
+ row = coll.find_one({'name' => 'Fred'})
120
+ oid = row['_id']
121
+ assert_not_nil oid
122
+ assert_equal insert_id, oid
123
+
124
+ oid = BSON::ObjectId.new
125
+ data = {'_id' => oid, 'name' => 'Barney', 'age' => 41}
126
+ coll.insert(data)
127
+ row = coll.find_one({'name' => data['name']})
128
+ db_oid = row['_id']
129
+ assert_equal oid, db_oid
130
+ assert_equal data, row
131
+
132
+ coll.remove
133
+ end
134
+
135
+ def test_pk_factory_reset
136
+ conn = standard_connection
137
+ db = conn.db(TEST_DB)
138
+ db.pk_factory = Object.new # first time
139
+ begin
140
+ db.pk_factory = Object.new
141
+ fail "error: expected exception"
142
+ rescue => ex
143
+ assert_match(/Cannot change/, ex.to_s)
144
+ ensure
145
+ conn.close
146
+ end
147
+ end
148
+
149
+ def test_command
150
+ assert_raise OperationFailure do
151
+ @db.command({:non_command => 1}, :check_response => true)
152
+ end
153
+
154
+ result = @db.command({:non_command => 1}, :check_response => false)
155
+ assert !Mongo::Support.ok?(result)
156
+ end
157
+
158
+ def test_error
159
+ @db.reset_error_history
160
+ assert_nil @db.get_last_error['err']
161
+ assert !@db.error?
162
+ assert_nil @db.previous_error
163
+
164
+ @db.command({:forceerror => 1}, :check_response => false)
165
+ assert @db.error?
166
+ assert_not_nil @db.get_last_error['err']
167
+ assert_not_nil @db.previous_error
168
+
169
+ @db.command({:forceerror => 1}, :check_response => false)
170
+ assert @db.error?
171
+ assert @db.get_last_error['err']
172
+ prev_error = @db.previous_error
173
+ assert_equal 1, prev_error['nPrev']
174
+ assert_equal prev_error["err"], @db.get_last_error['err']
175
+
176
+ @db.collection('test').find_one
177
+ assert_nil @db.get_last_error['err']
178
+ assert !@db.error?
179
+ assert @db.previous_error
180
+ assert_equal 2, @db.previous_error['nPrev']
181
+
182
+ @db.reset_error_history
183
+ assert_nil @db.get_last_error['err']
184
+ assert !@db.error?
185
+ assert_nil @db.previous_error
186
+ end
187
+
188
+ def test_check_command_response
189
+ if @version >= "2.1.0"
190
+ command = {:create => "$$$$"}
191
+ expected_codes = [10356, 2]
192
+ expected_msg = "invalid"
193
+ raised = false
194
+ begin
195
+ @db.command(command)
196
+ rescue => ex
197
+ raised = true
198
+ assert ex.message.include?(expected_msg) ||
199
+ (ex.result.has_key?("assertion") &&
200
+ ex.result["assertion"].include?(expected_msg)),
201
+ "error message does not contain '#{expected_msg}'"
202
+ assert expected_codes.include?(ex.error_code)
203
+ assert expected_codes.include?(ex.result['code'])
204
+ ensure
205
+ assert raised, "No assertion raised!"
206
+ end
207
+ end
208
+ end
209
+
210
+ def test_arbitrary_command_opts
211
+ with_forced_timeout(@client) do
212
+ assert_raise ExecutionTimeout do
213
+ cmd = OrderedHash.new
214
+ cmd[:ping] = 1
215
+ cmd[:maxTimeMS] = 100
216
+ @db.command(cmd)
217
+ end
218
+ end
219
+ end
220
+
221
+ def test_command_with_bson
222
+ normal_response = @db.command({:buildInfo => 1})
223
+ bson = BSON::BSON_CODER.serialize({:buildInfo => 1}, false, false)
224
+ bson_response = @db.command({:bson => bson})
225
+ assert_equal normal_response, bson_response
226
+ end
227
+
228
+ def test_last_status
229
+ @db['test'].remove
230
+ @db['test'].save("i" => 1)
231
+
232
+ @db['test'].update({"i" => 1}, {"$set" => {"i" => 2}})
233
+ assert @db.get_last_error()["updatedExisting"]
234
+
235
+ @db['test'].update({"i" => 1}, {"$set" => {"i" => 500}})
236
+ assert !@db.get_last_error()["updatedExisting"]
237
+ end
238
+
239
+ def test_text_port_number_raises_no_errors
240
+ client = standard_connection
241
+ db = client[TEST_DB]
242
+ db.collection('users').remove
243
+ end
244
+
245
+ def test_stored_function_management
246
+ grant_admin_user_eval_role(@client)
247
+ @db.add_stored_function("sum", "function (x, y) { return x + y; }")
248
+ assert_equal @db.eval("return sum(2,3);"), 5
249
+ assert @db.remove_stored_function("sum")
250
+ assert_raise OperationFailure do
251
+ @db.eval("return sum(2,3);")
252
+ end
253
+ end
254
+
255
+ def test_eval
256
+ grant_admin_user_eval_role(@client)
257
+ @db.eval("db.system.save({_id:'hello', value: function() { print('hello'); } })")
258
+ assert_equal 'hello', @db['system'].find_one['_id']
259
+ end
260
+
261
+ def test_eval_nook
262
+ grant_admin_user_eval_role(@client)
263
+ function = "db.system.save({_id:'hello', value: function(string) { print(string); } })"
264
+ @db.expects(:command).with do |selector, opts|
265
+ selector[:nolock] == true
266
+ end.returns({ 'ok' => 1, 'retval' => 1 })
267
+ @db.eval(function, 'hello', :nolock => true)
268
+ end
269
+
270
+ def test_default_admin_roles
271
+ return unless @version >= '2.5.3'
272
+ # admin user
273
+ @db.stubs(:command).returns({}, true)
274
+ @db.expects(:command).with do |command, cmd_opts|
275
+ command[:createUser] == TEST_USER
276
+ cmd_opts[:roles] == ['root'] if cmd_opts
277
+ end
278
+
279
+ silently { @db.add_user(TEST_USER, TEST_USER_PWD) }
280
+
281
+ @db.stubs(:command).returns({}, true)
282
+ @db.expects(:command).with do |command, cmd_opts|
283
+ command[:createUser] == TEST_USER
284
+ cmd_opts[:roles] == ['readAnyDatabase'] if cmd_opts
285
+ end
286
+
287
+ silently { @db.add_user(TEST_USER, TEST_USER_PWD, true) }
288
+ end
289
+
290
+ def test_db_stats
291
+ return unless @version >= "1.3.5"
292
+ stats = @db.stats
293
+ assert stats.has_key?('collections')
294
+ assert stats.has_key?('dataSize')
295
+ end
296
+
297
+ context "database profiling" do
298
+ setup do
299
+ @db = @client[TEST_DB]
300
+ @coll = @db['test']
301
+ @coll.remove
302
+ @r1 = @coll.insert('a' => 1) # collection not created until it's used
303
+ end
304
+
305
+ should "set default profiling level" do
306
+ assert_equal :off, @db.profiling_level
307
+ end
308
+
309
+ should "change profiling level" do
310
+ @db.profiling_level = :slow_only
311
+ assert_equal :slow_only, @db.profiling_level
312
+ @db.profiling_level = :off
313
+ assert_equal :off, @db.profiling_level
314
+ @db.profiling_level = :all
315
+ assert_equal :all, @db.profiling_level
316
+ begin
317
+ @db.profiling_level = :medium
318
+ fail "shouldn't be able to do this"
319
+ rescue
320
+ end
321
+ end
322
+
323
+ should "return profiling info" do
324
+ if @version >= "2.2" && @version < "3.0"
325
+ @db.profiling_level = :all
326
+ @coll.find()
327
+ @db.profiling_level = :off
328
+
329
+ info = @db.profiling_info
330
+ assert_kind_of Array, info
331
+ assert info.length >= 1
332
+ first = info.first
333
+ assert_kind_of Time, first['ts']
334
+ assert_kind_of Numeric, first['millis']
335
+ end
336
+ end
337
+
338
+ should "validate collection" do
339
+ doc = @db.validate_collection(@coll.name)
340
+ if @version >= "1.9.1"
341
+ assert doc['valid']
342
+ else
343
+ assert doc['result']
344
+ end
345
+ end
346
+
347
+ end
348
+ 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