Merge pull request #257 from sherbet/cleaning

DatabaseCleaner.cleaning
This commit is contained in:
Ben Mabey 2014-01-26 18:17:56 -08:00
commit b254ce57bd
9 changed files with 92 additions and 23 deletions

View file

@ -146,7 +146,7 @@ passed to [`keys`](http://redis.io/commands/keys)).
(I should point out the truncation strategy will never truncate your schema_migrations table.)
Some strategies require that you call `DatabaseCleaner.start` before calling `clean` (for example the `:transaction` one needs to know to open up a transaction). So you would have:
Some strategies need to be started before tests are run (for example the `:transaction` strategy needs to know to open up a transaction). This can be accomplished by calling `DatabaseCleaner.start` at the beginning of the run, or by running the tests inside a block to `Database.cleaning`. So you would have:
```ruby
require 'database_cleaner'
@ -158,6 +158,12 @@ DatabaseCleaner.start # usually this is called in setup of a test
dirty_the_db
DatabaseCleaner.clean # cleanup of the test
# OR
DatabaseCleaner.cleaning do
dirty_the_db
end
```
At times you may want to do a single clean with one strategy.
@ -196,12 +202,10 @@ RSpec.configure do |config|
DatabaseCleaner.clean_with(:truncation)
end
config.before(:each) do
DatabaseCleaner.start
end
config.after(:each) do
DatabaseCleaner.clean
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
end
@ -221,6 +225,13 @@ class MiniTest::Spec
DatabaseCleaner.clean
end
end
# with the minitest-around gem, this may be used instead:
class Minitest::Spec
around do |tests|
DatabaseCleaner.cleaning(&tests)
end
end
```
### Cucumber Example
@ -239,12 +250,8 @@ rescue NameError
raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end
Before do
DatabaseCleaner.start
end
After do |scenario|
DatabaseCleaner.clean
Around do |scenario, block|
DatabaseCleaner.cleaning(&block)
end
```
@ -358,6 +365,9 @@ If you are using Postgres and have foreign key constraints, the truncation strat
client_min_messages = warning
```
### Nothing happens in JRuby with Sequel using transactions
Due to an inconsistency in JRuby's implementation of Fibers, Sequel gives a different connection to `DatabaseCleaner.start` than is used for tests run between `.start` and `.clean`. This can be worked around by running your tests in a block like `DatabaseCleaner.cleaning { run_my_tests }` instead, which does not use Fibers.
## Debugging

View file

@ -88,6 +88,10 @@ module DatabaseCleaner
alias clean! clean
def cleaning(&block)
strategy.cleaning(&block)
end
def auto_detected?
!!@autodetected
end

View file

@ -81,6 +81,12 @@ module DatabaseCleaner
alias clean! clean
def cleaning(&inner_block)
connections.inject(inner_block) do |curr_block, connection|
proc { connection.cleaning(&curr_block) }
end.call
end
def clean_with(*args)
connections.each { |connection| connection.clean_with(*args) }
end

View file

@ -1,11 +1,3 @@
Before do
DatabaseCleaner.start
end
After do
begin
DatabaseCleaner.clean
rescue Exception => e
DatabaseCleaner.logger.error "Exception encountered by DatabaseCleaner in Cucumber After block: #{e}"
end
Around do |scenario, block|
DatabaseCleaner.cleaning(&block)
end

View file

@ -10,6 +10,12 @@ module ::DatabaseCleaner
:default
end
def cleaning(&block)
start
yield
clean
end
module ClassMethods
def available_strategies
%W[]

View file

@ -4,7 +4,18 @@ module DatabaseCleaner
class Transaction
include ::DatabaseCleaner::Sequel::Base
def self.check_fiber_brokenness
if !@checked_fiber_brokenness && Fiber.new { Thread.current }.resume != Thread.current
raise RuntimeError, "This ruby engine's Fibers are not compatible with Sequel's connection pool. " +
"To work around this, please use DatabaseCleaner.cleaning with a block instead of " +
"DatabaseCleaner.start and DatabaseCleaner.clean"
end
@checked_fiber_brokenness = true
end
def start
self.class.check_fiber_brokenness
@fibers||= []
db= self.db
f= Fiber.new do
@ -20,6 +31,10 @@ module DatabaseCleaner
f= @fibers.pop
f.resume
end
def cleaning
self.db.transaction(:rollback => :always, :savepoint => true) { yield }
end
end
end
end

View file

@ -451,6 +451,13 @@ module DatabaseCleaner
subject.clean!
end
end
describe "cleaning" do
it "should proxy cleaning to the strategy" do
strategy.should_receive(:cleaning)
subject.cleaning { }
end
end
end
describe "auto_detected?" do

View file

@ -163,6 +163,11 @@ describe ::DatabaseCleaner do
::DatabaseCleaner.clean
end
it 'should proxy cleaning' do
connection.should_receive(:cleaning)
::DatabaseCleaner.cleaning { }
end
it "should proxy clean_with" do
stratagem = double("stratgem")
connection.should_receive(:clean_with).with(stratagem, {})
@ -203,6 +208,28 @@ describe ::DatabaseCleaner do
::DatabaseCleaner.clean
end
it "should initiate cleaning on each connection, yield, and finish cleaning each connection" do
[active_record, data_mapper].each do |connection|
mc = class << connection; self; end
mc.send(:attr_reader, :started, :cleaned)
mc.send(:define_method, 'cleaning') do |&block|
@started = true
block.call
@cleaned = true
end
end
::DatabaseCleaner.cleaning do
active_record.started.should == true
data_mapper.started.should == true
active_record.cleaned.should == nil
data_mapper.cleaned.should == nil
@yielded = true
end
active_record.cleaned.should == true
data_mapper.cleaned.should == true
end
it "should proxy clean_with to all connections" do
stratagem = double("stratgem")
active_record.should_receive(:clean_with).with(stratagem)

View file

@ -5,9 +5,11 @@ end
shared_examples_for "a generic truncation strategy" do
it { should respond_to(:start) }
it { should respond_to(:clean) }
it { should respond_to(:cleaning) }
end
shared_examples_for "a generic transaction strategy" do
it { should respond_to(:start) }
it { should respond_to(:clean) }
it { should respond_to(:cleaning) }
end