PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/test/connection_test.rb

http://github.com/mongodb/mongo-ruby-driver
Ruby | 360 lines | 286 code | 61 blank | 13 comment | 13 complexity | 2a08758fb1da18e3f7cccba9f6ba6e7d MD5 | raw file
Possible License(s): Apache-2.0
  1. require './test/test_helper'
  2. require 'logger'
  3. require 'stringio'
  4. require 'thread'
  5. class TestConnection < Test::Unit::TestCase
  6. include Mongo
  7. include BSON
  8. def setup
  9. @conn = standard_connection
  10. end
  11. def teardown
  12. @conn.close
  13. end
  14. def test_connection_failure
  15. assert_raise Mongo::ConnectionFailure do
  16. Mongo::Connection.new('localhost', 27347)
  17. end
  18. end
  19. # def test_connection_timeout
  20. # passed = false
  21. # begin
  22. # t0 = Time.now
  23. # Mongo::Connection.new('foo.bar', 27017, :connect_timeout => 3)
  24. # rescue OperationTimeout
  25. # passed = true
  26. # t1 = Time.now
  27. # end
  28. # assert passed
  29. # assert t1 - t0 < 4
  30. # end
  31. def test_host_port_accessors
  32. assert_equal @conn.host, TEST_HOST
  33. assert_equal @conn.port, TEST_PORT
  34. end
  35. def test_server_info
  36. server_info = @conn.server_info
  37. assert server_info.keys.include?("version")
  38. assert Mongo::Support.ok?(server_info)
  39. end
  40. def test_ping
  41. ping = @conn.ping
  42. assert ping['ok']
  43. end
  44. def test_connection_uri
  45. con = Connection.from_uri("mongodb://#{host_port}")
  46. assert_equal mongo_host, con.primary_pool.host
  47. assert_equal mongo_port, con.primary_pool.port
  48. end
  49. def test_server_version
  50. assert_match(/\d\.\d+(\.\d+)?/, @conn.server_version.to_s)
  51. end
  52. def test_invalid_database_names
  53. assert_raise TypeError do @conn.db(4) end
  54. assert_raise Mongo::InvalidNSName do @conn.db('') end
  55. assert_raise Mongo::InvalidNSName do @conn.db('te$t') end
  56. assert_raise Mongo::InvalidNSName do @conn.db('te.t') end
  57. assert_raise Mongo::InvalidNSName do @conn.db('te\\t') end
  58. assert_raise Mongo::InvalidNSName do @conn.db('te/t') end
  59. assert_raise Mongo::InvalidNSName do @conn.db('te st') end
  60. end
  61. def test_options_passed_to_db
  62. @pk_mock = Object.new
  63. db = @conn.db('test', :pk => @pk_mock, :strict => true)
  64. assert_equal @pk_mock, db.pk_factory
  65. assert db.strict?
  66. end
  67. def test_database_info
  68. @conn.drop_database(MONGO_TEST_DB)
  69. @conn.db(MONGO_TEST_DB).collection('info-test').insert('a' => 1)
  70. info = @conn.database_info
  71. assert_not_nil info
  72. assert_kind_of Hash, info
  73. assert_not_nil info[MONGO_TEST_DB]
  74. assert info[MONGO_TEST_DB] > 0
  75. @conn.drop_database(MONGO_TEST_DB)
  76. end
  77. def test_copy_database
  78. @conn.db('old').collection('copy-test').insert('a' => 1)
  79. @conn.copy_database('old', 'new', host_port)
  80. old_object = @conn.db('old').collection('copy-test').find.next_document
  81. new_object = @conn.db('new').collection('copy-test').find.next_document
  82. assert_equal old_object, new_object
  83. @conn.drop_database('old')
  84. @conn.drop_database('new')
  85. end
  86. def test_copy_database_with_auth
  87. @conn.db('old').collection('copy-test').insert('a' => 1)
  88. @conn.db('old').add_user('bob', 'secret')
  89. assert_raise Mongo::OperationFailure do
  90. @conn.copy_database('old', 'new', host_port, 'bob', 'badpassword')
  91. end
  92. result = @conn.copy_database('old', 'new', host_port, 'bob', 'secret')
  93. assert Mongo::Support.ok?(result)
  94. @conn.drop_database('old')
  95. @conn.drop_database('new')
  96. end
  97. def test_database_names
  98. @conn.drop_database(MONGO_TEST_DB)
  99. @conn.db(MONGO_TEST_DB).collection('info-test').insert('a' => 1)
  100. names = @conn.database_names
  101. assert_not_nil names
  102. assert_kind_of Array, names
  103. assert names.length >= 1
  104. assert names.include?(MONGO_TEST_DB)
  105. end
  106. def test_logging
  107. output = StringIO.new
  108. logger = Logger.new(output)
  109. logger.level = Logger::DEBUG
  110. connection = standard_connection(:logger => logger).db(MONGO_TEST_DB)
  111. assert output.string.include?("admin['$cmd'].find")
  112. end
  113. def test_connection_logger
  114. output = StringIO.new
  115. logger = Logger.new(output)
  116. logger.level = Logger::DEBUG
  117. connection = standard_connection(:logger => logger)
  118. assert_equal logger, connection.logger
  119. connection.logger.debug 'testing'
  120. assert output.string.include?('testing')
  121. end
  122. def test_drop_database
  123. db = @conn.db('ruby-mongo-will-be-deleted')
  124. coll = db.collection('temp')
  125. coll.remove
  126. coll.insert(:name => 'temp')
  127. assert_equal 1, coll.count()
  128. assert @conn.database_names.include?('ruby-mongo-will-be-deleted')
  129. @conn.drop_database('ruby-mongo-will-be-deleted')
  130. assert !@conn.database_names.include?('ruby-mongo-will-be-deleted')
  131. end
  132. def test_nodes
  133. conn = Connection.multi([['foo', 27017], ['bar', 27018]], :connect => false)
  134. nodes = conn.nodes
  135. assert_equal 2, nodes.length
  136. assert_equal ['foo', 27017], nodes[0]
  137. assert_equal ['bar', 27018], nodes[1]
  138. end
  139. def test_fsync_lock
  140. assert !@conn.locked?
  141. @conn.lock!
  142. assert @conn.locked?
  143. assert_equal 1, @conn['admin']['$cmd.sys.inprog'].find_one['fsyncLock'], "Not fsync-locked"
  144. assert_match(/unlock/, @conn.unlock!['info'])
  145. unlocked = false
  146. counter = 0
  147. while counter < 5
  148. if @conn['admin']['$cmd.sys.inprog'].find_one['fsyncLock'].nil?
  149. unlocked = true
  150. break
  151. else
  152. sleep(1)
  153. counter += 1
  154. end
  155. end
  156. assert !@conn.locked?
  157. assert unlocked, "mongod failed to unlock"
  158. end
  159. def test_max_bson_size_value
  160. conn = standard_connection(:connect => false)
  161. admin_db = Object.new
  162. admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1, 'maxBsonObjectSize' => 15_000_000})
  163. conn.expects(:[]).with('admin').returns(admin_db)
  164. conn.connect
  165. assert_equal 15_000_000, conn.max_bson_size
  166. conn = standard_connection
  167. if conn.server_version > "1.7.2"
  168. assert_equal conn['admin'].command({:ismaster => 1})['maxBsonObjectSize'], conn.max_bson_size
  169. end
  170. conn.connect
  171. doc = {'n' => 'a' * (conn.max_bson_size)}
  172. assert_raise InvalidDocument do
  173. assert BSON::BSON_CODER.serialize(doc, false, true, @conn.max_bson_size)
  174. end
  175. end
  176. def test_max_bson_size_with_no_reported_max_size
  177. conn = standard_connection(:connect => false)
  178. admin_db = Object.new
  179. admin_db.expects(:command).returns({'ok' => 1, 'ismaster' => 1})
  180. conn.expects(:[]).with('admin').returns(admin_db)
  181. conn.connect
  182. assert_equal Mongo::DEFAULT_MAX_BSON_SIZE, BSON::BSON_CODER.max_bson_size
  183. end
  184. def test_connection_activity
  185. conn = standard_connection
  186. assert conn.active?
  187. conn.primary_pool.close
  188. assert !conn.active?
  189. # Simulate a dropped connection.
  190. dropped_socket = Mocha::Mock.new
  191. dropped_socket.stubs(:read).raises(Errno::ECONNRESET)
  192. dropped_socket.stubs(:send).raises(Errno::ECONNRESET)
  193. dropped_socket.stub_everything
  194. conn.primary_pool.host = 'localhost'
  195. conn.primary_pool.port = Mongo::Connection::DEFAULT_PORT
  196. conn.primary_pool.instance_variable_set("@pids", {dropped_socket => Process.pid})
  197. conn.primary_pool.instance_variable_set("@sockets", [dropped_socket])
  198. assert !conn.active?
  199. end
  200. context "Saved authentications" do
  201. setup do
  202. @conn = standard_connection
  203. @auth = {'db_name' => 'test', 'username' => 'bob', 'password' => 'secret'}
  204. @conn.add_auth(@auth['db_name'], @auth['username'], @auth['password'])
  205. end
  206. teardown do
  207. @conn.clear_auths
  208. end
  209. should "save the authentication" do
  210. assert_equal @auth, @conn.auths[0]
  211. end
  212. should "replace the auth if given a new auth for the same db" do
  213. auth = {'db_name' => 'test', 'username' => 'mickey', 'password' => 'm0u53'}
  214. @conn.add_auth(auth['db_name'], auth['username'], auth['password'])
  215. assert_equal 1, @conn.auths.length
  216. assert_equal auth, @conn.auths[0]
  217. end
  218. should "remove auths by database" do
  219. @conn.remove_auth('non-existent database')
  220. assert_equal 1, @conn.auths.length
  221. @conn.remove_auth('test')
  222. assert_equal 0, @conn.auths.length
  223. end
  224. should "remove all auths" do
  225. @conn.clear_auths
  226. assert_equal 0, @conn.auths.length
  227. end
  228. end
  229. context "Socket pools" do
  230. context "checking out writers" do
  231. setup do
  232. @con = standard_connection(:pool_size => 10, :timeout => 10)
  233. @coll = @con[MONGO_TEST_DB]['test-connection-exceptions']
  234. end
  235. should "close the connection on send_message for major exceptions" do
  236. @con.expects(:checkout_writer).raises(SystemStackError)
  237. @con.expects(:close)
  238. begin
  239. @coll.insert({:foo => "bar"})
  240. rescue SystemStackError
  241. end
  242. end
  243. should "close the connection on send_message_with_safe_check for major exceptions" do
  244. @con.expects(:checkout_writer).raises(SystemStackError)
  245. @con.expects(:close)
  246. begin
  247. @coll.insert({:foo => "bar"}, :safe => true)
  248. rescue SystemStackError
  249. end
  250. end
  251. should "close the connection on receive_message for major exceptions" do
  252. @con.expects(:checkout_writer).raises(SystemStackError)
  253. @con.expects(:close)
  254. begin
  255. @coll.find.next
  256. rescue SystemStackError
  257. end
  258. end
  259. end
  260. end
  261. context "Connection exceptions" do
  262. setup do
  263. @con = standard_connection(:pool_size => 10, :timeout => 10)
  264. @coll = @con[MONGO_TEST_DB]['test-connection-exceptions']
  265. end
  266. should "release connection if an exception is raised on send_message" do
  267. @con.stubs(:send_message_on_socket).raises(ConnectionFailure)
  268. assert_equal 0, @con.primary_pool.checked_out.size
  269. assert_raise ConnectionFailure do
  270. @coll.insert({:test => "insert"})
  271. end
  272. assert_equal 0, @con.primary_pool.checked_out.size
  273. end
  274. should "release connection if an exception is raised on send_with_safe_check" do
  275. @con.stubs(:receive).raises(ConnectionFailure)
  276. assert_equal 0, @con.primary_pool.checked_out.size
  277. assert_raise ConnectionFailure do
  278. @coll.insert({:test => "insert"}, :safe => true)
  279. end
  280. assert_equal 0, @con.primary_pool.checked_out.size
  281. end
  282. should "release connection if an exception is raised on receive_message" do
  283. @con.stubs(:receive).raises(ConnectionFailure)
  284. assert_equal 0, @con.primary_pool.checked_out.size
  285. assert_raise ConnectionFailure do
  286. @coll.find.to_a
  287. end
  288. assert_equal 0, @con.primary_pool.checked_out.size
  289. end
  290. should "show a proper exception message if an IOError is raised while closing a socket" do
  291. fake_socket = Mocha::Mock.new
  292. fake_socket.stubs(:close).raises(IOError.new)
  293. fake_socket.stub_everything
  294. TCPSocket.stubs(:new).returns(fake_socket)
  295. @con.primary_pool.checkout_new_socket
  296. assert @con.primary_pool.close
  297. end
  298. end
  299. end