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
|
||||
|
||||
#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>
|
||||
|
||||
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
|
||||
#DatabaseCleaner
|
||||
# require "#{File.dirname(__FILE__)}/../../../lib/datamapper_models"
|
||||
# require "#{File.dirname(__FILE__)}/../../../lib/activerecord_models"
|
||||
#
|
||||
# DatabaseCleaner[:datamapper, {:connection => :one} ].strategy = :truncation
|
||||
# DatabaseCleaner[:datamapper, {:connection => :two} ].strategy = :truncation
|
||||
# DatabaseCleaner[:active_record, {:connection => 'ActiveRecordWidgetUsingDatabaseOne'} ].strategy = whatever
|
||||
# DatabaseCleaner[:active_record, {:connection => 'ActiveRecordWidgetUsingDatabaseTwo'} ].strategy = whatever
|
||||
end
|
||||
|
||||
When /^I create a widget using activerecord$/ do
|
||||
|
|
|
@ -42,9 +42,13 @@ if orm && strategy
|
|||
DatabaseCleaner.app_root = "#{File.dirname(__FILE__)}/../.."
|
||||
orm_sym = orm.gsub(/(.)([A-Z]+)/,'\1_\2').downcase.to_sym
|
||||
|
||||
if orm_sym == :mongo_mapper
|
||||
DatabaseCleaner[ orm_sym, {:connection => 'database_cleaner_test_one'} ].strategy = strategy.to_sym
|
||||
DatabaseCleaner[ orm_sym, {:connection => 'database_cleaner_test_two'} ].strategy = strategy.to_sym
|
||||
case orm_sym
|
||||
when :mongo_mapper
|
||||
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
|
||||
DatabaseCleaner[ orm_sym, {:connection => :one} ].strategy = strategy.to_sym
|
||||
DatabaseCleaner[ orm_sym, {:connection => :two} ].strategy = strategy.to_sym
|
||||
|
|
|
@ -17,5 +17,4 @@ Feature: multiple database cleaning
|
|||
| DataMapper | truncation |
|
||||
| MongoMapper | truncation |
|
||||
| DataMapper | transaction |
|
||||
# Not working...
|
||||
#| ActiveRecord | transaction |
|
||||
| ActiveRecord | transaction |
|
||||
|
|
|
@ -9,44 +9,24 @@ module DatabaseCleaner
|
|||
%w[truncation transaction deletion]
|
||||
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
|
||||
include ::DatabaseCleaner::Generic::Base
|
||||
|
||||
attr_accessor :connection_hash
|
||||
|
||||
def db=(desired_db)
|
||||
@db = desired_db
|
||||
load_config
|
||||
def db=(model_class)
|
||||
@model_class = model_class unless model_class == :default # hack. this design sucks.
|
||||
@connection_class = nil
|
||||
end
|
||||
|
||||
def db
|
||||
@db || super
|
||||
@model_class || ::ActiveRecord::Base
|
||||
end
|
||||
|
||||
def load_config
|
||||
if self.db != :default && File.file?(ActiveRecord.config_file_location)
|
||||
connection_details = YAML::load(ERB.new(IO.read(ActiveRecord.config_file_location)).result)
|
||||
@connection_hash = connection_details[self.db.to_s]
|
||||
end
|
||||
def connection
|
||||
connection_class.connection
|
||||
end
|
||||
|
||||
def create_connection_klass
|
||||
Class.new(::ActiveRecord::Base)
|
||||
end
|
||||
|
||||
def connection_klass
|
||||
return ::ActiveRecord::Base unless connection_hash
|
||||
klass = create_connection_klass
|
||||
klass.send :establish_connection, connection_hash
|
||||
klass
|
||||
def connection_class
|
||||
@connection_class ||= db.is_a?(String) ? Module.const_get(db) : db
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -53,7 +53,6 @@ module DatabaseCleaner::ActiveRecord
|
|||
class Deletion < Truncation
|
||||
|
||||
def clean
|
||||
connection = connection_klass.connection
|
||||
tables_to_truncate(connection).each do |table_name|
|
||||
connection.delete_table table_name
|
||||
end
|
||||
|
|
|
@ -4,24 +4,24 @@ module DatabaseCleaner::ActiveRecord
|
|||
include ::DatabaseCleaner::ActiveRecord::Base
|
||||
|
||||
def start
|
||||
if connection_klass.connection.respond_to?(:increment_open_transactions)
|
||||
connection_klass.connection.increment_open_transactions
|
||||
if connection.respond_to?(:increment_open_transactions)
|
||||
connection.increment_open_transactions
|
||||
else
|
||||
connection_klass.__send__(:increment_open_transactions)
|
||||
connection_class.__send__(:increment_open_transactions)
|
||||
end
|
||||
connection_klass.connection.begin_db_transaction
|
||||
connection.begin_db_transaction
|
||||
end
|
||||
|
||||
|
||||
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)
|
||||
connection_klass.connection.decrement_open_transactions
|
||||
if connection.respond_to?(:decrement_open_transactions)
|
||||
connection.decrement_open_transactions
|
||||
else
|
||||
connection_klass.__send__(:decrement_open_transactions)
|
||||
connection_class.__send__(:decrement_open_transactions)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -86,7 +86,7 @@ module ActiveRecord
|
|||
def truncate_table(table_name)
|
||||
truncate_tables([table_name])
|
||||
end
|
||||
|
||||
|
||||
def truncate_tables(table_names)
|
||||
execute("TRUNCATE TABLE #{table_names.map{|name| quote_table_name(name)}.join(', ')} #{restart_identity} #{cascade};")
|
||||
end
|
||||
|
@ -119,7 +119,6 @@ module DatabaseCleaner::ActiveRecord
|
|||
include ::DatabaseCleaner::Generic::Truncation
|
||||
|
||||
def clean
|
||||
connection = connection_klass.connection
|
||||
connection.disable_referential_integrity do
|
||||
connection.truncate_tables(tables_to_truncate(connection))
|
||||
end
|
||||
|
@ -138,6 +137,3 @@ module DatabaseCleaner::ActiveRecord
|
|||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,140 +3,37 @@ require 'active_record'
|
|||
require 'database_cleaner/active_record/base'
|
||||
require 'database_cleaner/shared_strategy_spec'
|
||||
|
||||
module DatabaseCleaner
|
||||
describe ActiveRecord do
|
||||
it { should respond_to(:available_strategies) }
|
||||
|
||||
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
|
||||
|
||||
class FakeModel
|
||||
def self.connection
|
||||
:fake_connection
|
||||
end
|
||||
end
|
||||
|
||||
module DatabaseCleaner
|
||||
module ActiveRecord
|
||||
class ExampleStrategy
|
||||
include ::DatabaseCleaner::ActiveRecord::Base
|
||||
end
|
||||
|
||||
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"
|
||||
|
||||
describe "db" do
|
||||
|
||||
it "should store my desired db" do
|
||||
subject.stub(:load_config)
|
||||
|
||||
subject.db = :my_db
|
||||
subject.db.should == :my_db
|
||||
describe "#connection" do
|
||||
it "returns the connection from ActiveRecord::Base by default" do
|
||||
::ActiveRecord::Base.stub!(:connection).and_return(:fake_connection)
|
||||
subject.connection.should == :fake_connection
|
||||
end
|
||||
|
||||
it "should default to :default" do
|
||||
subject.db.should == :default
|
||||
it "returns the connection of the model provided" do
|
||||
subject.db = FakeModel
|
||||
subject.connection.should == :fake_connection
|
||||
end
|
||||
|
||||
it "should load_config when I set db" do
|
||||
subject.should_receive(:load_config)
|
||||
subject.db = :my_db
|
||||
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
|
||||
it "allows for the model to be passed in as a string" do
|
||||
subject.db = "FakeModel"
|
||||
subject.connection.should == :fake_connection
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue