/spec/lib/active_record/connection_adapters/abstract_adapter/connection_pool_spec.rb

https://github.com/debbiemezyene/metasploit-framework · Ruby · 209 lines · 158 code · 38 blank · 13 comment · 5 complexity · 0b2e3b03dd86e0e3ba19e33f3c3b004e MD5 · raw file

  1. # -*- coding:binary -*-
  2. require 'spec_helper'
  3. # helps with environment configuration to use for connection to database
  4. require 'metasploit/framework'
  5. # load Mdm::Host for testing
  6. MetasploitDataModels.require_models
  7. describe ActiveRecord::ConnectionAdapters::ConnectionPool do
  8. def database_configurations
  9. YAML.load_file(database_configurations_pathname)
  10. end
  11. def database_configurations_pathname
  12. Metasploit::Framework.root.join('config', 'database.yml')
  13. end
  14. subject(:connection_pool) do
  15. ActiveRecord::Base.connection_pool
  16. end
  17. # Not all specs require a database connection, and railties aren't being
  18. # used, so have to manually establish connection.
  19. before(:each) do
  20. ActiveRecord::Base.configurations = database_configurations
  21. spec = ActiveRecord::Base.configurations[Metasploit::Framework.env]
  22. ActiveRecord::Base.establish_connection(spec)
  23. end
  24. after(:each) do
  25. ActiveRecord::Base.clear_all_connections!
  26. end
  27. context '#active_connection?' do
  28. subject(:active_connection?) do
  29. connection_pool.active_connection?
  30. end
  31. # Let! so that Thread is captured before creating and entering new Threads
  32. let!(:main_thread) do
  33. Thread.current
  34. end
  35. before(:each) do
  36. ActiveRecord::Base.connection_pool.connection
  37. end
  38. context 'in thread with connection' do
  39. it { should be_true }
  40. end
  41. context 'in thread without connection' do
  42. it 'should be false' do
  43. thread = Thread.new do
  44. Thread.current.should_not == main_thread
  45. expect(active_connection?).to be_false
  46. end
  47. thread.join
  48. end
  49. end
  50. end
  51. context '#with_connection' do
  52. def reserved_connection_count
  53. connection_pool.instance_variable_get(:@reserved_connections).length
  54. end
  55. let(:connection_id) do
  56. main_thread.object_id
  57. end
  58. it 'should call #current_connection_id' do
  59. connection_pool.should_receive(
  60. :current_connection_id
  61. ).at_least(
  62. :once
  63. ).and_call_original
  64. connection_pool.with_connection { }
  65. end
  66. it 'should yield #connection' do
  67. connection = double('Connection')
  68. connection_pool.stub(:connection => connection)
  69. expect { |block|
  70. connection_pool.with_connection(&block)
  71. }.to yield_with_args(connection)
  72. end
  73. context 'with active thread connection' do
  74. let!(:connection) do
  75. connection_pool.connection
  76. end
  77. after(:each) do
  78. connection_pool.checkin connection
  79. end
  80. it 'should return true from #active_connection?' do
  81. expect(connection_pool.active_connection?).to be_true
  82. end
  83. context 'with error' do
  84. it 'should not release connection' do
  85. expect {
  86. # capture error so it doesn't stop example
  87. expect {
  88. connection_pool.with_connection do
  89. # raise error to trigger with_connection's ensure
  90. raise ArgumentError, 'bad arguments'
  91. end
  92. }.to raise_error(ArgumentError)
  93. }.to change {
  94. reserved_connection_count
  95. }.by(0)
  96. end
  97. end
  98. context 'without error' do
  99. it 'should not release connection' do
  100. expect {
  101. connection_pool.with_connection { }
  102. }.to change{
  103. reserved_connection_count
  104. }.by(0)
  105. end
  106. end
  107. end
  108. context 'without active thread connection' do
  109. it 'should return false from #active_connection?' do
  110. expect(connection_pool.active_connection?).to be_false
  111. end
  112. context 'with error' do
  113. it 'should not leave connection created for block' do
  114. expect {
  115. # capture error so it doesn't stop example
  116. expect {
  117. connection_pool.with_connection do
  118. # raise error to trigger with_connection's ensure
  119. raise ArgumentError, 'bad arguments'
  120. end
  121. }.to raise_error(ArgumentError)
  122. }.to change {
  123. reserved_connection_count
  124. }.by(0)
  125. end
  126. end
  127. context 'without error' do
  128. it 'should not leave connection created for block' do
  129. expect {
  130. connection_pool.with_connection { }
  131. }.to change{
  132. reserved_connection_count
  133. }.by(0)
  134. end
  135. end
  136. context 'with nested' do
  137. it 'should not reserve another connection in the nested block' do
  138. before_count = reserved_connection_count
  139. connection_pool.with_connection do
  140. child_count = reserved_connection_count
  141. count_change = child_count - before_count
  142. count_change.should == 1
  143. connection_pool.with_connection do
  144. grandchild_count = reserved_connection_count
  145. grandchild_count.should == child_count
  146. end
  147. end
  148. after_count = reserved_connection_count
  149. after_count.should == before_count
  150. end
  151. end
  152. context 'without with_connection first' do
  153. it 'should use connection reserved outside with_connection' do
  154. # Using query methods without a block is expected to retain the
  155. # reserved connection
  156. expect {
  157. # access database outside with_connection block
  158. Mdm::Host.count
  159. }.to change {
  160. reserved_connection_count
  161. }.by(1)
  162. outside = reserved_connection_count
  163. connection_pool.with_connection do
  164. inside = reserved_connection_count
  165. inside.should == outside
  166. end
  167. end
  168. end
  169. end
  170. end
  171. end