mongo 0.17.1 → 0.18

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+