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
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)