mongo 1.8.2 → 1.8.3.rc0

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 (54) hide show
  1. data.tar.gz.sig +0 -0
  2. data/LICENSE +1 -1
  3. data/README.md +2 -7
  4. data/VERSION +1 -1
  5. data/lib/mongo.rb +2 -18
  6. data/lib/mongo/collection.rb +20 -24
  7. data/lib/mongo/cursor.rb +30 -35
  8. data/lib/mongo/db.rb +1 -19
  9. data/lib/mongo/exceptions.rb +0 -19
  10. data/lib/mongo/gridfs/grid.rb +18 -29
  11. data/lib/mongo/gridfs/grid_ext.rb +0 -18
  12. data/lib/mongo/gridfs/grid_file_system.rb +17 -26
  13. data/lib/mongo/gridfs/grid_io.rb +0 -18
  14. data/lib/mongo/legacy.rb +0 -18
  15. data/lib/mongo/mongo_client.rb +11 -33
  16. data/lib/mongo/mongo_replica_set_client.rb +29 -56
  17. data/lib/mongo/mongo_sharded_client.rb +38 -50
  18. data/lib/mongo/networking.rb +5 -4
  19. data/lib/mongo/util/conversions.rb +0 -17
  20. data/lib/mongo/util/core_ext.rb +0 -18
  21. data/lib/mongo/util/node.rb +16 -3
  22. data/lib/mongo/util/pool.rb +46 -36
  23. data/lib/mongo/util/pool_manager.rb +102 -71
  24. data/lib/mongo/util/read_preference.rb +4 -2
  25. data/lib/mongo/util/server_version.rb +0 -17
  26. data/lib/mongo/util/sharding_pool_manager.rb +4 -23
  27. data/lib/mongo/util/socket_util.rb +20 -0
  28. data/lib/mongo/util/ssl_socket.rb +10 -19
  29. data/lib/mongo/util/support.rb +0 -18
  30. data/lib/mongo/util/tcp_socket.rb +1 -9
  31. data/lib/mongo/util/thread_local_variable_manager.rb +0 -18
  32. data/lib/mongo/util/uri_parser.rb +87 -82
  33. data/lib/mongo/util/write_concern.rb +0 -18
  34. data/mongo.gemspec +4 -1
  35. data/test/auxillary/pool_reuse_test.rb +65 -0
  36. data/test/functional/collection_test.rb +92 -3
  37. data/test/functional/connection_test.rb +30 -6
  38. data/test/functional/db_api_test.rb +11 -0
  39. data/test/functional/timeout_test.rb +23 -0
  40. data/test/functional/uri_test.rb +69 -0
  41. data/test/replica_set/client_test.rb +0 -22
  42. data/test/replica_set/cursor_test.rb +11 -5
  43. data/test/replica_set/refresh_test.rb +0 -0
  44. data/test/replica_set/z_cluster_shutdown.rb +13 -0
  45. data/test/sharded_cluster/basic_test.rb +46 -32
  46. data/test/test_helper.rb +26 -1
  47. data/test/threading/basic_test.rb +10 -9
  48. data/test/tools/mongo_config.rb +6 -2
  49. data/test/unit/collection_test.rb +1 -1
  50. data/test/unit/grid_test.rb +20 -13
  51. data/test/unit/mongo_sharded_client_test.rb +32 -0
  52. data/test/unit/pool_manager_test.rb +28 -14
  53. metadata +45 -12
  54. metadata.gz.sig +0 -0
@@ -1,21 +1,3 @@
1
- # encoding: UTF-8
2
-
3
- # --
4
- # Copyright (C) 2008-2011 10gen Inc.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
- # ++
18
-
19
1
  module Mongo
20
2
  module WriteConcern
21
3
 
@@ -3,13 +3,16 @@ Gem::Specification.new do |s|
3
3
 
4
4
  s.version = File.read(File.join(File.dirname(__FILE__), 'VERSION'))
5
5
  s.platform = Gem::Platform::RUBY
6
- s.authors = ['Tyler Brock', 'Gary Murakami', 'Emily Stolfo', 'Brandon Black']
6
+ s.authors = ['Tyler Brock', 'Gary Murakami', 'Emily Stolfo', 'Brandon Black', 'Durran Jordan']
7
7
  s.email = 'mongodb-dev@googlegroups.com'
8
8
  s.homepage = 'http://www.mongodb.org'
9
9
  s.summary = 'Ruby driver for MongoDB'
10
10
  s.description = 'A Ruby driver for MongoDB. For more information about Mongo, see http://www.mongodb.org.'
11
11
  s.rubyforge_project = 'mongo'
12
12
 
13
+ s.signing_key = 'gem-private_key.pem'
14
+ s.cert_chain = ['gem-public_cert.pem']
15
+
13
16
  s.files = ['mongo.gemspec', 'LICENSE', 'VERSION']
14
17
  s.files += ['README.md', 'Rakefile', 'bin/mongo_console']
15
18
  s.files += ['lib/mongo.rb'] + Dir['lib/mongo/**/*.rb']
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+ require 'mongo'
3
+
4
+ class PoolReuseTest < Test::Unit::TestCase
5
+ include Mongo
6
+
7
+ def count_open_file_handles
8
+ @conn["admin"].command(:serverStatus => 1)["connections"]["current"]
9
+ end
10
+
11
+ def setup
12
+ ensure_cluster(:rs, :replicas => 2, :arbiters => 1)
13
+ connect
14
+ end
15
+
16
+ def teardown
17
+ @@cluster.stop if @@cluster
18
+ @conn.close if @conn
19
+ end
20
+
21
+ def connect
22
+ @conn.close if @conn
23
+ @conn = MongoReplicaSetClient.new(["%s:%s" % [@rs.primary.host, @rs.primary.port]])
24
+ end
25
+
26
+ def test_pool_resources_are_reused
27
+ handles_before_refresh = count_open_file_handles
28
+ 10.times do
29
+ @conn.hard_refresh!
30
+ end
31
+ assert_equal handles_before_refresh, count_open_file_handles
32
+ end
33
+
34
+ def test_pool_connectability_after_cycling_members
35
+ db = @conn['sample-db']
36
+
37
+ assert_equal db.collection_names, []
38
+ old_primary = @@cluster.primary
39
+ @conn["admin"].command step_down_command rescue nil
40
+ old_primary.stop
41
+
42
+ rescue_connection_failure do
43
+ db.collection_names
44
+ end
45
+
46
+ # We should be reconnected to the new master now
47
+ assert_equal db.collection_names, []
48
+
49
+ # Start up the old primary
50
+ old_primary.start
51
+
52
+ # Stop the new primary
53
+ primary = @@cluster.primary
54
+ @conn["admin"].command step_down_command rescue nil
55
+ primary.stop
56
+
57
+ # Wait for primary failover
58
+ rescue_connection_failure do
59
+ db.collection_names
60
+ end
61
+
62
+ # Reconnect and verify that we can read again
63
+ assert_equal db.collection_names, []
64
+ end
65
+ end
@@ -244,14 +244,103 @@ class TestCollection < Test::Unit::TestCase
244
244
  assert_equal error_docs, invalid_docs
245
245
  end
246
246
 
247
+ def limited_collection
248
+ conn = standard_connection(:connect => false)
249
+ admin_db = Object.new
250
+ admin_db.expects(:command).returns({
251
+ 'ok' => 1,
252
+ 'ismaster' => 1,
253
+ 'maxBsonObjectSize' => 1024,
254
+ 'maxMessageSizeBytes' => 3 * 1024
255
+ })
256
+ conn.expects(:[]).with('admin').returns(admin_db)
257
+ conn.connect
258
+ return conn.db(MONGO_TEST_DB)["test"]
259
+ end
260
+
247
261
  def test_maximum_insert_size
248
262
  docs = []
249
- 16.times do
250
- docs << {'foo' => 'a' * 1024 * 1024}
263
+ 3.times do
264
+ docs << {'foo' => 'a' * 950}
265
+ end
266
+ assert_equal limited_collection.insert(docs).length, 3
267
+ end
268
+
269
+ def test_maximum_document_size
270
+ assert_raise InvalidDocument do
271
+ limited_collection.insert({'foo' => 'a' * 1024})
272
+ end
273
+ end
274
+
275
+ def test_maximum_message_size
276
+ docs = []
277
+ 4.times do
278
+ docs << {'foo' => 'a' * 950}
251
279
  end
252
280
 
253
281
  assert_raise InvalidOperation do
254
- @@test.insert(docs)
282
+ limited_collection.insert(docs)
283
+ end
284
+ end
285
+
286
+ def test_maximum_save_size
287
+ assert limited_collection.save({'foo' => 'a' * 950})
288
+ assert_raise InvalidDocument do
289
+ limited_collection.save({'foo' => 'a' * 1024})
290
+ end
291
+ end
292
+
293
+ def test_maximum_remove_size
294
+ assert limited_collection.remove({'foo' => 'a' * 950})
295
+ assert_raise InvalidDocument do
296
+ limited_collection.remove({'foo' => 'a' * 1024})
297
+ end
298
+ end
299
+
300
+ def test_maximum_update_size
301
+ assert_raise InvalidDocument do
302
+ limited_collection.update(
303
+ {'foo' => 'a' * 1024},
304
+ {'foo' => 'a' * 950}
305
+ )
306
+ end
307
+
308
+ assert_raise InvalidDocument do
309
+ limited_collection.update(
310
+ {'foo' => 'a' * 950},
311
+ {'foo' => 'a' * 1024}
312
+ )
313
+ end
314
+
315
+ assert_raise InvalidDocument do
316
+ limited_collection.update(
317
+ {'foo' => 'a' * 1024},
318
+ {'foo' => 'a' * 1024}
319
+ )
320
+ end
321
+
322
+ assert limited_collection.update(
323
+ {'foo' => 'a' * 950},
324
+ {'foo' => 'a' * 950}
325
+ )
326
+ end
327
+
328
+ def test_maximum_query_size
329
+ assert limited_collection.find({'foo' => 'a' * 950}).to_a
330
+ assert limited_collection.find(
331
+ {'foo' => 'a' * 950},
332
+ {:fields => {'foo' => 'a' * 950}}
333
+ ).to_a
334
+
335
+ assert_raise InvalidDocument do
336
+ limited_collection.find({'foo' => 'a' * 1024}).to_a
337
+ end
338
+
339
+ assert_raise InvalidDocument do
340
+ limited_collection.find(
341
+ {'foo' => 'a' * 950},
342
+ {:fields => {'foo' => 'a' * 1024}}
343
+ ).to_a
255
344
  end
256
345
  end
257
346
 
@@ -269,11 +269,24 @@ class TestConnection < Test::Unit::TestCase
269
269
  if conn.server_version > "1.7.2"
270
270
  assert_equal conn['admin'].command({:ismaster => 1})['maxBsonObjectSize'], conn.max_bson_size
271
271
  end
272
+ end
273
+
274
+ def test_max_message_size_value
275
+ conn = standard_connection(:connect => false)
272
276
 
277
+ admin_db = Object.new
278
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1, 'maxMessageSizeBytes' => 20_000_000})
279
+ conn.expects(:[]).with('admin').returns(admin_db)
273
280
  conn.connect
274
- doc = {'n' => 'a' * (conn.max_bson_size)}
275
- assert_raise InvalidDocument do
276
- assert BSON::BSON_CODER.serialize(doc, false, true, @client.max_bson_size)
281
+
282
+ assert_equal 20_000_000, conn.max_message_size
283
+
284
+ conn = standard_connection
285
+ maxMessageSizeBytes = conn['admin'].command({:ismaster => 1})['maxMessageSizeBytes']
286
+ if conn.server_version.to_s[/([^-]+)/,1] >= "2.4.0"
287
+ assert_equal 48_000_000, maxMessageSizeBytes
288
+ elsif conn.server_version > "2.3.2"
289
+ assert_equal conn.max_bson_size, maxMessageSizeBytes
277
290
  end
278
291
  end
279
292
 
@@ -288,6 +301,17 @@ class TestConnection < Test::Unit::TestCase
288
301
  assert_equal Mongo::DEFAULT_MAX_BSON_SIZE, conn.max_bson_size
289
302
  end
290
303
 
304
+ def test_max_message_size_with_no_reported_max_size
305
+ conn = standard_connection(:connect => false)
306
+
307
+ admin_db = Object.new
308
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
309
+ conn.expects(:[]).with('admin').returns(admin_db)
310
+
311
+ conn.connect
312
+ assert_equal Mongo::DEFAULT_MAX_MESSAGE_SIZE, conn.max_message_size
313
+ end
314
+
291
315
  def test_connection_activity
292
316
  conn = standard_connection
293
317
  assert conn.active?
@@ -365,7 +389,7 @@ class TestConnection < Test::Unit::TestCase
365
389
  @con.expects(:checkout_writer).raises(SystemStackError)
366
390
  @con.expects(:close)
367
391
  begin
368
- @coll.insert({:foo => "bar"}, :safe => true)
392
+ @coll.insert({:foo => "bar"}, :w => 1)
369
393
  rescue SystemStackError
370
394
  end
371
395
  end
@@ -396,11 +420,11 @@ class TestConnection < Test::Unit::TestCase
396
420
  assert_equal 0, @con.primary_pool.checked_out.size
397
421
  end
398
422
 
399
- should "release connection if an exception is raised on send_with_safe_check" do
423
+ should "release connection if an exception is raised on write concern :w => 1" do
400
424
  @con.stubs(:receive).raises(ConnectionFailure)
401
425
  assert_equal 0, @con.primary_pool.checked_out.size
402
426
  assert_raise ConnectionFailure do
403
- @coll.insert({:test => "insert"}, :safe => true)
427
+ @coll.insert({:test => "insert"}, :w => 1)
404
428
  end
405
429
  assert_equal 0, @con.primary_pool.checked_out.size
406
430
  end
@@ -575,6 +575,17 @@ HERE
575
575
  end
576
576
  end
577
577
 
578
+ def test_named_hint
579
+ name = @@coll.create_index('a', :name => 'named_index')
580
+ begin
581
+ assert_nil @@coll.hint
582
+ assert_equal 1, @@coll.find({'a' => 1}, :named_hint => 'named_index').to_a.size
583
+ assert_equal 1, @@coll.find({'a' => 1}, :hint => 'a', :named_hint => "bad_hint").to_a.size
584
+ ensure
585
+ @@coll.drop_index('named_index')
586
+ end
587
+ end
588
+
578
589
  def test_hash_default_value_id
579
590
  val = Hash.new(0)
580
591
  val["x"] = 5
@@ -15,8 +15,31 @@ class TestTimeout < Test::Unit::TestCase
15
15
  assert_raise Mongo::OperationTimeout do
16
16
  admin.command(command)
17
17
  end
18
+ end
19
+
20
+ def test_external_timeout_does_not_leave_socket_in_bad_state
21
+ client = Mongo::MongoClient.new
22
+ db = client['testdb']
23
+ coll = db['testcoll']
24
+
25
+ # prepare the database
26
+ coll.drop
27
+ coll.insert({:a => 1})
18
28
 
29
+ # use external timeout to mangle socket
30
+ begin
31
+ Timeout::timeout(1) do
32
+ db.command({:eval => "sleep(1500)"})
33
+ end
34
+ rescue Timeout::Error => ex
35
+ #puts "Thread timed out and has now mangled the socket"
36
+ end
37
+
38
+ assert_nothing_raised do
39
+ coll.find_one
40
+ end
19
41
  end
42
+
20
43
  =begin
21
44
  def test_ssl_op_timeout
22
45
  connection = standard_connection(:op_timeout => 1, :ssl => true)
@@ -128,4 +128,73 @@ class URITest < Test::Unit::TestCase
128
128
  assert_equal true, parser.journal
129
129
  assert_equal true, parser.safe
130
130
  end
131
+
132
+ def test_read_preference_option_primary
133
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=primary")
134
+ assert_equal :primary, parser.readpreference
135
+ end
136
+
137
+ def test_read_preference_option_primary_preferred
138
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=primaryPreferred")
139
+ assert_equal :primary_preferred, parser.readpreference
140
+ end
141
+
142
+ def test_read_preference_option_secondary
143
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=secondary")
144
+ assert_equal :secondary, parser.readpreference
145
+ end
146
+
147
+ def test_read_preference_option_secondary_preferred
148
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=secondaryPreferred")
149
+ assert_equal :secondary_preferred, parser.readpreference
150
+ end
151
+
152
+ def test_read_preference_option_nearest
153
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=nearest")
154
+ assert_equal :nearest, parser.readpreference
155
+ end
156
+
157
+ def test_read_preference_option_with_invalid
158
+ assert_raise_error MongoArgumentError do
159
+ Mongo::URIParser.new("mongodb://localhost:27018?readPreference=invalid")
160
+ end
161
+ end
162
+
163
+ def test_read_preference_connection_options
164
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?replicaset=test&readPreference=nearest")
165
+ assert_equal :nearest, parser.connection_options[:read]
166
+ end
167
+
168
+ def test_read_preference_connection_options_prefers_preference_over_slaveok
169
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?replicaset=test&readPreference=nearest&slaveok=true")
170
+ assert_equal :nearest, parser.connection_options[:read]
171
+ end
172
+
173
+ def test_read_preference_when_no_replica_set
174
+ parser = Mongo::URIParser.new("mongodb://localhost:27018?readPreference=nearest")
175
+ assert_nil parser.connection_options[:read]
176
+ end
177
+
178
+ def test_connection_when_sharded_with_no_options
179
+ parser = Mongo::URIParser.new("mongodb://localhost:27017,localhost:27018")
180
+ client = parser.connection({}, false, true)
181
+ assert_equal [[ "localhost", 27017 ], [ "localhost", 27018 ]], client.seeds
182
+ assert_true client.mongos?
183
+ end
184
+
185
+ def test_connection_when_sharded_with_options
186
+ parser = Mongo::URIParser.new("mongodb://localhost:27017,localhost:27018")
187
+ client = parser.connection({ :refresh_interval => 10 }, false, true)
188
+ assert_equal [[ "localhost", 27017 ], [ "localhost", 27018 ]], client.seeds
189
+ assert_equal 10, client.refresh_interval
190
+ assert_true client.mongos?
191
+ end
192
+
193
+ def test_connection_when_sharded_with_uri_options
194
+ parser = Mongo::URIParser.new("mongodb://localhost:27017,localhost:27018?readPreference=nearest")
195
+ client = parser.connection({}, false, true)
196
+ assert_equal [[ "localhost", 27017 ], [ "localhost", 27018 ]], client.seeds
197
+ assert_equal :nearest, client.read
198
+ assert_true client.mongos?
199
+ end
131
200
  end
@@ -28,28 +28,6 @@ class ClientTest < Test::Unit::TestCase
28
28
  end
29
29
  end
30
30
 
31
- def test_reconnect_method_override
32
- rescue_connection_failure do
33
- @client = MongoReplicaSetClient.new(@rs.repl_set_seeds)
34
- end
35
-
36
- MongoReplicaSetClient.any_instance.expects(:connect)
37
- MongoClient.any_instance.expects(:connect).never
38
- assert_nothing_raised Mongo::ConnectionFailure do
39
- @client.reconnect
40
- end
41
- end
42
-
43
- def test_primary_method_override
44
- rescue_connection_failure do
45
- @client = MongoReplicaSetClient.new(@rs.repl_set_seeds)
46
- end
47
-
48
- MongoReplicaSetClient.any_instance.expects(:read_primary?)
49
- MongoClient.any_instance.expects(:read_primary?).never
50
- @client.primary?
51
- end
52
-
53
31
  def test_connect_with_first_secondary_node_terminated
54
32
  @rs.secondaries.first.stop
55
33
 
@@ -13,12 +13,18 @@ class ReplicaSetCursorTest < Test::Unit::TestCase
13
13
 
14
14
  def test_cursors_get_closed_secondary
15
15
  setup_client(:secondary)
16
- assert_cursor_count
16
+ assert_cursor_count(:secondary)
17
+ end
18
+
19
+ def test_cusors_get_closed_secondary_query
20
+ setup_client(:primary, :secondary)
21
+ assert_cursor_count(:secondary)
17
22
  end
18
23
 
19
24
  private
20
25
 
21
- def setup_client(read=:primary)
26
+ def setup_client(read=:primary, route_read=nil)
27
+ route_read ||= read
22
28
  # Setup ReplicaSet Connection
23
29
  @client = MongoReplicaSetClient.new(@rs.repl_set_seeds, :read => read)
24
30
 
@@ -35,7 +41,7 @@ class ReplicaSetCursorTest < Test::Unit::TestCase
35
41
 
36
42
  # Setup Direct Connections
37
43
  @primary = Mongo::MongoClient.new(*@client.manager.primary)
38
- @read = Mongo::MongoClient.new(*@client.manager.read)
44
+ @read = Mongo::MongoClient.new(*@client.manager.read_pool(route_read).host_port)
39
45
  end
40
46
 
41
47
  def cursor_count(client)
@@ -46,12 +52,12 @@ class ReplicaSetCursorTest < Test::Unit::TestCase
46
52
  client['admin'].command({:serverStatus => 1})['opcounters']['query']
47
53
  end
48
54
 
49
- def assert_cursor_count
55
+ def assert_cursor_count(read=:primary)
50
56
  before_primary_cursor = cursor_count(@primary)
51
57
  before_read_cursor = cursor_count(@read)
52
58
  before_read_query = query_count(@read)
53
59
 
54
- @coll.find.limit(2).to_a
60
+ @coll.find({}, :read => read).limit(2).to_a
55
61
 
56
62
  after_primary_cursor = cursor_count(@primary)
57
63
  after_read_cursor = cursor_count(@read)