mongo 1.8.2 → 1.8.3.rc0

Sign up to get free protection for your applications and to get access to all the features.
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)