mongo 0.17.1 → 0.18

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.
@@ -17,9 +17,10 @@ class DBTest < Test::Unit::TestCase
17
17
 
18
18
  include Mongo
19
19
 
20
- @@host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
21
- @@port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
22
- @@db = Connection.new(@@host, @@port).db('ruby-mongo-test')
20
+ @@host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
21
+ @@port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
22
+ @@conn = Connection.new(@@host, @@port)
23
+ @@db = @@conn.db('ruby-mongo-test')
23
24
  @@users = @@db.collection('system.users')
24
25
 
25
26
  def setup
@@ -35,8 +36,8 @@ class DBTest < Test::Unit::TestCase
35
36
  end
36
37
 
37
38
  def test_close
38
- @@db.close
39
- assert !@@db.connected?
39
+ @@conn.close
40
+ assert !@@conn.connected?
40
41
  begin
41
42
  @@db.collection('test').insert('a' => 1)
42
43
  fail "expected 'NilClass' exception"
@@ -52,10 +53,10 @@ class DBTest < Test::Unit::TestCase
52
53
  output = StringIO.new
53
54
  logger = Logger.new(output)
54
55
  logger.level = Logger::DEBUG
55
- db = Connection.new(@host, @port, :logger => logger).db('ruby-mongo-test')
56
- assert_equal logger, db.logger
56
+ conn = Connection.new(@host, @port, :logger => logger)
57
+ assert_equal logger, conn.logger
57
58
 
58
- db.logger.debug 'testing'
59
+ conn.logger.debug 'testing'
59
60
  assert output.string.include?('testing')
60
61
  end
61
62
 
@@ -89,12 +90,16 @@ class DBTest < Test::Unit::TestCase
89
90
  end
90
91
 
91
92
  def test_pair
92
- @@db.close
93
+ @@conn.close
93
94
  @@users = nil
94
- @@db = Connection.new({:left => "this-should-fail", :right => [@@host, @@port]}).db('ruby-mongo-test')
95
- assert @@db.connected?
95
+ @@conn = Connection.new({:left => "this-should-fail", :right => [@@host, @@port]})
96
+ @@db = @@conn['ruby-mongo-test']
97
+ assert @@conn.connected?
96
98
  ensure
97
- @@db = Connection.new(@@host, @@port).db('ruby-mongo-test') unless @@db.connected?
99
+ unless @@conn.connected?
100
+ @@conn = Connection.new(@@host, @@port)
101
+ @@db = @@conn.db('ruby-mongo-test')
102
+ end
98
103
  @@users = @@db.collection('system.users')
99
104
  end
100
105
 
@@ -122,7 +127,8 @@ class DBTest < Test::Unit::TestCase
122
127
  end
123
128
 
124
129
  def test_pk_factory_reset
125
- db = Connection.new(@@host, @@port).db('ruby-mongo-test')
130
+ conn = Connection.new(@@host, @@port)
131
+ db = conn.db('ruby-mongo-test')
126
132
  db.pk_factory = Object.new # first time
127
133
  begin
128
134
  db.pk_factory = Object.new
@@ -130,7 +136,7 @@ class DBTest < Test::Unit::TestCase
130
136
  rescue => ex
131
137
  assert_match /can not change PK factory/, ex.to_s
132
138
  ensure
133
- db.close
139
+ conn.close
134
140
  end
135
141
  end
136
142
 
@@ -144,33 +150,18 @@ class DBTest < Test::Unit::TestCase
144
150
  @@db.logout # only testing that we don't throw exception
145
151
  end
146
152
 
147
- def test_auto_connect
148
- @@db.close
149
- db = Connection.new(@@host, @@port, :auto_reconnect => true).db('ruby-mongo-test')
150
- assert db.connected?
151
- assert db.auto_reconnect?
152
- db.close
153
- assert !db.connected?
154
- assert db.auto_reconnect?
155
- db.collection('test').insert('a' => 1)
156
- assert db.connected?
157
- ensure
158
- @@db = Connection.new(@@host, @@port).db('ruby-mongo-test')
159
- @@users = @@db.collection('system.users')
160
- end
161
-
162
153
  def test_error
163
154
  @@db.reset_error_history
164
155
  assert_nil @@db.error
165
156
  assert !@@db.error?
166
157
  assert_nil @@db.previous_error
167
158
 
168
- @@db.send(:db_command, :forceerror => 1)
159
+ @@db.send(:command, :forceerror => 1)
169
160
  assert @@db.error?
170
161
  assert_not_nil @@db.error
171
162
  assert_not_nil @@db.previous_error
172
163
 
173
- @@db.send(:db_command, :forceerror => 1)
164
+ @@db.send(:command, :forceerror => 1)
174
165
  assert @@db.error?
175
166
  assert @@db.error
176
167
  prev_error = @@db.previous_error
@@ -207,10 +198,10 @@ class DBTest < Test::Unit::TestCase
207
198
  assert !@@db.last_status()["updatedExisting"]
208
199
  end
209
200
 
210
- def test_text_port_number
211
- db = DB.new('ruby-mongo-test', [[@@host, @@port.to_s]])
212
- # If there is no error, all is well
213
- db.collection('users').remove
201
+ def test_text_port_number_raises_no_errors
202
+ conn = Connection.new(@@host, @@port.to_s)
203
+ db = conn['ruby-mongo-test']
204
+ assert db.collection('users').remove
214
205
  end
215
206
 
216
207
  end
@@ -6,11 +6,11 @@ require 'test/unit'
6
6
  class DBAPITest < Test::Unit::TestCase
7
7
  include Mongo
8
8
 
9
- @@connection = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
9
+ @@conn = Connection.new(ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost',
10
10
  ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT)
11
- @@db = @@connection.db("ruby-mongo-test")
11
+ @@db = @@conn.db("ruby-mongo-test")
12
12
  @@coll = @@db.collection('test')
13
- @@version = @@connection.server_version
13
+ @@version = @@conn.server_version
14
14
 
15
15
  def setup
16
16
  @@coll.remove
@@ -95,7 +95,7 @@ class DBAPITest < Test::Unit::TestCase
95
95
  # Can't compare _id values because at insert, an _id was added to @r1 by
96
96
  # the database but we don't know what it is without re-reading the record
97
97
  # (which is what we are doing right now).
98
- # assert_equal doc['_id'], @r1['_id']
98
+ # assert_equal doc['_id'], @r1['_id']
99
99
  assert_equal doc['a'], @r1['a']
100
100
  end
101
101
 
@@ -167,7 +167,7 @@ class DBAPITest < Test::Unit::TestCase
167
167
  assert_equal 1, docs[3]['a']
168
168
 
169
169
  # Sorting using array of names; assumes ascending order.
170
- docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => ['a']).to_a
170
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => 'a').to_a
171
171
  assert_equal 4, docs.size
172
172
  assert_equal 1, docs[0]['a']
173
173
  assert_equal 2, docs[1]['a']
@@ -197,22 +197,9 @@ class DBAPITest < Test::Unit::TestCase
197
197
  # order of the keys won't be guaranteed thus your sort won't make sense.
198
198
  oh = OrderedHash.new
199
199
  oh['a'] = -1
200
- docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
201
- assert_equal 4, docs.size
202
- assert_equal 4, docs[0]['a']
203
- assert_equal 3, docs[1]['a']
204
- assert_equal 2, docs[2]['a']
205
- assert_equal 1, docs[3]['a']
206
-
207
- oh = OrderedHash.new
208
- oh['b'] = -1
209
- oh['a'] = 1
210
- docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
211
- assert_equal 4, docs.size
212
- assert_equal 1, docs[0]['a']
213
- assert_equal 3, docs[1]['a']
214
- assert_equal 2, docs[2]['a']
215
- assert_equal 4, docs[3]['a']
200
+ assert_raise InvalidSortValueError do
201
+ docs = @@coll.find({'a' => { '$lt' => 10 }}, :sort => oh).to_a
202
+ end
216
203
  end
217
204
 
218
205
  def test_find_limits
@@ -488,14 +475,6 @@ class DBAPITest < Test::Unit::TestCase
488
475
  end
489
476
  end
490
477
 
491
- def test_ismaster
492
- assert @@db.master?
493
- end
494
-
495
- def test_master
496
- assert_equal "#{@@db.host}:#{@@db.port}", @@db.master
497
- end
498
-
499
478
  def test_where
500
479
  @@coll.insert('a' => 2)
501
480
  @@coll.insert('a' => 3)
@@ -776,7 +755,7 @@ class DBAPITest < Test::Unit::TestCase
776
755
  # doesn't really test functionality, just that the option is set correctly
777
756
  def test_snapshot
778
757
  @@db.collection("test").find({}, :snapshot => true).to_a
779
- assert_raise RuntimeError do
758
+ assert_raise OperationFailure do
780
759
  @@db.collection("test").find({}, :snapshot => true, :sort => 'a').to_a
781
760
  end
782
761
  end
@@ -22,4 +22,19 @@ require 'mongo'
22
22
  # NOTE: most tests assume that MongoDB is running.
23
23
  class Test::Unit::TestCase
24
24
  include Mongo
25
+
26
+ # Generic code for rescuing connection failures and retrying operations.
27
+ # This could be combined with some timeout functionality.
28
+ def rescue_connection_failure
29
+ success = false
30
+ while !success
31
+ begin
32
+ yield
33
+ success = true
34
+ rescue Mongo::ConnectionFailure
35
+ puts "Rescuing"
36
+ sleep(1)
37
+ end
38
+ end
39
+ end
25
40
  end
@@ -9,8 +9,9 @@ class SlaveConnectionTest < Test::Unit::TestCase
9
9
  def self.connect_to_slave
10
10
  @@host = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
11
11
  @@port = ENV['MONGO_RUBY_DRIVER_PORT'] || Connection::DEFAULT_PORT
12
- db = Connection.new(@@host, @@port, :slave_ok => true).db('ruby-mongo-demo')
13
- !db.master?
12
+ conn = Connection.new(@@host, @@port, :slave_ok => true)
13
+ cmd = conn['admin'].command(:ismaster => 1)
14
+ cmd['ok'] == 1 && cmd['ismaster'] != 1
14
15
  end
15
16
 
16
17
  if self.connect_to_slave
@@ -30,8 +31,8 @@ class SlaveConnectionTest < Test::Unit::TestCase
30
31
  puts "Not connected to slave; skipping slave connection tests."
31
32
 
32
33
  def test_slave_ok_false_on_queries
33
- @db = Connection.new(@@host, @@port).db('ruby-mongo-demo')
34
- assert !@db.slave_ok?
34
+ @conn = Connection.new(@@host, @@port)
35
+ assert !@conn.slave_ok?
35
36
  end
36
37
  end
37
38
  end
@@ -4,14 +4,14 @@ class TestThreading < Test::Unit::TestCase
4
4
 
5
5
  include Mongo
6
6
 
7
- @@db = Connection.new.db('ruby-mongo-test')
7
+ @@db = Connection.new('localhost', 27017, :pool_size => 1, :timeout => 3).db('ruby-mongo-test')
8
8
  @@coll = @@db.collection('thread-test-collection')
9
9
 
10
10
  def set_up_safe_data
11
11
  @@db.drop_collection('duplicate')
12
12
  @@db.drop_collection('unique')
13
13
  @duplicate = @@db.collection('duplicate')
14
- @unique = @@db.collection('unique')
14
+ @unique = @@db.collection('unique')
15
15
 
16
16
  @duplicate.insert("test" => "insert")
17
17
  @duplicate.insert("test" => "update")
@@ -0,0 +1,90 @@
1
+ require 'test/test_helper'
2
+
3
+ # Essentialy the same as test_threading.rb but with an expanded pool for
4
+ # testing multiple connections.
5
+ class TestThreadingLargePool < Test::Unit::TestCase
6
+
7
+ include Mongo
8
+
9
+ @@db = Connection.new('localhost', 27017, :pool_size => 50, :timeout => 15).db('ruby-mongo-test')
10
+ @@coll = @@db.collection('thread-test-collection')
11
+
12
+ def set_up_safe_data
13
+ @@db.drop_collection('duplicate')
14
+ @@db.drop_collection('unique')
15
+ @duplicate = @@db.collection('duplicate')
16
+ @unique = @@db.collection('unique')
17
+
18
+ @duplicate.insert("test" => "insert")
19
+ @duplicate.insert("test" => "update")
20
+ @unique.insert("test" => "insert")
21
+ @unique.insert("test" => "update")
22
+ @unique.create_index("test", true)
23
+ end
24
+
25
+ def test_safe_update
26
+ set_up_safe_data
27
+ threads = []
28
+ 100.times do |i|
29
+ threads[i] = Thread.new do
30
+ if i % 2 == 0
31
+ assert_raise Mongo::OperationFailure do
32
+ @unique.update({"test" => "insert"}, {"$set" => {"test" => "update"}}, :safe => true)
33
+ end
34
+ else
35
+ @duplicate.update({"test" => "insert"}, {"$set" => {"test" => "update"}}, :safe => true)
36
+ end
37
+ end
38
+ end
39
+
40
+ 100.times do |i|
41
+ threads[i].join
42
+ end
43
+ end
44
+
45
+ def test_safe_insert
46
+ set_up_safe_data
47
+ threads = []
48
+ 100.times do |i|
49
+ threads[i] = Thread.new do
50
+ if i % 2 == 0
51
+ assert_raise Mongo::OperationFailure do
52
+ @unique.insert({"test" => "insert"}, :safe => true)
53
+ end
54
+ else
55
+ @duplicate.insert({"test" => "insert"}, :safe => true)
56
+ end
57
+ end
58
+ end
59
+
60
+ 100.times do |i|
61
+ threads[i].join
62
+ end
63
+ end
64
+
65
+ def test_threading
66
+ @@coll.drop
67
+ @@coll = @@db.collection('thread-test-collection')
68
+
69
+ 1000.times do |i|
70
+ @@coll.insert("x" => i)
71
+ end
72
+
73
+ threads = []
74
+
75
+ 10.times do |i|
76
+ threads[i] = Thread.new do
77
+ sum = 0
78
+ @@coll.find().each do |document|
79
+ sum += document["x"]
80
+ end
81
+ assert_equal 499500, sum
82
+ end
83
+ end
84
+
85
+ 10.times do |i|
86
+ threads[i].join
87
+ end
88
+ end
89
+
90
+ end
@@ -1,12 +1,6 @@
1
1
  require 'test/test_helper'
2
2
 
3
- class CollectionTest < Test::Unit::TestCase
4
-
5
- class MockDB < DB
6
- def connect_to_master
7
- true
8
- end
9
- end
3
+ class ConnectionTest < Test::Unit::TestCase
10
4
 
11
5
  context "Basic operations: " do
12
6
  setup do
@@ -14,36 +8,40 @@ class CollectionTest < Test::Unit::TestCase
14
8
  end
15
9
 
16
10
  should "send update message" do
17
- @db = MockDB.new("testing", ['localhost', 27017], :logger => @logger)
11
+ @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
12
+ @db = @conn['testing']
18
13
  @coll = @db.collection('books')
19
- @db.expects(:send_message_with_operation).with do |op, msg, log|
14
+ @conn.expects(:send_message).with do |op, msg, log|
20
15
  op == 2001 && log.include?("db.books.update")
21
16
  end
22
17
  @coll.update({}, {:title => 'Moby Dick'})
23
18
  end
24
19
 
25
20
  should "send insert message" do
26
- @db = MockDB.new("testing", ['localhost', 27017], :logger => @logger)
21
+ @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
22
+ @db = @conn['testing']
27
23
  @coll = @db.collection('books')
28
- @db.expects(:send_message_with_operation).with do |op, msg, log|
24
+ @conn.expects(:send_message).with do |op, msg, log|
29
25
  op == 2002 && log.include?("db.books.insert")
30
26
  end
31
27
  @coll.insert({:title => 'Moby Dick'})
32
28
  end
33
29
 
34
30
  should "send safe update message" do
35
- @db = MockDB.new("testing", ['localhost', 27017], :logger => @logger)
31
+ @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
32
+ @db = @conn['testing']
36
33
  @coll = @db.collection('books')
37
- @db.expects(:send_message_with_safe_check).with do |op, msg, log|
34
+ @conn.expects(:send_message_with_safe_check).with do |op, msg, db_name, log|
38
35
  op == 2001 && log.include?("db.books.update")
39
36
  end
40
37
  @coll.update({}, {:title => 'Moby Dick'}, :safe => true)
41
38
  end
42
39
 
43
40
  should "send safe insert message" do
44
- @db = MockDB.new("testing", ['localhost', 27017], :logger => @logger)
41
+ @conn = Connection.new('localhost', 27017, :logger => @logger, :connect => false)
42
+ @db = @conn['testing']
45
43
  @coll = @db.collection('books')
46
- @db.expects(:send_message_with_safe_check).with do |op, msg, log|
44
+ @conn.expects(:send_message_with_safe_check).with do |op, msg, db_name, log|
47
45
  op == 2001 && log.include?("db.books.update")
48
46
  end
49
47
  @coll.update({}, {:title => 'Moby Dick'}, :safe => true)
@@ -0,0 +1,122 @@
1
+ require 'test/test_helper'
2
+
3
+ class ConnectionTest < Test::Unit::TestCase
4
+
5
+ def new_mock_socket
6
+ socket = Object.new
7
+ socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
8
+ socket
9
+ end
10
+
11
+ def new_mock_db
12
+ db = Object.new
13
+ end
14
+
15
+ # Make a few methods public for these tests.
16
+ class Mongo::Connection
17
+ public :checkin, :checkout, :clear_stale_cached_connections!
18
+ end
19
+
20
+ context "Initialization: " do
21
+
22
+ context "given a single node" do
23
+ setup do
24
+ TCPSocket.stubs(:new).returns(new_mock_socket)
25
+ @conn = Connection.new('localhost', 27107, :connect => false)
26
+
27
+ admin_db = new_mock_db
28
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
29
+ @conn.expects(:[]).with('admin').returns(admin_db)
30
+ @conn.connect_to_master
31
+ end
32
+
33
+ should "set localhost and port to master" do
34
+ assert_equal 'localhost', @conn.host
35
+ assert_equal 27017, @conn.port
36
+ end
37
+
38
+ should "set connection pool to 1" do
39
+ assert_equal 1, @conn.size
40
+ end
41
+
42
+ should "default slave_ok to false" do
43
+ assert !@conn.slave_ok?
44
+ end
45
+ end
46
+ end
47
+
48
+ context "Connection pooling: " do
49
+ setup do
50
+ TCPSocket.stubs(:new).returns(new_mock_socket)
51
+ @conn = Connection.new('localhost', 27107, :connect => false,
52
+ :pool_size => 3)
53
+
54
+ admin_db = new_mock_db
55
+ admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
56
+ @conn.expects(:[]).with('admin').returns(admin_db)
57
+ @conn.connect_to_master
58
+ end
59
+
60
+ should "check out a new connection" do
61
+ socket = @conn.checkout
62
+ assert @conn.reserved_connections.keys.include?(Thread.current.object_id)
63
+ end
64
+
65
+ context "with multiple threads" do
66
+ setup do
67
+ @thread1 = Object.new
68
+ @thread2 = Object.new
69
+ @thread3 = Object.new
70
+ @thread4 = Object.new
71
+
72
+ Thread.stubs(:current).returns(@thread1)
73
+ @socket1 = @conn.checkout
74
+ Thread.stubs(:current).returns(@thread2)
75
+ @socket2 = @conn.checkout
76
+ Thread.stubs(:current).returns(@thread3)
77
+ @socket3 = @conn.checkout
78
+ end
79
+
80
+ should "add each thread to the reserved pool" do
81
+ assert @conn.reserved_connections.keys.include?(@thread1.object_id)
82
+ assert @conn.reserved_connections.keys.include?(@thread2.object_id)
83
+ assert @conn.reserved_connections.keys.include?(@thread3.object_id)
84
+ end
85
+
86
+ should "only add one socket per thread" do
87
+ @conn.reserved_connections.values do |socket|
88
+ assert [@socket1, @socket2, @socket3].include?(socket)
89
+ end
90
+ end
91
+
92
+ should "check out all sockets" do
93
+ assert_equal @conn.sockets.size, @conn.checked_out.size
94
+ @conn.sockets.each do |sock|
95
+ assert @conn.checked_out.include?(sock)
96
+ end
97
+ end
98
+
99
+ should "raise an error if no more sockets can be checked out" do
100
+ # This can't be tested with mock threads.
101
+ # Will test in integration tests.
102
+ end
103
+
104
+ context "when releasing dead threads" do
105
+ setup do
106
+ @thread1.expects(:alive?).returns(false)
107
+ @thread2.expects(:alive?).returns(true)
108
+ @thread3.expects(:alive?).returns(true)
109
+ Thread.expects(:list).returns([@thread1, @thread2, @thread3])
110
+ @conn.clear_stale_cached_connections!
111
+ end
112
+
113
+ should "return connections for dead threads" do
114
+ assert !@conn.checked_out.include?(@socket1)
115
+ assert_nil @conn.reserved_connections[@thread1.object_id]
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+ end
122
+