mongo 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/README.md +9 -6
  2. data/Rakefile +3 -4
  3. data/docs/HISTORY.md +20 -2
  4. data/docs/READ_PREFERENCE.md +39 -0
  5. data/docs/RELEASES.md +1 -1
  6. data/docs/REPLICA_SETS.md +23 -2
  7. data/docs/TAILABLE_CURSORS.md +51 -0
  8. data/docs/TUTORIAL.md +4 -4
  9. data/docs/WRITE_CONCERN.md +5 -2
  10. data/lib/mongo.rb +7 -22
  11. data/lib/mongo/collection.rb +96 -29
  12. data/lib/mongo/connection.rb +107 -62
  13. data/lib/mongo/cursor.rb +136 -57
  14. data/lib/mongo/db.rb +26 -5
  15. data/lib/mongo/exceptions.rb +17 -1
  16. data/lib/mongo/gridfs/grid.rb +1 -1
  17. data/lib/mongo/repl_set_connection.rb +273 -156
  18. data/lib/mongo/util/logging.rb +42 -0
  19. data/lib/mongo/util/node.rb +183 -0
  20. data/lib/mongo/util/pool.rb +76 -13
  21. data/lib/mongo/util/pool_manager.rb +208 -0
  22. data/lib/mongo/util/ssl_socket.rb +38 -0
  23. data/lib/mongo/util/support.rb +9 -1
  24. data/lib/mongo/util/timeout.rb +42 -0
  25. data/lib/mongo/version.rb +3 -0
  26. data/mongo.gemspec +2 -2
  27. data/test/bson/binary_test.rb +1 -1
  28. data/test/bson/bson_string_test.rb +30 -0
  29. data/test/bson/bson_test.rb +6 -3
  30. data/test/bson/byte_buffer_test.rb +1 -1
  31. data/test/bson/hash_with_indifferent_access_test.rb +1 -1
  32. data/test/bson/json_test.rb +1 -1
  33. data/test/bson/object_id_test.rb +2 -18
  34. data/test/bson/ordered_hash_test.rb +38 -3
  35. data/test/bson/test_helper.rb +46 -0
  36. data/test/bson/timestamp_test.rb +32 -10
  37. data/test/collection_test.rb +89 -3
  38. data/test/connection_test.rb +35 -20
  39. data/test/cursor_test.rb +63 -2
  40. data/test/db_test.rb +12 -2
  41. data/test/pool_test.rb +21 -0
  42. data/test/replica_sets/connect_test.rb +26 -13
  43. data/test/replica_sets/connection_string_test.rb +1 -4
  44. data/test/replica_sets/count_test.rb +1 -0
  45. data/test/replica_sets/insert_test.rb +1 -0
  46. data/test/replica_sets/pooled_insert_test.rb +4 -1
  47. data/test/replica_sets/query_secondaries.rb +2 -1
  48. data/test/replica_sets/query_test.rb +2 -1
  49. data/test/replica_sets/read_preference_test.rb +43 -0
  50. data/test/replica_sets/refresh_test.rb +123 -0
  51. data/test/replica_sets/replication_ack_test.rb +9 -4
  52. data/test/replica_sets/rs_test_helper.rb +2 -2
  53. data/test/timeout_test.rb +14 -0
  54. data/test/tools/repl_set_manager.rb +134 -23
  55. data/test/unit/collection_test.rb +6 -8
  56. data/test/unit/connection_test.rb +4 -4
  57. data/test/unit/cursor_test.rb +23 -5
  58. data/test/unit/db_test.rb +2 -0
  59. data/test/unit/grid_test.rb +2 -0
  60. data/test/unit/node_test.rb +73 -0
  61. data/test/unit/pool_manager_test.rb +47 -0
  62. data/test/unit/read_test.rb +101 -0
  63. metadata +214 -138
  64. data/lib/mongo/test.rb +0 -20
  65. data/test/async/collection_test.rb +0 -224
  66. data/test/async/connection_test.rb +0 -24
  67. data/test/async/cursor_test.rb +0 -162
  68. data/test/async/worker_pool_test.rb +0 -99
  69. data/test/load/resque/load.rb +0 -21
  70. data/test/load/resque/processor.rb +0 -26
  71. data/test/load/unicorn/unicorn.rb +0 -29
  72. data/test/tools/load.rb +0 -58
  73. data/test/tools/sharding_manager.rb +0 -202
  74. data/test/tools/test.rb +0 -4
  75. data/test/unit/repl_set_connection_test.rb +0 -59
@@ -13,7 +13,7 @@ class TestConnection < Test::Unit::TestCase
13
13
  end
14
14
 
15
15
  def teardown
16
- @conn[MONGO_TEST_DB].get_last_error
16
+ @conn.close
17
17
  end
18
18
 
19
19
  def test_connection_failure
@@ -22,6 +22,20 @@ class TestConnection < Test::Unit::TestCase
22
22
  end
23
23
  end
24
24
 
25
+ # def test_connection_timeout
26
+ # passed = false
27
+ # begin
28
+ # t0 = Time.now
29
+ # Mongo::Connection.new('foo.bar', 27017, :connect_timeout => 3)
30
+ # rescue OperationTimeout
31
+ # passed = true
32
+ # t1 = Time.now
33
+ # end
34
+
35
+ # assert passed
36
+ # assert t1 - t0 < 4
37
+ # end
38
+
25
39
  def test_host_port_accessors
26
40
  assert_equal @conn.host, TEST_HOST
27
41
  assert_equal @conn.port, TEST_PORT
@@ -147,8 +161,8 @@ class TestConnection < Test::Unit::TestCase
147
161
  end
148
162
 
149
163
  def test_nodes
150
- db = Connection.multi([['foo', 27017], ['bar', 27018]], :connect => false)
151
- nodes = db.nodes
164
+ conn = Connection.multi([['foo', 27017], ['bar', 27018]], :connect => false)
165
+ nodes = conn.nodes
152
166
  assert_equal 2, nodes.length
153
167
  assert_equal ['foo', 27017], nodes[0]
154
168
  assert_equal ['bar', 27018], nodes[1]
@@ -176,35 +190,32 @@ class TestConnection < Test::Unit::TestCase
176
190
  end
177
191
 
178
192
  def test_max_bson_size_value
193
+ conn = standard_connection(:connect => false)
194
+
195
+ admin_db = Object.new
196
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1, 'maxBsonObjectSize' => 15_000_000})
197
+ conn.expects(:[]).with('admin').returns(admin_db)
198
+ conn.connect
199
+ assert_equal 15_000_000, conn.max_bson_size
200
+
179
201
  conn = standard_connection
180
202
  if conn.server_version > "1.7.2"
181
203
  assert_equal conn['admin'].command({:ismaster => 1})['maxBsonObjectSize'], conn.max_bson_size
182
204
  end
183
205
 
184
206
  conn.connect
185
- assert_equal BSON::BSON_CODER.max_bson_size, conn.max_bson_size
186
- doc = {'n' => 'a' * (BSON_CODER.max_bson_size - 11)}
207
+ doc = {'n' => 'a' * (conn.max_bson_size)}
187
208
  assert_raise InvalidDocument do
188
- assert BSON::BSON_CODER.serialize(doc)
189
- end
190
-
191
- limit = 7 * 1024 * 1024
192
- conn.stubs(:max_bson_size).returns(limit)
193
- conn.connect
194
- assert_equal limit, conn.max_bson_size
195
- assert_equal limit, BSON::BSON_CODER.max_bson_size
196
- doc = {'n' => 'a' * ((limit) - 11)}
197
- assert_raise_error InvalidDocument, "limited to #{limit}" do
198
- assert BSON::BSON_CODER.serialize(doc)
209
+ assert BSON::BSON_CODER.serialize(doc, false, true, @conn.max_bson_size)
199
210
  end
200
211
  end
201
212
 
202
- def test_max_bson_size_with_old_mongod
213
+ def test_max_bson_size_with_no_reported_max_size
203
214
  conn = standard_connection(:connect => false)
204
215
 
205
216
  admin_db = Object.new
206
- admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1}).twice
207
- conn.expects(:[]).with('admin').returns(admin_db).twice
217
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
218
+ conn.expects(:[]).with('admin').returns(admin_db)
208
219
 
209
220
  conn.connect
210
221
  assert_equal Mongo::DEFAULT_MAX_BSON_SIZE, BSON::BSON_CODER.max_bson_size
@@ -238,6 +249,10 @@ class TestConnection < Test::Unit::TestCase
238
249
  @conn.add_auth(@auth['db_name'], @auth['username'], @auth['password'])
239
250
  end
240
251
 
252
+ teardown do
253
+ @conn.clear_auths
254
+ end
255
+
241
256
  should "save the authentication" do
242
257
  assert_equal @auth, @conn.auths[0]
243
258
  end
@@ -300,7 +315,7 @@ class TestConnection < Test::Unit::TestCase
300
315
  fake_socket = Mocha::Mock.new
301
316
  fake_socket.stubs(:close).raises(IOError.new)
302
317
  fake_socket.stub_everything
303
- TCPSocket.expects(:new).returns(fake_socket)
318
+ TCPSocket.stubs(:new).returns(fake_socket)
304
319
 
305
320
  @con.primary_pool.checkout_new_socket
306
321
  assert_equal [], @con.primary_pool.close
@@ -2,8 +2,8 @@ require './test/test_helper'
2
2
  require 'logger'
3
3
 
4
4
  class CursorTest < Test::Unit::TestCase
5
-
6
5
  include Mongo
6
+ include Mongo::Constants
7
7
 
8
8
  @@connection = standard_connection
9
9
  @@db = @@connection.db(MONGO_TEST_DB)
@@ -16,11 +16,72 @@ class CursorTest < Test::Unit::TestCase
16
16
  @@coll_full_name = "#{MONGO_TEST_DB}.test"
17
17
  end
18
18
 
19
+ def test_alive
20
+ batch = []
21
+ 5000.times do |n|
22
+ batch << {:a => n}
23
+ end
24
+
25
+ @@coll.insert(batch)
26
+ cursor = @@coll.find
27
+ assert !cursor.alive?
28
+ cursor.next
29
+ assert cursor.alive?
30
+ cursor.close
31
+ assert !cursor.alive?
32
+ @@coll.remove
33
+ end
34
+
35
+ def test_add_and_remove_options
36
+ c = @@coll.find
37
+ assert_equal 0, c.options & OP_QUERY_EXHAUST
38
+ c.add_option(OP_QUERY_EXHAUST)
39
+ assert_equal OP_QUERY_EXHAUST, c.options & OP_QUERY_EXHAUST
40
+ c.remove_option(OP_QUERY_EXHAUST)
41
+ assert_equal 0, c.options & OP_QUERY_EXHAUST
42
+
43
+ c.next
44
+ assert_raise Mongo::InvalidOperation do
45
+ c.add_option(OP_QUERY_EXHAUST)
46
+ end
47
+
48
+ assert_raise Mongo::InvalidOperation do
49
+ c.add_option(OP_QUERY_EXHAUST)
50
+ end
51
+ end
52
+
53
+ def test_exhaust
54
+ if @@version >= "2.0"
55
+ @@coll.remove
56
+ data = "1" * 100_000
57
+ 10_000.times do |n|
58
+ @@coll.insert({:n => n, :data => data})
59
+ end
60
+
61
+ c = Cursor.new(@@coll)
62
+ c.add_option(OP_QUERY_EXHAUST)
63
+ assert_equal @@coll.count, c.to_a.size
64
+ assert c.closed?
65
+
66
+ c = Cursor.new(@@coll)
67
+ c.add_option(OP_QUERY_EXHAUST)
68
+ 9999.times do
69
+ c.next
70
+ end
71
+ assert c.has_next?
72
+ assert c.next
73
+ assert !c.has_next?
74
+ assert c.closed?
75
+
76
+ @@coll.remove
77
+ end
78
+ end
79
+
19
80
  def test_inspect
20
81
  selector = {:a => 1}
21
82
  cursor = @@coll.find(selector)
22
83
  assert_equal "<Mongo::Cursor:0x#{cursor.object_id.to_s(16)} namespace='#{@@db.name}.#{@@coll.name}' " +
23
- "@selector=#{selector.inspect}>", cursor.inspect
84
+ "@selector=#{selector.inspect} @cursor_id=#{cursor.cursor_id}>", cursor.inspect
24
85
  end
25
86
 
26
87
  def test_explain
@@ -156,7 +156,8 @@ class DBTest < Test::Unit::TestCase
156
156
  assert Mongo::Connection.from_uri("mongodb://spongebob:squarepants@#{host_port}/#{@@db.name}")
157
157
 
158
158
  assert_raise Mongo::AuthenticationError do
159
- Mongo::Connection.from_uri("mongodb://wrong:info@#{host_port}/#{@@db.name}")
159
+ con = Mongo::Connection.from_uri("mongodb://wrong:info@#{host_port}/#{@@db.name}")
160
+ con['test']['foo'].find_one
160
161
  end
161
162
  end
162
163
 
@@ -205,8 +206,17 @@ class DBTest < Test::Unit::TestCase
205
206
 
206
207
  def test_check_command_response
207
208
  command = {:forceerror => 1}
208
- assert_raise OperationFailure do
209
+ raised = false
210
+ begin
209
211
  @@db.command(command)
212
+ rescue => ex
213
+ raised = true
214
+ assert ex.message.include?("forced error"),
215
+ "error message does not contain 'forced error'"
216
+ assert_equal 10038, ex.error_code
217
+ assert_equal 10038, ex.result['assertionCode']
218
+ ensure
219
+ assert raised, "No assertion raised!"
210
220
  end
211
221
  end
212
222
 
@@ -0,0 +1,21 @@
1
+ require './test/test_helper'
2
+ require 'logger'
3
+ require 'stringio'
4
+ require 'thread'
5
+
6
+ class TestPool < Test::Unit::TestCase
7
+
8
+ include Mongo
9
+ include BSON
10
+
11
+ def setup
12
+ @conn = standard_connection
13
+ end
14
+
15
+ def teardown
16
+ @conn[MONGO_TEST_DB].get_last_error
17
+ end
18
+
19
+ def test_foo
20
+ end
21
+ end
@@ -6,12 +6,9 @@ require './test/replica_sets/rs_test_helper'
6
6
  class ConnectTest < Test::Unit::TestCase
7
7
  include Mongo
8
8
 
9
- def setup
10
- RS.restart_killed_nodes
11
- end
12
-
13
9
  def teardown
14
10
  RS.restart_killed_nodes
11
+ @conn.close if defined?(@conn) && @conn
15
12
  end
16
13
 
17
14
  def test_connect_with_deprecated_multi
@@ -22,17 +19,30 @@ class ConnectTest < Test::Unit::TestCase
22
19
 
23
20
  def test_connect_bad_name
24
21
  assert_raise_error(ReplicaSetConnectionError, "-wrong") do
25
- ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
26
- [RS.host, RS.ports[2]], :rs_name => RS.name + "-wrong")
22
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
23
+ [RS.host, RS.ports[2]], :name => RS.name + "-wrong")
27
24
  end
28
25
  end
29
26
 
27
+ # def test_connect_timeout
28
+ # passed = false
29
+ # timeout = 3
30
+ # begin
31
+ # t0 = Time.now
32
+ # @conn = ReplSetConnection.new(['192.169.169.1', 27017], :connect_timeout => timeout)
33
+ # rescue OperationTimeout
34
+ # passed = true
35
+ # t1 = Time.now
36
+ # end
37
+
38
+ # assert passed
39
+ # assert t1 - t0 < timeout + 1
40
+ # end
41
+
30
42
  def test_connect
31
43
  @conn = ReplSetConnection.new([RS.host, RS.ports[1]], [RS.host, RS.ports[0]],
32
44
  [RS.host, RS.ports[2]], :name => RS.name)
33
45
  assert @conn.connected?
34
- assert @conn.read_primary?
35
- assert @conn.primary?
36
46
 
37
47
  assert_equal RS.primary, @conn.primary
38
48
  assert_equal RS.secondaries.sort, @conn.secondaries.sort
@@ -66,22 +76,25 @@ class ConnectTest < Test::Unit::TestCase
66
76
  @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
67
77
  [RS.host, RS.ports[2]])
68
78
  end
69
- assert @conn.connected?
70
79
  end
71
80
 
72
81
  def test_connect_with_secondary_node_killed
73
82
  node = RS.kill_secondary
74
83
 
75
- @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
76
- [RS.host, RS.ports[2]])
84
+ rescue_connection_failure do
85
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
86
+ [RS.host, RS.ports[2]])
87
+ end
77
88
  assert @conn.connected?
78
89
  end
79
90
 
80
91
  def test_connect_with_third_node_killed
81
92
  RS.kill(RS.get_node_from_port(RS.ports[2]))
82
93
 
83
- @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
84
- [RS.host, RS.ports[2]])
94
+ rescue_connection_failure do
95
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
96
+ [RS.host, RS.ports[2]])
97
+ end
85
98
  assert @conn.connected?
86
99
  end
87
100
 
@@ -6,12 +6,9 @@ require './test/replica_sets/rs_test_helper'
6
6
  class ConnectionStringTest < Test::Unit::TestCase
7
7
  include Mongo
8
8
 
9
- def setup
10
- RS.restart_killed_nodes
11
- end
12
-
13
9
  def teardown
14
10
  RS.restart_killed_nodes
11
+ @conn.close if @conn
15
12
  end
16
13
 
17
14
  def test_connect_with_connection_string
@@ -15,6 +15,7 @@ class ReplicaSetCountTest < Test::Unit::TestCase
15
15
 
16
16
  def teardown
17
17
  RS.restart_killed_nodes
18
+ @conn.close if @conn
18
19
  end
19
20
 
20
21
  def test_correct_count_after_insertion_reconnect
@@ -15,6 +15,7 @@ class ReplicaSetInsertTest < Test::Unit::TestCase
15
15
 
16
16
  def teardown
17
17
  RS.restart_killed_nodes
18
+ @conn.close if @conn
18
19
  end
19
20
 
20
21
  def test_insert
@@ -8,7 +8,7 @@ class ReplicaSetPooledInsertTest < Test::Unit::TestCase
8
8
 
9
9
  def setup
10
10
  @conn = ReplSetConnection.new([RS.host, RS.ports[0]], [RS.host, RS.ports[1]],
11
- [RS.host, RS.ports[2]], :pool_size => 10, :timeout => 5)
11
+ [RS.host, RS.ports[2]], :pool_size => 5, :timeout => 5)
12
12
  @db = @conn.db(MONGO_TEST_DB)
13
13
  @db.drop_collection("test-sets")
14
14
  @coll = @db.collection("test-sets")
@@ -16,6 +16,7 @@ class ReplicaSetPooledInsertTest < Test::Unit::TestCase
16
16
 
17
17
  def teardown
18
18
  RS.restart_killed_nodes
19
+ @conn.close if @conn
19
20
  end
20
21
 
21
22
  def test_insert
@@ -33,6 +34,8 @@ class ReplicaSetPooledInsertTest < Test::Unit::TestCase
33
34
  end
34
35
  end
35
36
 
37
+ threads.each {|t| t.join}
38
+
36
39
  # Restart the old master and wait for sync
37
40
  RS.restart_killed_nodes
38
41
  sleep(1)
@@ -7,13 +7,14 @@ class ReplicaSetQuerySecondariesTest < Test::Unit::TestCase
7
7
  include Mongo
8
8
 
9
9
  def setup
10
- @conn = ReplSetConnection.new([RS.host, RS.ports[0]], :read_secondary => true)
10
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0]], :read => :secondary)
11
11
  @db = @conn.db(MONGO_TEST_DB)
12
12
  @db.drop_collection("test-sets")
13
13
  end
14
14
 
15
15
  def teardown
16
16
  RS.restart_killed_nodes
17
+ @conn.close if @conn
17
18
  end
18
19
 
19
20
  def test_read_primary
@@ -7,7 +7,7 @@ class ReplicaSetQueryTest < Test::Unit::TestCase
7
7
  include Mongo
8
8
 
9
9
  def setup
10
- @conn = ReplSetConnection.new([RS.host, RS.ports[0]])
10
+ @conn = ReplSetConnection.new([RS.host, RS.ports[0], RS.ports[1]])
11
11
  @db = @conn.db(MONGO_TEST_DB)
12
12
  @db.drop_collection("test-sets")
13
13
  @coll = @db.collection("test-sets")
@@ -15,6 +15,7 @@ class ReplicaSetQueryTest < Test::Unit::TestCase
15
15
 
16
16
  def teardown
17
17
  RS.restart_killed_nodes
18
+ @conn.close if @conn
18
19
  end
19
20
 
20
21
  def test_query
@@ -0,0 +1,43 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ require './test/replica_sets/rs_test_helper'
3
+
4
+ # TODO: enable this once we enable reads from tags.
5
+ class ReadPreferenceTest < Test::Unit::TestCase
6
+ include Mongo
7
+
8
+ #def setup
9
+ # @conn = ReplSetConnection.new([RS.host, RS.ports[0], RS.host, RS.ports[1]], :read => :secondary, :pool_size => 50)
10
+ # @db = @conn.db(MONGO_TEST_DB)
11
+ # @db.drop_collection("test-sets")
12
+ #end
13
+
14
+ # TODO: enable this once we enable reads from tags.
15
+ # def test_query_tagged
16
+ # col = @db['mongo-test']
17
+
18
+ # col.insert({:a => 1}, :safe => {:w => 3})
19
+ # col.find_one({}, :read => {:db => "main"})
20
+ # col.find_one({}, :read => {:dc => "ny"})
21
+ # col.find_one({}, :read => {:dc => "sf"})
22
+
23
+ # assert_raise Mongo::NodeWithTagsNotFound do
24
+ # col.find_one({}, :read => {:foo => "bar"})
25
+ # end
26
+
27
+ # threads = []
28
+ # 100.times do
29
+ # threads << Thread.new do
30
+ # col.find_one({}, :read => {:dc => "sf"})
31
+ # end
32
+ # end
33
+
34
+ # threads.each {|t| t.join }
35
+
36
+ # col.remove
37
+ # end
38
+
39
+ #def teardown
40
+ # RS.restart_killed_nodes
41
+ #end
42
+
43
+ end