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
File without changes
@@ -0,0 +1,13 @@
1
+ require 'test_helper'
2
+
3
+ # mock test case to shutdown cluster for rake test:replica_set, must be last by file name sort order
4
+ class ZClusterShutdownTest < Test::Unit::TestCase
5
+ def setup
6
+ ensure_cluster(:rs)
7
+ end
8
+
9
+ def test_cluster_shutdown
10
+ @@force_shutdown = true
11
+ end
12
+ end
13
+
@@ -6,28 +6,24 @@ class Cursor
6
6
  end
7
7
 
8
8
  class BasicTest < Test::Unit::TestCase
9
-
9
+
10
10
  def setup
11
11
  ensure_cluster(:sc)
12
- end
13
-
14
- def self.shutdown
15
- @@cluster.stop
16
- @@cluster.clobber
12
+ @document = { "name" => "test_user" }
13
+ @seeds = @sc.mongos_seeds
17
14
  end
18
15
 
19
16
  # TODO member.primary? ==> true
20
17
  def test_connect
21
- seeds = @sc.mongos_seeds
22
- @client = MongoShardedClient.new(seeds)
18
+ @client = MongoShardedClient.new(@seeds)
23
19
  assert @client.connected?
24
- assert_equal(seeds.size, @client.seeds.size)
25
- probe(seeds.size)
20
+ assert_equal(@seeds.size, @client.seeds.size)
21
+ probe(@seeds.size)
26
22
  @client.close
27
23
  end
28
24
 
29
25
  def test_connect_from_standard_client
30
- mongos = @sc.mongos_seeds.first
26
+ mongos = @seeds.first
31
27
  @client = MongoClient.new(*mongos.split(':'))
32
28
  assert @client.connected?
33
29
  assert @client.mongos?
@@ -35,26 +31,48 @@ class BasicTest < Test::Unit::TestCase
35
31
  end
36
32
 
37
33
  def test_read_from_client
38
- host, port = @sc.mongos_seeds.first.split(':')
39
- tags = [{:dc => "mongolia"}]
34
+ host, port = @seeds.first.split(':')
35
+ tags = [{:dc => "mongolia"}]
40
36
  @client = MongoClient.new(host, port, {:read => :secondary, :tag_sets => tags})
41
37
  assert @client.connected?
42
38
  cursor = Cursor.new(@client[MONGO_TEST_DB]['whatever'], {})
43
39
  assert_equal cursor.construct_query_spec['$readPreference'], {:mode => :secondary, :tags => tags}
44
40
  end
45
41
 
42
+ def test_find_one_with_read_secondary
43
+ @client = MongoShardedClient.new(@seeds, { :read => :secondary })
44
+ @client[MONGO_TEST_DB]["users"].insert([ @document ])
45
+ assert_equal @client[MONGO_TEST_DB]['users'].find_one["name"], "test_user"
46
+ end
47
+
48
+ def test_find_one_with_read_secondary_preferred
49
+ @client = MongoShardedClient.new(@seeds, { :read => :secondary_preferred })
50
+ @client[MONGO_TEST_DB]["users"].insert([ @document ])
51
+ assert_equal @client[MONGO_TEST_DB]['users'].find_one["name"], "test_user"
52
+ end
53
+
54
+ def test_find_one_with_read_primary
55
+ @client = MongoShardedClient.new(@seeds, { :read => :primary })
56
+ @client[MONGO_TEST_DB]["users"].insert([ @document ])
57
+ assert_equal @client[MONGO_TEST_DB]['users'].find_one["name"], "test_user"
58
+ end
59
+
60
+ def test_find_one_with_read_primary_preferred
61
+ @client = MongoShardedClient.new(@seeds, { :read => :primary_preferred })
62
+ @client[MONGO_TEST_DB]["users"].insert([ @document ])
63
+ assert_equal @client[MONGO_TEST_DB]['users'].find_one["name"], "test_user"
64
+ end
65
+
46
66
  def test_read_from_sharded_client
47
- seeds = @sc.mongos_seeds
48
- tags = [{:dc => "mongolia"}]
49
- @client = MongoShardedClient.new(seeds, {:read => :secondary, :tag_sets => tags})
67
+ tags = [{:dc => "mongolia"}]
68
+ @client = MongoShardedClient.new(@seeds, {:read => :secondary, :tag_sets => tags})
50
69
  assert @client.connected?
51
70
  cursor = Cursor.new(@client[MONGO_TEST_DB]['whatever'], {})
52
71
  assert_equal cursor.construct_query_spec['$readPreference'], {:mode => :secondary, :tags => tags}
53
72
  end
54
73
 
55
74
  def test_hard_refresh
56
- seeds = @sc.mongos_seeds
57
- @client = MongoShardedClient.new(seeds)
75
+ @client = MongoShardedClient.new(@seeds)
58
76
  assert @client.connected?
59
77
  @client.hard_refresh!
60
78
  assert @client.connected?
@@ -62,44 +80,41 @@ class BasicTest < Test::Unit::TestCase
62
80
  end
63
81
 
64
82
  def test_reconnect
65
- seeds = @sc.mongos_seeds
66
- @client = MongoShardedClient.new(seeds)
83
+ @client = MongoShardedClient.new(@seeds)
67
84
  assert @client.connected?
68
85
  router = @sc.servers(:routers).first
69
86
  router.stop
70
- probe(seeds.size)
87
+ probe(@seeds.size)
71
88
  assert @client.connected?
72
89
  @client.close
73
90
  end
74
91
 
75
92
  def test_all_down
76
- seeds = @sc.mongos_seeds
77
- @client = MongoShardedClient.new(seeds)
93
+ @client = MongoShardedClient.new(@seeds)
78
94
  assert @client.connected?
79
95
  @sc.servers(:routers).each{|router| router.stop}
80
96
  assert_raises Mongo::ConnectionFailure do
81
- probe(seeds.size)
97
+ probe(@seeds.size)
82
98
  end
83
99
  assert_false @client.connected?
84
100
  @client.close
85
101
  end
86
102
 
87
103
  def test_cycle
88
- seeds = @sc.mongos_seeds
89
- @client = MongoShardedClient.new(seeds)
104
+ @client = MongoShardedClient.new(@seeds)
90
105
  assert @client.connected?
91
106
  routers = @sc.servers(:routers)
92
107
  while routers.size > 0 do
93
108
  rescue_connection_failure do
94
- probe(seeds.size)
109
+ probe(@seeds.size)
95
110
  end
96
- probe(seeds.size)
111
+ probe(@seeds.size)
97
112
  router = routers.detect{|r| r.port == @client.manager.primary.last}
98
113
  routers.delete(router)
99
114
  router.stop
100
115
  end
101
116
  assert_raises Mongo::ConnectionFailure do
102
- probe(seeds.size)
117
+ probe(@seeds.size)
103
118
  end
104
119
  assert_false @client.connected?
105
120
  routers = @sc.servers(:routers).reverse
@@ -107,9 +122,9 @@ class BasicTest < Test::Unit::TestCase
107
122
  r.start
108
123
  @client.hard_refresh!
109
124
  rescue_connection_failure do
110
- probe(seeds.size)
125
+ probe(@seeds.size)
111
126
  end
112
- probe(seeds.size)
127
+ probe(@seeds.size)
113
128
  end
114
129
  @client.close
115
130
  end
@@ -119,5 +134,4 @@ class BasicTest < Test::Unit::TestCase
119
134
  def probe(size)
120
135
  assert_equal(size, @client['config']['mongos'].find.to_a.size)
121
136
  end
122
-
123
137
  end
@@ -1,4 +1,16 @@
1
1
  require 'rubygems'
2
+ # SimpleCov must load before our code - A coverage report summary line will print after each test suite
3
+ if RUBY_VERSION >= '1.9.0' && RUBY_ENGINE == 'ruby'
4
+ if ENV.key?('COVERAGE')
5
+ require 'simplecov'
6
+ SimpleCov.start do
7
+ add_group "Mongo", 'lib/mongo'
8
+ add_group "BSON", 'lib/bson'
9
+ add_filter "/test/"
10
+ end
11
+ end
12
+ end
13
+ gem 'test-unit' # Do NOT remove this line - gem version is needed for Test::Unit::TestCase.shutdown
2
14
  require 'test/unit'
3
15
  require 'tools/mongo_config'
4
16
 
@@ -7,7 +19,7 @@ class Test::Unit::TestCase
7
19
  TEST_DATA = File.join(File.dirname(__FILE__), 'data')
8
20
 
9
21
  def ensure_cluster(kind=nil, opts={})
10
- @@cluster ||= false
22
+ @@cluster ||= nil
11
23
 
12
24
  unless @@cluster
13
25
  if kind == :rs
@@ -25,6 +37,17 @@ class Test::Unit::TestCase
25
37
  config = Mongo::Config.cluster(cluster_opts)
26
38
  #debug 1, config
27
39
  @@cluster = Mongo::Config::ClusterManager.new(config)
40
+
41
+ Test::Unit::TestCase.class_eval do
42
+ @@force_shutdown = false
43
+
44
+ def self.shutdown
45
+ if @@force_shutdown || /rake_test_loader/ !~ $0
46
+ @@cluster.stop
47
+ @@cluster.clobber
48
+ end
49
+ end
50
+ end
28
51
  end
29
52
 
30
53
  @@cluster.start
@@ -143,6 +166,8 @@ class Test::Unit::TestCase
143
166
  socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
144
167
  socket.stubs(:close)
145
168
  socket.stubs(:closed?)
169
+ socket.stubs(:checkin)
170
+ socket.stubs(:pool)
146
171
  socket
147
172
  end
148
173
 
@@ -5,7 +5,7 @@ class TestThreading < Test::Unit::TestCase
5
5
  include Mongo
6
6
 
7
7
  def setup
8
- @client = standard_connection(:pool_size => 50, :pool_timeout => 60)
8
+ @client = standard_connection(:pool_size => 10, :pool_timeout => 30)
9
9
  @db = @client.db(MONGO_TEST_DB)
10
10
  @coll = @db.collection('thread-test-collection')
11
11
  @coll.drop
@@ -58,22 +58,23 @@ class TestThreading < Test::Unit::TestCase
58
58
  threads.each {|thread| thread.join}
59
59
  end
60
60
 
61
- def test_count
61
+ def test_concurrent_find
62
+ n_threads = 50
63
+
62
64
  1000.times do |i|
63
- @coll.insert({ "x" => i })
65
+ @coll.insert({ "x" => "a" })
64
66
  end
65
67
 
66
68
  threads = []
67
- 10.times do |i|
69
+ n_threads.times do |i|
68
70
  threads << Thread.new do
69
71
  sum = 0
70
- @coll.find().each do |document|
71
- sum += document["x"]
72
- end
73
- assert_equal 499500, sum
72
+ @coll.find.to_a.size
74
73
  end
75
74
  end
76
75
 
77
- threads.each {|thread| thread.join}
76
+ thread_values = threads.map(&:value)
77
+ assert thread_values.all?{|v| v == 1000}
78
+ assert_equal thread_values.size, n_threads
78
79
  end
79
80
  end
@@ -145,6 +145,7 @@ module Mongo
145
145
  def self.port_available?(port)
146
146
  ret = false
147
147
  socket = Socket.new(Socket::Constants::AF_INET, Socket::Constants::SOCK_STREAM, 0)
148
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
148
149
  sockaddr = Socket.sockaddr_in(port, '0.0.0.0')
149
150
  begin
150
151
  socket.bind(sockaddr)
@@ -211,7 +212,10 @@ module Mongo
211
212
  false
212
213
  end
213
214
  # cleanup lock if unclean shutdown
214
- File.delete(File.join(@config[:dbpath], 'mongod.lock')) if @config[:dbpath]
215
+ begin
216
+ File.delete(File.join(@config[:dbpath], 'mongod.lock')) if @config[:dbpath]
217
+ rescue Errno::ENOENT
218
+ end
215
219
  end
216
220
 
217
221
  def wait
@@ -550,7 +554,7 @@ module Mongo
550
554
  end
551
555
 
552
556
  def clobber
553
- system "rm -fr #{@config[:dbpath]}/*"
557
+ FileUtils.rm_rf @config[:dbpath]
554
558
  self
555
559
  end
556
560
  end
@@ -37,7 +37,7 @@ class CollectionTest < Test::Unit::TestCase
37
37
  @client = MongoClient.new('localhost', 27017, :logger => @logger, :connect => false)
38
38
  @db = @client['testing']
39
39
  @coll = @db.collection('books')
40
- @client.expects(:checkout_reader).returns(mock(:pool))
40
+ @client.expects(:checkout_reader).returns(new_mock_socket)
41
41
  @client.expects(:receive_message).with do |op, msg, log, sock|
42
42
  op == 2004
43
43
  end.returns([[], 0, 0])
@@ -13,43 +13,50 @@ class GridTest < Test::Unit::TestCase
13
13
  @files = mock()
14
14
  @chunks = mock()
15
15
 
16
- @db.expects(:[]).with('fs.files').returns(@files)
17
- @db.expects(:[]).with('fs.chunks').returns(@chunks)
16
+ @db.stubs(:[]).with('fs.files').returns(@files)
17
+ @db.stubs(:[]).with('fs.chunks').returns(@chunks)
18
18
  @db.stubs(:safe)
19
19
  @db.stubs(:read).returns(:primary)
20
20
  end
21
21
 
22
- context "Grid classe with standard connections" do
22
+ context "Grid classes with standard connections" do
23
23
  setup do
24
- @client.expects(:class).returns(MongoClient)
25
- @client.expects(:read_primary?).returns(true)
24
+ @chunks.expects(:ensure_index)
26
25
  end
27
26
 
28
27
  should "create indexes for Grid" do
29
- @chunks.expects(:create_index)
30
28
  Grid.new(@db)
31
29
  end
32
30
 
33
31
  should "create indexes for GridFileSystem" do
34
- @files.expects(:create_index)
35
- @chunks.expects(:create_index)
32
+ @files.expects(:ensure_index)
36
33
  GridFileSystem.new(@db)
37
34
  end
38
35
  end
39
36
 
40
37
  context "Grid classes with slave connection" do
41
38
  setup do
42
- @client.expects(:class).twice.returns(MongoClient)
43
- @client.expects(:read_primary?).returns(false)
39
+ @chunks.stubs(:ensure_index).raises(Mongo::ConnectionFailure)
40
+ @files.stubs(:ensure_index).raises(Mongo::ConnectionFailure)
44
41
  end
45
42
 
46
43
  should "not create indexes for Grid" do
47
- Grid.new(@db)
44
+ grid = Grid.new(@db)
45
+ data = "hello world!"
46
+ assert_raise Mongo::ConnectionFailure do
47
+ grid.put(data)
48
+ end
48
49
  end
49
50
 
50
51
  should "not create indexes for GridFileSystem" do
51
- GridFileSystem.new(@db)
52
+ gridfs = GridFileSystem.new(@db)
53
+ data = "hello world!"
54
+ assert_raise Mongo::ConnectionFailure do
55
+ gridfs.open('image.jpg', 'w') do |f|
56
+ f.write data
57
+ end
58
+ end
52
59
  end
53
60
  end
54
61
  end
55
- end
62
+ end
@@ -0,0 +1,32 @@
1
+ require "test_helper"
2
+
3
+ class MongoShardedClientTest < Test::Unit::TestCase
4
+ include Mongo
5
+
6
+ def setup
7
+ ENV["MONGODB_URI"] = nil
8
+ end
9
+
10
+ def test_initialize_with_single_mongos_uri
11
+ ENV["MONGODB_URI"] = "mongodb://localhost:27017"
12
+ client = MongoShardedClient.new
13
+ assert_equal [[ "localhost", 27017 ]], client.seeds
14
+ end
15
+
16
+ def test_initialize_with_multiple_mongos_uris
17
+ ENV["MONGODB_URI"] = "mongodb://localhost:27017,localhost:27018"
18
+ client = MongoShardedClient.new
19
+ assert_equal [[ "localhost", 27017 ], [ "localhost", 27018 ]], client.seeds
20
+ end
21
+
22
+ def test_from_uri_with_string
23
+ client = MongoShardedClient.from_uri("mongodb://localhost:27017,localhost:27018")
24
+ assert_equal [[ "localhost", 27017 ], [ "localhost", 27018 ]], client.seeds
25
+ end
26
+
27
+ def test_from_uri_with_env_variable
28
+ ENV["MONGODB_URI"] = "mongodb://localhost:27017,localhost:27018"
29
+ client = MongoShardedClient.from_uri
30
+ assert_equal [[ "localhost", 27017 ], [ "localhost", 27018 ]], client.seeds
31
+ end
32
+ end
@@ -22,21 +22,33 @@ class PoolManagerTest < Test::Unit::TestCase
22
22
  @client.stubs(:replica_set_name).returns(nil)
23
23
  @client.stubs(:log)
24
24
  @arbiters = ['localhost:27020']
25
- @hosts = ['localhost:27017', 'localhost:27018', 'localhost:27019',
26
- 'localhost:27020']
25
+ @hosts = [
26
+ 'localhost:27017',
27
+ 'localhost:27018',
28
+ 'localhost:27019',
29
+ 'localhost:27020'
30
+ ]
31
+
32
+ @ismaster = {
33
+ 'hosts' => @hosts,
34
+ 'arbiters' => @arbiters,
35
+ 'maxMessageSizeBytes' => 1024 * 2.5,
36
+ 'maxBsonObjectSize' => 1024
37
+ }
27
38
  end
28
39
 
29
40
  should "populate pools correctly" do
30
41
 
31
42
  @db.stubs(:command).returns(
32
43
  # First call to get a socket.
33
- {'ismaster' => true, 'hosts' => @hosts, 'arbiters' => @arbiters},
44
+ @ismaster.merge({'ismaster' => true}),
34
45
 
35
46
  # Subsequent calls to configure pools.
36
- {'ismaster' => true, 'hosts' => @hosts, 'arbiters' => @arbiters},
37
- {'secondary' => true, 'hosts' => @hosts, 'arbiters' => @arbiters},
38
- {'secondary' => true, 'hosts' => @hosts, 'arbiters' => @arbiters},
39
- {'arbiterOnly' => true, 'hosts' => @hosts, 'arbiters' => @arbiters})
47
+ @ismaster.merge({'ismaster' => true}),
48
+ @ismaster.merge({'secondary' => true, 'maxMessageSizeBytes' => 700}),
49
+ @ismaster.merge({'secondary' => true, 'maxBsonObjectSize' => 500}),
50
+ @ismaster.merge({'arbiterOnly' => true})
51
+ )
40
52
 
41
53
  seeds = [['localhost', 27017]]
42
54
  manager = Mongo::PoolManager.new(@client, seeds)
@@ -45,22 +57,24 @@ class PoolManagerTest < Test::Unit::TestCase
45
57
  assert_equal ['localhost', 27017], manager.primary
46
58
  assert_equal 27017, manager.primary_pool.port
47
59
  assert_equal 2, manager.secondaries.length
48
- assert_equal 27018, manager.secondary_pools[0].port
49
- assert_equal 27019, manager.secondary_pools[1].port
60
+ assert_equal [27018, 27019], manager.secondary_pools.map(&:port).sort
50
61
  assert_equal [['localhost', 27020]], manager.arbiters
62
+ assert_equal 500, manager.max_bson_size
63
+ assert_equal 700 , manager.max_message_size
51
64
  end
52
65
 
53
66
  should "populate pools with single unqueryable seed" do
54
67
 
55
68
  @db.stubs(:command).returns(
56
69
  # First call to recovering node
57
- {'ismaster' => false, 'secondary' => false, 'hosts' => @hosts, 'arbiters' => @arbiters},
70
+ @ismaster.merge({'ismaster' => false, 'secondary' => false}),
58
71
 
59
72
  # Subsequent calls to configure pools.
60
- {'ismaster' => false, 'secondary' => false, 'hosts' => @hosts, 'arbiters' => @arbiters},
61
- {'ismaster' => true, 'hosts' => @hosts, 'arbiters' => @arbiters},
62
- {'secondary' => true, 'hosts' => @hosts, 'arbiters' => @arbiters},
63
- {'arbiterOnly' => true, 'hosts' => @hosts, 'arbiters' => @arbiters})
73
+ @ismaster.merge({'ismaster' => false, 'secondary' => false}),
74
+ @ismaster.merge({'ismaster' => true}),
75
+ @ismaster.merge({'secondary' => true}),
76
+ @ismaster.merge({'arbiterOnly' => true})
77
+ )
64
78
 
65
79
  seeds = [['localhost', 27017]]
66
80
  manager = Mongo::PoolManager.new(@client, seeds)