PageRenderTime 49ms CodeModel.GetById 8ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

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