mongo 1.3.1 → 1.4.0

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