mirror of
https://github.com/DatabaseCleaner/database_cleaner
synced 2023-03-27 23:22:03 -04:00
fixes #22, AR code doesn't create new connections like it is going out of style
The code that switches ActiveRecord adapters to take a model class instead of a connection hash or name.
This commit is contained in:
parent
501025b9de
commit
604c9cf6ad
9 changed files with 51 additions and 170 deletions
|
@ -148,7 +148,13 @@ Sometimes you need to use multiple ORMs in your application. You can use Databas
|
||||||
DatabaseCleaner[:mongo_mapper].strategy = :truncation
|
DatabaseCleaner[:mongo_mapper].strategy = :truncation
|
||||||
|
|
||||||
#How to specify particular connections
|
#How to specify particular connections
|
||||||
DatabaseCleaner[:active_record,{:connection => :two}]
|
|
||||||
|
# with DataMapper you pass in the name of the repository
|
||||||
|
DatabaseCleaner[:data_mapper,{:connection => :my_other_repository}]
|
||||||
|
|
||||||
|
# With ActiveRecord you pass in the model whose #connection DataCleaner should use
|
||||||
|
DatabaseCleaner[:active_record,{:connection => Widget}]
|
||||||
|
DatabaseCleaner[:active_record,{:connection => "Widget"}] # You may pass in the model as a String in case you need/want to delay loading.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Usage beyond that remains the same with DatabaseCleaner.start calling any setup on the different configured connections, and DatabaseCleaner.clean executing afterwards.
|
Usage beyond that remains the same with DatabaseCleaner.start calling any setup on the different configured connections, and DatabaseCleaner.clean executing afterwards.
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
Given /^I have setup database cleaner to clean multiple databases using activerecord$/ do
|
Given /^I have setup database cleaner to clean multiple databases using activerecord$/ do
|
||||||
#DatabaseCleaner
|
#DatabaseCleaner
|
||||||
# require "#{File.dirname(__FILE__)}/../../../lib/datamapper_models"
|
# require "#{File.dirname(__FILE__)}/../../../lib/activerecord_models"
|
||||||
#
|
#
|
||||||
# DatabaseCleaner[:datamapper, {:connection => :one} ].strategy = :truncation
|
# DatabaseCleaner[:active_record, {:connection => 'ActiveRecordWidgetUsingDatabaseOne'} ].strategy = whatever
|
||||||
# DatabaseCleaner[:datamapper, {:connection => :two} ].strategy = :truncation
|
# DatabaseCleaner[:active_record, {:connection => 'ActiveRecordWidgetUsingDatabaseTwo'} ].strategy = whatever
|
||||||
end
|
end
|
||||||
|
|
||||||
When /^I create a widget using activerecord$/ do
|
When /^I create a widget using activerecord$/ do
|
||||||
|
|
|
@ -42,9 +42,13 @@ if orm && strategy
|
||||||
DatabaseCleaner.app_root = "#{File.dirname(__FILE__)}/../.."
|
DatabaseCleaner.app_root = "#{File.dirname(__FILE__)}/../.."
|
||||||
orm_sym = orm.gsub(/(.)([A-Z]+)/,'\1_\2').downcase.to_sym
|
orm_sym = orm.gsub(/(.)([A-Z]+)/,'\1_\2').downcase.to_sym
|
||||||
|
|
||||||
if orm_sym == :mongo_mapper
|
case orm_sym
|
||||||
DatabaseCleaner[ orm_sym, {:connection => 'database_cleaner_test_one'} ].strategy = strategy.to_sym
|
when :mongo_mapper
|
||||||
DatabaseCleaner[ orm_sym, {:connection => 'database_cleaner_test_two'} ].strategy = strategy.to_sym
|
DatabaseCleaner[:mongo_mapper, {:connection => 'database_cleaner_test_one'} ].strategy = strategy.to_sym
|
||||||
|
DatabaseCleaner[:mongo_mapper, {:connection => 'database_cleaner_test_two'} ].strategy = strategy.to_sym
|
||||||
|
when :active_record
|
||||||
|
DatabaseCleaner[:active_record, {:connection => 'ActiveRecordWidgetUsingDatabaseOne'} ].strategy = strategy.to_sym
|
||||||
|
DatabaseCleaner[:active_record, {:connection => 'ActiveRecordWidgetUsingDatabaseTwo'} ].strategy = strategy.to_sym
|
||||||
else
|
else
|
||||||
DatabaseCleaner[ orm_sym, {:connection => :one} ].strategy = strategy.to_sym
|
DatabaseCleaner[ orm_sym, {:connection => :one} ].strategy = strategy.to_sym
|
||||||
DatabaseCleaner[ orm_sym, {:connection => :two} ].strategy = strategy.to_sym
|
DatabaseCleaner[ orm_sym, {:connection => :two} ].strategy = strategy.to_sym
|
||||||
|
|
|
@ -17,5 +17,4 @@ Feature: multiple database cleaning
|
||||||
| DataMapper | truncation |
|
| DataMapper | truncation |
|
||||||
| MongoMapper | truncation |
|
| MongoMapper | truncation |
|
||||||
| DataMapper | transaction |
|
| DataMapper | transaction |
|
||||||
# Not working...
|
| ActiveRecord | transaction |
|
||||||
#| ActiveRecord | transaction |
|
|
||||||
|
|
|
@ -9,44 +9,24 @@ module DatabaseCleaner
|
||||||
%w[truncation transaction deletion]
|
%w[truncation transaction deletion]
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.config_file_location=(path)
|
|
||||||
@config_file_location = path
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.config_file_location
|
|
||||||
@config_file_location ||= "#{DatabaseCleaner.app_root}/config/database.yml"
|
|
||||||
end
|
|
||||||
|
|
||||||
module Base
|
module Base
|
||||||
include ::DatabaseCleaner::Generic::Base
|
include ::DatabaseCleaner::Generic::Base
|
||||||
|
|
||||||
attr_accessor :connection_hash
|
def db=(model_class)
|
||||||
|
@model_class = model_class unless model_class == :default # hack. this design sucks.
|
||||||
def db=(desired_db)
|
@connection_class = nil
|
||||||
@db = desired_db
|
|
||||||
load_config
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def db
|
def db
|
||||||
@db || super
|
@model_class || ::ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_config
|
def connection
|
||||||
if self.db != :default && File.file?(ActiveRecord.config_file_location)
|
connection_class.connection
|
||||||
connection_details = YAML::load(ERB.new(IO.read(ActiveRecord.config_file_location)).result)
|
|
||||||
@connection_hash = connection_details[self.db.to_s]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_connection_klass
|
def connection_class
|
||||||
Class.new(::ActiveRecord::Base)
|
@connection_class ||= db.is_a?(String) ? Module.const_get(db) : db
|
||||||
end
|
|
||||||
|
|
||||||
def connection_klass
|
|
||||||
return ::ActiveRecord::Base unless connection_hash
|
|
||||||
klass = create_connection_klass
|
|
||||||
klass.send :establish_connection, connection_hash
|
|
||||||
klass
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -53,7 +53,6 @@ module DatabaseCleaner::ActiveRecord
|
||||||
class Deletion < Truncation
|
class Deletion < Truncation
|
||||||
|
|
||||||
def clean
|
def clean
|
||||||
connection = connection_klass.connection
|
|
||||||
tables_to_truncate(connection).each do |table_name|
|
tables_to_truncate(connection).each do |table_name|
|
||||||
connection.delete_table table_name
|
connection.delete_table table_name
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,24 +4,24 @@ module DatabaseCleaner::ActiveRecord
|
||||||
include ::DatabaseCleaner::ActiveRecord::Base
|
include ::DatabaseCleaner::ActiveRecord::Base
|
||||||
|
|
||||||
def start
|
def start
|
||||||
if connection_klass.connection.respond_to?(:increment_open_transactions)
|
if connection.respond_to?(:increment_open_transactions)
|
||||||
connection_klass.connection.increment_open_transactions
|
connection.increment_open_transactions
|
||||||
else
|
else
|
||||||
connection_klass.__send__(:increment_open_transactions)
|
connection_class.__send__(:increment_open_transactions)
|
||||||
end
|
end
|
||||||
connection_klass.connection.begin_db_transaction
|
connection.begin_db_transaction
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def clean
|
def clean
|
||||||
return unless connection_klass.connection.open_transactions > 0
|
return unless connection.open_transactions > 0
|
||||||
|
|
||||||
connection_klass.connection.rollback_db_transaction
|
connection.rollback_db_transaction
|
||||||
|
|
||||||
if connection_klass.connection.respond_to?(:decrement_open_transactions)
|
if connection.respond_to?(:decrement_open_transactions)
|
||||||
connection_klass.connection.decrement_open_transactions
|
connection.decrement_open_transactions
|
||||||
else
|
else
|
||||||
connection_klass.__send__(:decrement_open_transactions)
|
connection_class.__send__(:decrement_open_transactions)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -119,7 +119,6 @@ module DatabaseCleaner::ActiveRecord
|
||||||
include ::DatabaseCleaner::Generic::Truncation
|
include ::DatabaseCleaner::Generic::Truncation
|
||||||
|
|
||||||
def clean
|
def clean
|
||||||
connection = connection_klass.connection
|
|
||||||
connection.disable_referential_integrity do
|
connection.disable_referential_integrity do
|
||||||
connection.truncate_tables(tables_to_truncate(connection))
|
connection.truncate_tables(tables_to_truncate(connection))
|
||||||
end
|
end
|
||||||
|
@ -138,6 +137,3 @@ module DatabaseCleaner::ActiveRecord
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,140 +3,37 @@ require 'active_record'
|
||||||
require 'database_cleaner/active_record/base'
|
require 'database_cleaner/active_record/base'
|
||||||
require 'database_cleaner/shared_strategy_spec'
|
require 'database_cleaner/shared_strategy_spec'
|
||||||
|
|
||||||
module DatabaseCleaner
|
class FakeModel
|
||||||
describe ActiveRecord do
|
def self.connection
|
||||||
it { should respond_to(:available_strategies) }
|
:fake_connection
|
||||||
|
|
||||||
describe "config_file_location" do
|
|
||||||
subject { ActiveRecord.config_file_location }
|
|
||||||
|
|
||||||
it "should default to DatabaseCleaner.root / config / database.yml" do
|
|
||||||
ActiveRecord.config_file_location=nil
|
|
||||||
DatabaseCleaner.should_receive(:app_root).and_return("/path/to")
|
|
||||||
subject.should == '/path/to/config/database.yml'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module DatabaseCleaner
|
||||||
module ActiveRecord
|
module ActiveRecord
|
||||||
class ExampleStrategy
|
class ExampleStrategy
|
||||||
include ::DatabaseCleaner::ActiveRecord::Base
|
include ::DatabaseCleaner::ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
describe ExampleStrategy do
|
describe ExampleStrategy do
|
||||||
let :config_location do
|
|
||||||
'/path/to/config/database.yml'
|
|
||||||
end
|
|
||||||
|
|
||||||
before { ::DatabaseCleaner::ActiveRecord.stub(:config_file_location).and_return(config_location) }
|
|
||||||
|
|
||||||
it_should_behave_like "a generic strategy"
|
it_should_behave_like "a generic strategy"
|
||||||
|
|
||||||
describe "db" do
|
|
||||||
|
|
||||||
it "should store my desired db" do
|
describe "#connection" do
|
||||||
subject.stub(:load_config)
|
it "returns the connection from ActiveRecord::Base by default" do
|
||||||
|
::ActiveRecord::Base.stub!(:connection).and_return(:fake_connection)
|
||||||
subject.db = :my_db
|
subject.connection.should == :fake_connection
|
||||||
subject.db.should == :my_db
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should default to :default" do
|
it "returns the connection of the model provided" do
|
||||||
subject.db.should == :default
|
subject.db = FakeModel
|
||||||
|
subject.connection.should == :fake_connection
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should load_config when I set db" do
|
it "allows for the model to be passed in as a string" do
|
||||||
subject.should_receive(:load_config)
|
subject.db = "FakeModel"
|
||||||
subject.db = :my_db
|
subject.connection.should == :fake_connection
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "load_config" do
|
|
||||||
|
|
||||||
before do
|
|
||||||
subject.db = :my_db
|
|
||||||
yaml = <<-Y
|
|
||||||
my_db:
|
|
||||||
database: <%= "ONE".downcase %>
|
|
||||||
Y
|
|
||||||
File.stub(:file?).with(config_location).and_return(true)
|
|
||||||
IO.stub(:read).with(config_location).and_return(yaml)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the config" do
|
|
||||||
YAML.should_receive(:load).and_return( {:nil => nil} )
|
|
||||||
subject.load_config
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should process erb in the config" do
|
|
||||||
transformed = <<-Y
|
|
||||||
my_db:
|
|
||||||
database: one
|
|
||||||
Y
|
|
||||||
YAML.should_receive(:load).with(transformed).and_return({ "my_db" => {"database" => "one"} })
|
|
||||||
subject.load_config
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should store the relevant config in connection_hash" do
|
|
||||||
subject.load_config
|
|
||||||
subject.connection_hash.should == {"database" => "one"}
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should skip config if config file is not available" do
|
|
||||||
File.should_receive(:file?).with(config_location).and_return(false)
|
|
||||||
subject.load_config
|
|
||||||
subject.connection_hash.should be_blank
|
|
||||||
end
|
|
||||||
|
|
||||||
it "skips the file when the db is set to :default" do
|
|
||||||
# to avoid https://github.com/bmabey/database_cleaner/issues/72
|
|
||||||
subject.db = :default
|
|
||||||
YAML.should_not_receive(:load)
|
|
||||||
subject.load_config
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "connection_hash" do
|
|
||||||
it "should store connection_hash" do
|
|
||||||
subject.connection_hash = { :key => "value" }
|
|
||||||
subject.connection_hash.should == { :key => "value" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "create_connection_klass" do
|
|
||||||
it "should return a class" do
|
|
||||||
subject.create_connection_klass.should be_a(Class)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a class extending ::ActiveRecord::Base" do
|
|
||||||
subject.create_connection_klass.ancestors.should include(::ActiveRecord::Base)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "connection_klass" do
|
|
||||||
it { expect{ subject.connection_klass }.to_not raise_error }
|
|
||||||
it "should default to ActiveRecord::Base" do
|
|
||||||
subject.connection_klass.should == ::ActiveRecord::Base
|
|
||||||
end
|
|
||||||
|
|
||||||
context "when connection_hash is set" do
|
|
||||||
let(:hash) { mock("hash") }
|
|
||||||
before { subject.stub(:connection_hash).and_return(hash) }
|
|
||||||
|
|
||||||
it "should create connection_klass if it doesnt exist if connection_hash is set" do
|
|
||||||
subject.should_receive(:create_connection_klass).and_return(mock('class').as_null_object)
|
|
||||||
subject.connection_klass
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should configure the class from create_connection_klass if connection_hash is set" do
|
|
||||||
klass = mock('klass')
|
|
||||||
klass.should_receive(:establish_connection).with(hash)
|
|
||||||
|
|
||||||
subject.should_receive(:create_connection_klass).and_return(klass)
|
|
||||||
subject.connection_klass
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue