Skip to content
This repository
Browse code

Specs for activerecord patch

[#46141013]

Spec the desired behavior for ConnectionPool prior to removing the patch
to sync with upstream 3.2.12.
  • Loading branch information...
commit f1a4fd937afc53c3fa3ba452b7b5dda2527c7d24 1 parent 0f6b053
Luke Imhoff limhoff-r7 authored
11 Rakefile
@@ -2,12 +2,19 @@ require 'bundler/setup'
2 2
3 3 require 'metasploit_data_models'
4 4
  5 +pathname = Pathname.new(__FILE__)
  6 +root = pathname.parent
  7 +
  8 +# add metasploit-framework/lib to load paths so rake files can just require
  9 +# files normally without having to use __FILE__ and recalculating root and the
  10 +# path to lib
  11 +lib_pathname = root.join('lib')
  12 +$LOAD_PATH.unshift(lib_pathname.to_s)
  13 +
5 14 #
6 15 # load rake files like a rails engine
7 16 #
8 17
9   -pathname = Pathname.new(__FILE__)
10   -root = pathname.parent
11 18 rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path
12 19
13 20 Dir.glob(rakefile_glob) do |rakefile|
45 lib/metasploit/framework.rb
... ... @@ -0,0 +1,45 @@
  1 +# Top-level namespace that is shared between {Metasploit::Framework
  2 +# metasploit-framework} and pro, which uses Metasploit::Pro.
  3 +module Metasploit
  4 + # Supports Rails and Rails::Engine like access to metasploit-framework so it
  5 + # works in compatible manner with activerecord's rake tasks and other
  6 + # railties.
  7 + module Framework
  8 + # Returns the environment for {Metasploit::Framework}. Checks
  9 + # `METASPLOIT_FRAMEWORK_ENV` environment variable for value. Defaults to
  10 + # `'development'` if `METASPLOIT_FRAMEWORK_ENV` is not set in the
  11 + # environment variables.
  12 + #
  13 + # {env} is a ActiveSupport::StringInquirer like `Rails.env` so it can be
  14 + # queried for its value.
  15 + #
  16 + # @example check if environment is development
  17 + # if Metasploit::Framework.env.development?
  18 + # # runs only when in development
  19 + # end
  20 + #
  21 + # @return [ActiveSupport::StringInquirer] the environment name
  22 + def self.env
  23 + unless instance_variable_defined? :@env
  24 + name = ENV['METASPLOIT_FRAMEWORK_ENV']
  25 + name ||= 'development'
  26 + @env = ActiveSupport::StringInquirer.new(name)
  27 + end
  28 +
  29 + @env
  30 + end
  31 +
  32 + # Returns the root of the metasploit-framework project. Use in place of
  33 + # `Rails.root`.
  34 + #
  35 + # @return [Pathname]
  36 + def self.root
  37 + unless instance_variable_defined? :@root
  38 + pathname = Pathname.new(__FILE__)
  39 + @root = pathname.parent.parent.parent
  40 + end
  41 +
  42 + @root
  43 + end
  44 + end
  45 +end
24 lib/tasks/database.rake
... ... @@ -1,28 +1,6 @@
1 1 load 'active_record/railties/databases.rake'
2 2
3   -module Metasploit
4   - module Framework
5   - def self.env
6   - unless instance_variable_defined? :@env
7   - name = ENV['METASPLOIT_FRAMEWORK_ENV']
8   - name ||= 'development'
9   - @env = ActiveSupport::StringInquirer.new(name)
10   - end
11   -
12   - @env
13   - end
14   -
15   - def self.root
16   - unless instance_variable_defined? :@root
17   - pathname = Pathname.new(__FILE__)
18   - @root = pathname.parent.parent.parent
19   - end
20   -
21   - @root
22   - end
23   - end
24   -end
25   -
  3 +require 'metasploit/framework'
26 4
27 5 # A modification to remove dependency on Rails.env
28 6 #
251 spec/lib/active_record/connection_adapters/abstract_adapter/connection_pool_spec.rb
... ... @@ -0,0 +1,251 @@
  1 +require 'spec_helper'
  2 +
  3 +# include patch under test
  4 +require 'msf/core/patches/active_record'
  5 +# helps with environment configuration to use for connection to database
  6 +require 'metasploit/framework'
  7 +
  8 +# load Mdm::Host for testing
  9 +MetasploitDataModels.require_models
  10 +
  11 +describe ActiveRecord::ConnectionAdapters::ConnectionPool do
  12 + def database_configurations
  13 + YAML.load_file(database_configurations_pathname)
  14 + end
  15 +
  16 + def database_configurations_pathname
  17 + Metasploit::Framework.root.join('config', 'database.yml')
  18 + end
  19 +
  20 + subject(:connection_pool) do
  21 + ActiveRecord::Base.connection_pool
  22 + end
  23 +
  24 + # Not all specs require a database connection, and railties aren't being
  25 + # used, so have to manually establish connection.
  26 + before(:each) do
  27 + ActiveRecord::Base.configurations = database_configurations
  28 + spec = ActiveRecord::Base.configurations[Metasploit::Framework.env]
  29 + ActiveRecord::Base.establish_connection(spec)
  30 + end
  31 +
  32 + after(:each) do
  33 + ActiveRecord::Base.clear_all_connections!
  34 + end
  35 +
  36 + context '#active_thread_connection?' do
  37 + subject(:active_thread_connection?) do
  38 + connection_pool.active_thread_connection?
  39 + end
  40 +
  41 + # Let! so that Thread is captured before creating and entering new Threads
  42 + let!(:main_thread) do
  43 + Thread.current
  44 + end
  45 +
  46 + before(:each) do
  47 + ActiveRecord::Base.connection_pool.connection
  48 + end
  49 +
  50 + context 'with connection id' do
  51 + subject(:active_thread_connection?) do
  52 + connection_pool.active_thread_connection?(connection_id)
  53 + end
  54 +
  55 + context 'with connection id from other thread that has connection' do
  56 + let(:connection_id) do
  57 + main_thread.object_id
  58 + end
  59 +
  60 + it 'should be true' do
  61 + thread = Thread.new do
  62 + Thread.current.should_not == main_thread
  63 +
  64 + expect(active_thread_connection?).to be_true
  65 + end
  66 +
  67 + thread.join
  68 + end
  69 + end
  70 + end
  71 +
  72 + context 'without connection id' do
  73 + context 'in thread with connection' do
  74 + it { should be_true }
  75 + end
  76 +
  77 + context 'in thread without connection' do
  78 + it 'should be false' do
  79 + thread = Thread.new do
  80 + Thread.current.should_not == main_thread
  81 + expect(active_thread_connection?).to be_false
  82 + end
  83 +
  84 + thread.join
  85 + end
  86 + end
  87 + end
  88 + end
  89 +
  90 + context 'checkout' do
  91 +
  92 + end
  93 +
  94 + context '#with_connection' do
  95 + def reserved_connection_count
  96 + connection_pool.instance_variable_get(:@reserved_connections).length
  97 + end
  98 +
  99 + let(:connection_id) do
  100 + main_thread.object_id
  101 + end
  102 +
  103 + it 'should call #current_connection_id' do
  104 + connection_pool.should_receive(
  105 + :current_connection_id
  106 + ).at_least(
  107 + :once
  108 + ).and_call_original
  109 +
  110 + connection_pool.with_connection { }
  111 + end
  112 +
  113 + it 'should call #active_thread_connection? with #current_connection_id' do
  114 + current_connection_id = mock('Connection ID')
  115 + connection_pool.stub(:current_connection_id => current_connection_id)
  116 +
  117 + connection_pool.should_receive(
  118 + :active_thread_connection?
  119 + ).with(
  120 + current_connection_id
  121 + ).and_call_original
  122 +
  123 + connection_pool.with_connection { }
  124 + end
  125 +
  126 + it 'should yield #connection' do
  127 + connection = mock('Connection')
  128 + connection_pool.stub(:connection => connection)
  129 +
  130 + expect { |block|
  131 + connection_pool.with_connection(&block)
  132 + }.to yield_with_args(connection)
  133 + end
  134 +
  135 + context 'with active thread connection' do
  136 + let!(:connection) do
  137 + connection_pool.connection
  138 + end
  139 +
  140 + after(:each) do
  141 + connection_pool.checkin connection
  142 + end
  143 +
  144 + it 'should return true from #active_thread_connection?' do
  145 + expect(connection_pool.active_thread_connection?).to be_true
  146 + end
  147 +
  148 + context 'with error' do
  149 + it 'should not release connection' do
  150 + expect {
  151 + # capture error so it doesn't stop example
  152 + expect {
  153 + connection_pool.with_connection do
  154 + # raise error to trigger with_connection's ensure
  155 + raise ArgumentError, 'bad arguments'
  156 + end
  157 + }.to raise_error(ArgumentError)
  158 + }.to change {
  159 + reserved_connection_count
  160 + }.by(0)
  161 + end
  162 + end
  163 +
  164 + context 'without error' do
  165 + it 'should not release connection' do
  166 + expect {
  167 + connection_pool.with_connection { }
  168 + }.to change{
  169 + reserved_connection_count
  170 + }.by(0)
  171 + end
  172 + end
  173 + end
  174 +
  175 + context 'without active thread connection' do
  176 + it 'should return false from #active_thread_connection?' do
  177 + expect(connection_pool.active_thread_connection?).to be_false
  178 + end
  179 +
  180 + context 'with error' do
  181 + it 'should not leave connection created for block' do
  182 + expect {
  183 + # capture error so it doesn't stop example
  184 + expect {
  185 + connection_pool.with_connection do
  186 + # raise error to trigger with_connection's ensure
  187 + raise ArgumentError, 'bad arguments'
  188 + end
  189 + }.to raise_error(ArgumentError)
  190 + }.to change {
  191 + reserved_connection_count
  192 + }.by(0)
  193 + end
  194 + end
  195 +
  196 + context 'without error' do
  197 + it 'should not leave connection created for block' do
  198 + expect {
  199 + connection_pool.with_connection { }
  200 + }.to change{
  201 + reserved_connection_count
  202 + }.by(0)
  203 + end
  204 + end
  205 +
  206 + context 'with nested' do
  207 + it 'should not reserve another connection in the nested block' do
  208 + before_count = reserved_connection_count
  209 +
  210 + connection_pool.with_connection do
  211 + child_count = reserved_connection_count
  212 + count_change = child_count - before_count
  213 +
  214 + count_change.should == 1
  215 +
  216 + connection_pool.with_connection do
  217 + grandchild_count = reserved_connection_count
  218 +
  219 + grandchild_count.should == child_count
  220 + end
  221 + end
  222 +
  223 + after_count = reserved_connection_count
  224 +
  225 + after_count.should == before_count
  226 + end
  227 + end
  228 +
  229 + context 'without with_connection first' do
  230 + it 'should use connection reserved outside with_connection' do
  231 + # Using query methods without a block is expected to retain the
  232 + # reserved connection
  233 + expect {
  234 + # access database outside with_connection block
  235 + Mdm::Host.count
  236 + }.to change {
  237 + reserved_connection_count
  238 + }.by(1)
  239 +
  240 + outside = reserved_connection_count
  241 +
  242 + connection_pool.with_connection do
  243 + inside = reserved_connection_count
  244 +
  245 + inside.should == outside
  246 + end
  247 + end
  248 + end
  249 + end
  250 + end
  251 +end

0 comments on commit f1a4fd9

Please sign in to comment.
Something went wrong with that request. Please try again.