specs for multi orms/connections and some implementation

This commit is contained in:
Jon Rowe 2010-03-30 22:49:30 +01:00
parent ebb6377fe5
commit f7858cd501
3 changed files with 352 additions and 103 deletions

View file

@ -36,9 +36,48 @@ module DatabaseCleaner
%w[truncation] %w[truncation]
end end
end end
class << self
def [](orm)
raise NoORMDetected if orm.nil?
DatabaseCleaner::Base.new(orm)
end
class << self def connections
@connections ||= [::DatabaseCleaner::Base.new]
end
def strategy=(stratagem)
self.connections.first.strategy = stratagem
end
def orm=(orm)
self.connections.first.orm = orm
end
def start
self.connections.first.start
end
def clean
self.connections.first.clean
end
def clean_with(stratagem)
self.connections.first.clean_with stratagem
end
end
class Base
def initialize(desired_orm = nil)
if desired_orm == :autodetect || desired_orm.nil?
autodetect
else
self.orm = desired_orm
end
end
def create_strategy(*args) def create_strategy(*args)
strategy, *strategy_args = args strategy, *strategy_args = args
orm_strategy(strategy).new(*strategy_args) orm_strategy(strategy).new(*strategy_args)
@ -63,8 +102,8 @@ module DatabaseCleaner
end end
end end
def orm=(orm_string) def orm=(desired_orm)
@orm = orm_string @orm = desired_orm
end end
def start def start
@ -76,52 +115,62 @@ module DatabaseCleaner
end end
alias clean! clean alias clean! clean
def orm
@orm || autodetect
end
def auto_detected
return true unless @autodetected.nil?
end
private private
def strategy def strategy
return @strategy if @strategy return @strategy if @strategy
raise NoStrategySetError, "Please set a strategy with DatabaseCleaner.strategy=." raise NoStrategySetError, "Please set a strategy with DatabaseCleaner.strategy=."
end end
def orm_module
::DatabaseCleaner.orm_module(orm)
end
def orm_strategy(strategy) def orm_strategy(strategy)
require "database_cleaner/#{orm}/#{strategy}" require "database_cleaner/#{orm.to_s}/#{strategy.to_s}"
orm_module.const_get(strategy.to_s.capitalize) orm_module.const_get(strategy.to_s.capitalize)
rescue LoadError => e rescue LoadError => e
raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}" raise UnknownStrategySpecified, "The '#{strategy}' strategy does not exist for the #{orm} ORM! Available strategies: #{orm_module.available_strategies.join(', ')}"
end end
def autodetect
def orm @orm ||= begin
@orm ||=begin @autodetected = true
if defined? ::ActiveRecord if defined? ::ActiveRecord
'active_record' :active_record
elsif defined? ::DataMapper elsif defined? ::DataMapper
'data_mapper' :data_mapper
elsif defined? ::MongoMapper elsif defined? ::MongoMapper
'mongo_mapper' :mongo_mapper
elsif defined? ::CouchPotato elsif defined? ::CouchPotato
'couch_potato' :couch_potato
else else
raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, MongoMapper or CouchPotato loaded?" raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, MongoMapper or CouchPotato loaded?"
end end
end end
end end
def orm_module def orm_module
case orm case orm
when 'active_record' when :active_record
DatabaseCleaner::ActiveRecord DatabaseCleaner::ActiveRecord
when 'data_mapper' when :data_mapper
DatabaseCleaner::DataMapper DatabaseCleaner::DataMapper
when 'mongo_mapper' when :mongo_mapper
DatabaseCleaner::MongoMapper DatabaseCleaner::MongoMapper
when 'couch_potato' when :couch_potato
DatabaseCleaner::CouchPotato DatabaseCleaner::CouchPotato
end end
end end
end end
end end

View file

@ -18,101 +18,300 @@ describe DatabaseCleaner do
end end
end end
end end
context "orm specification" do
# These examples muck around with the constants for autodetection so we need to clean up.... it "should not accept unrecognised orms" do
before(:all) do lambda { ::DatabaseCleaner[nil] }.should raise_error ::DatabaseCleaner::NoORMDetected
TempAR = ActiveRecord unless defined?(TempAR) end
TempMM = MongoMapper unless defined?(TempMM)
Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper) it "should accept :active_record" do
# need to add one for each ORM that we load in the spec helper... cleaner = ::DatabaseCleaner[:active_record]
end cleaner.should be_a ::DatabaseCleaner::Base
after(:all) do cleaner.orm.should == :active_record
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord) #want to make sure we have the real one... end
ActiveRecord = TempAR
MongoMapper = TempMM it "should accept :data_mapper" do
end cleaner = ::DatabaseCleaner[:data_mapper]
cleaner.should be_a ::DatabaseCleaner::Base
before(:each) do cleaner.orm.should == :data_mapper
DatabaseCleaner::ActiveRecord::Transaction.stub!(:new).and_return(@strategy = mock('strategy')) end
Object.const_set('ActiveRecord', "just mocking out the constant here...") unless defined?(::ActiveRecord)
DatabaseCleaner.strategy = nil it "should accept :mongo_mapper" do
DatabaseCleaner.orm = nil cleaner = ::DatabaseCleaner[:mongo_mapper]
cleaner.should be_a ::DatabaseCleaner::Base
cleaner.orm.should == :mongo_mapper
end
it "should accept :couch_potato" do
cleaner = ::DatabaseCleaner[:couch_potato]
cleaner.should be_a ::DatabaseCleaner::Base
cleaner.orm.should == :couch_potato
end
end end
describe ".create_strategy" do context "class methods" do
it "should initialize and return the appropirate strategy" do it "should have array of connections (orm agnostic)" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash') ::DatabaseCleaner.connections.should respond_to(:each)
result = DatabaseCleaner.create_strategy(:transaction, {'options' => 'hash'}) end
result.should == @strategy
it "should give me a default (autodetection) databasecleaner by default" do
::DatabaseCleaner.connections.should have (1).items
::DatabaseCleaner.connections.first.should be_a ::DatabaseCleaner::Base
end end
end end
describe ".clean_with" do context "instance methods" do
it "should initialize the appropirate strategy and clean with it" do it "should default to autodetect upon initalisation" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash') cleaner = ::DatabaseCleaner::Base.new
@strategy.should_receive(:clean) cleaner.auto_detected.should == true
DatabaseCleaner.clean_with(:transaction, 'options' => 'hash')
end end
context "autodetect" do
before(:all) do
Temp_AR = ActiveRecord if defined?(::ActiveRecord) and not defined?(Temp_AR)
Temp_DM = DataMapper if defined?(::DataMapper) and not defined?(Temp_DM)
Temp_MM = MongoMapper if defined?(::MongoMapper) and not defined?(Temp_MM)
Temp_CP = CouchPotato if defined?(::CouchPotato) and not defined?(Temp_CP)
end
before(:each) do
# Remove ORM consts for these tests
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper)
Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
end
it "should raise an error when no ORM is detected" do
running { DatabaseCleaner::Base.new(:autodetect) }.should raise_error(DatabaseCleaner::NoORMDetected)
end
it "should detect ActiveRecord first" do
Object.const_set('ActiveRecord','Actively mocking records.')
Object.const_set('DataMapper', 'Mapping data mocks')
Object.const_set('MongoMapper', 'Mapping mock mongos')
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :active_record
end
it "should detect DataMapper second" do
Object.const_set('DataMapper', 'Mapping data mocks')
Object.const_set('MongoMapper', 'Mapping mock mongos')
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :data_mapper
end
it "should detect MongoMapper third" do
Object.const_set('MongoMapper', 'Mapping mock mongos')
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :mongo_mapper
end
it "should detect CouchPotato last" do
Object.const_set('CouchPotato', 'Couching mock potatos')
cleaner = DatabaseCleaner::Base.new :autodetect
cleaner.orm.should == :couch_potato
end
after(:all) do
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
Object.send(:remove_const, 'MongoMapper') if defined?(::MongoMapper)
Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
# Restore ORMs
ActiveRecord = Temp_AR if defined? Temp_AR
DataMapper = Temp_DM if defined? Temp_DM
MongoMapper = Temp_MM if defined? Temp_MM
CouchPotato = Temp_CP if defined? Temp_CP
end
end
end end
describe ".strategy=" do context "single orm" do
it "should initialize the appropirate strategy based on the ORM adapter detected" do let (:connection) { ::DatabaseCleaner.connections.first }
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash') it "should proxy strategy=" do
DatabaseCleaner.strategy = :transaction, {'options' => 'hash'} stratagum = mock("stratagum")
connection.should_receive(:strategy=).with(stratagum)
Object.send(:remove_const, 'ActiveRecord') ::DatabaseCleaner.strategy = stratagum
Object.const_set('DataMapper', "just mocking out the constant here...")
DatabaseCleaner.orm = nil
DatabaseCleaner::DataMapper::Transaction.should_receive(:new).with(no_args)
DatabaseCleaner.strategy = :transaction
end end
it "should raise an error when no ORM is detected" do it "should proxy orm=" do
Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord) orm = mock("orm")
Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper) connection.should_receive(:orm=).with(orm)
Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) ::DatabaseCleaner.orm = orm
running { DatabaseCleaner.strategy = :transaction }.should raise_error(DatabaseCleaner::NoORMDetected)
end end
it "should use the strategy version of the ORM specified with #orm=" do it "should proxy start" do
DatabaseCleaner.orm = 'data_mapper' connection.should_receive(:start)
DatabaseCleaner::DataMapper::Transaction.should_receive(:new) ::DatabaseCleaner.start
DatabaseCleaner.strategy = :transaction
end end
it "should raise an error when multiple args is passed in and the first is not a symbol" do it "should proxy clean" do
running { DatabaseCleaner.strategy=Object.new, {:foo => 'bar'} }.should raise_error(ArgumentError) connection.should_receive(:clean)
::DatabaseCleaner.clean
end end
it "should raise an error when the specified strategy is not found" do it "should proxy clean_with" do
running { DatabaseCleaner.strategy = :foo }.should raise_error(DatabaseCleaner::UnknownStrategySpecified) stratagem = mock("stratgem")
connection.should_receive(:clean_with).with(stratagem)
::DatabaseCleaner.clean_with stratagem
end end
it "should allow any object to be set as the strategy" do
mock_strategy = mock('strategy')
running { DatabaseCleaner.strategy = mock_strategy }.should_not raise_error
end
end end
describe ::DatabaseCleaner::Base do
%w[start clean].each do |strategy_method|
describe ".#{strategy_method}" do describe "orm_module" do
it "should be delgated to the strategy set with strategy=" do it "should proxy to the class method"
DatabaseCleaner.strategy = :transaction end
@strategy.should_receive(strategy_method) let(:strategy) { mock("stratagum") }
DatabaseCleaner.send(strategy_method) context "active record" do
let(:cleaner) { ::DatabaseCleaner::Base.new(:active_record) }
before(:each) do
::DatabaseCleaner::ActiveRecord::Transaction.stub!(:new).and_return(strategy)
#Object.const_set('ActiveRecord', "just mocking out the constant here...") unless defined?(::ActiveRecord)
cleaner.strategy = nil
end
describe ".create_strategy" do
it "should initialize and return the appropirate strategy" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash')
result = cleaner.create_strategy(:transaction, {'options' => 'hash'})
result.should == strategy
end end
end
it "should raise en error when no strategy has been set" do describe ".clean_with" do
running { DatabaseCleaner.send(strategy_method) }.should raise_error(DatabaseCleaner::NoStrategySetError) it "should initialize the appropirate strategy and clean with it" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash')
strategy.should_receive(:clean)
cleaner.clean_with(:transaction, 'options' => 'hash')
end
end
describe ".strategy=" do
it "should initialize the appropirate strategy for active record" do
DatabaseCleaner::ActiveRecord::Transaction.should_receive(:new).with('options' => 'hash')
cleaner.strategy = :transaction, {'options' => 'hash'}
end
it "should allow any object to be set as the strategy" do
mock_strategy = mock('strategy')
running { DatabaseCleaner.strategy = mock_strategy }.should_not raise_error
end
it "should raise an error when the specified strategy is not found" do
running { DatabaseCleaner.strategy = :foo }.should raise_error(DatabaseCleaner::UnknownStrategySpecified)
end
it "should raise an error when multiple args is passed in and the first is not a symbol" do
running { DatabaseCleaner.strategy=Object.new, {:foo => 'bar'} }.should raise_error(ArgumentError)
end
end
%w[start clean].each do |strategy_method|
describe ".#{strategy_method}" do
it "should be delgated to the strategy set with strategy=" do
cleaner.strategy = :transaction
strategy.should_receive(strategy_method)
cleaner.send(strategy_method)
end
it "should raise en error when no strategy has been set" do
running { cleaner.send(strategy_method) }.should raise_error(DatabaseCleaner::NoStrategySetError)
end
end end
end end
end end
context "data mapper" do
let(:cleaner) { ::DatabaseCleaner::Base.new(:data_mapper) }
before(:each) do
::DatabaseCleaner::DataMapper::Transaction.stub!(:new).and_return(strategy)
#Object.const_set('ActiveRecord', "just mocking out the constant here...") unless defined?(::ActiveRecord)
cleaner.strategy = nil
end
describe ".create_strategy" do
it "should initialize and return the appropirate strategy" do
DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
result = cleaner.create_strategy(:transaction)
result.should == strategy
end
end
describe ".clean_with" do
it "should initialize the appropirate strategy and clean with it" do
DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
strategy.should_receive(:clean)
cleaner.clean_with(:transaction)
end
end
describe ".strategy=" do
it "should initalize the appropriate strategy for data mapper" do
DatabaseCleaner::DataMapper::Transaction.should_receive(:new).with(no_args)
cleaner.strategy = :transaction
end
it "should allow any object to be set as the strategy" do
mock_strategy = mock('strategy')
running { cleaner.strategy = mock_strategy }.should_not raise_error
end
it "should raise an error when the specified strategy is not found" do
running { cleaner.strategy = :foo }.should raise_error(DatabaseCleaner::UnknownStrategySpecified)
end
it "should raise an error when multiple args is passed in and the first is not a symbol" do
running { cleaner.strategy=Object.new, {:foo => 'bar'} }.should raise_error(ArgumentError)
end
end
%w[start clean].each do |strategy_method|
describe ".#{strategy_method}" do
it "should be delgated to the strategy set with strategy=" do
cleaner.strategy = :transaction
strategy.should_receive(strategy_method)
cleaner.send(strategy_method)
end
it "should raise en error when no strategy has been set" do
running { cleaner.send(strategy_method) }.should raise_error(DatabaseCleaner::NoStrategySetError)
end
end
end
end
# it "should raise an error when no ORM is detected" do
# Object.send(:remove_const, 'ActiveRecord') if defined?(::ActiveRecord)
# Object.send(:remove_const, 'DataMapper') if defined?(::DataMapper)
# Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato)
#
# running { DatabaseCleaner.strategy = :transaction }.should raise_error(DatabaseCleaner::NoORMDetected)
# end
# it "should use the strategy version of the ORM specified with #orm=" do
# DatabaseCleaner.orm = 'data_mapper'
# DatabaseCleaner::DataMapper::Transaction.should_receive(:new)
#
# DatabaseCleaner.strategy = :transaction
# end
end
end end

View file

@ -4,3 +4,4 @@
mtime mtime
--reverse --reverse
--backtrace --backtrace
--debugger