From dedbe8da0e30800f61086915284bac21ed4fdc91 Mon Sep 17 00:00:00 2001 From: Justin Edwards Date: Fri, 8 Mar 2013 18:43:06 -0600 Subject: [PATCH 01/10] Update README.markdown to fix a small typo --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 31783e8..3d8b110 100644 --- a/README.markdown +++ b/README.markdown @@ -88,7 +88,7 @@ For the SQL libraries the fastest option will be to use `:transaction` as transa One common approach is to force all processes to use the same database connection ([common ActiveRecord hack](http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite/)) however this approach has been reported to result in non-deterministic failures. -Another approach is to have the transactions rolled back in the application's process and relax the isolation level of the database (so the tests can read the uncommited transactions). +Another approach is to have the transactions rolled back in the application's process and relax the isolation level of the database (so the tests can read the uncommitted transactions). An easier, but slower, solution is to use the `:truncation` or `:deletion` strategy. From 1af146fb80fef05acca0d1a322bb6987af645cc0 Mon Sep 17 00:00:00 2001 From: John Hampton Date: Mon, 18 Mar 2013 08:58:53 -0700 Subject: [PATCH 02/10] Call transaction before calling rollback_transaction_records If the protected method rollback_transaction_records is called before transaction has been called at least once, the @_current_transaction_records instance variable will be unitialized. This results is an exception when clean attempts to call rollback_transaction_records. --- lib/database_cleaner/active_record/transaction.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/database_cleaner/active_record/transaction.rb b/lib/database_cleaner/active_record/transaction.rb index e7b4990..ee96ffb 100644 --- a/lib/database_cleaner/active_record/transaction.rb +++ b/lib/database_cleaner/active_record/transaction.rb @@ -7,6 +7,10 @@ module DatabaseCleaner::ActiveRecord include ::DatabaseCleaner::Generic::Transaction def start + # Hack to make sure that the connection is properly setup for + # the clean code. + connection_class.connection.transaction + if connection_maintains_transaction_count? if connection_class.connection.respond_to?(:increment_open_transactions) connection_class.connection.increment_open_transactions From 7762d2f4f5400a85717d940b0eb5216169dbe2d0 Mon Sep 17 00:00:00 2001 From: Cyprian Kowalczyk Date: Tue, 19 Mar 2013 15:01:23 +0100 Subject: [PATCH 03/10] Added support for Moped (when used without Mongoid) Fixed DatabaseCleaner::Base null strategy spec --- README.markdown | 11 +++ lib/database_cleaner/base.rb | 6 +- lib/database_cleaner/mongoid/truncation.rb | 4 +- lib/database_cleaner/moped/base.rb | 35 +++++++++ lib/database_cleaner/moped/truncation.rb | 28 +------ lib/database_cleaner/moped/truncation_base.rb | 34 +++++++++ spec/database_cleaner/base_spec.rb | 29 ++++++- spec/database_cleaner/configuration_spec.rb | 7 ++ spec/database_cleaner/moped/moped_examples.rb | 26 +++++++ .../database_cleaner/moped/truncation_spec.rb | 75 +++++++++++++++++++ 10 files changed, 223 insertions(+), 32 deletions(-) create mode 100644 lib/database_cleaner/moped/base.rb create mode 100644 lib/database_cleaner/moped/truncation_base.rb create mode 100644 spec/database_cleaner/moped/moped_examples.rb create mode 100644 spec/database_cleaner/moped/truncation_spec.rb diff --git a/README.markdown b/README.markdown index 3d8b110..b6cc5b0 100644 --- a/README.markdown +++ b/README.markdown @@ -72,6 +72,12 @@ Here is an overview of the strategies supported for each library: No No + + Moped + Yes + No + No + @@ -276,6 +282,11 @@ Usage beyond that remains the same with `DatabaseCleaner.start` calling any setu DatabaseCleaner[:mongoid] Multiple databases supported for Mongoid 3. Specify DatabaseCleaner[:mongoid, {:connection => :db_name}] + + Moped + DatabaseCleaner[:moped] + It is necessary to configure database name with DatabaseCleaner[:moped].db = db_name otherwise name `default` will be used. + Couch Potato DatabaseCleaner[:couch_potato] diff --git a/lib/database_cleaner/base.rb b/lib/database_cleaner/base.rb index 7565502..e1830cf 100644 --- a/lib/database_cleaner/base.rb +++ b/lib/database_cleaner/base.rb @@ -120,8 +120,10 @@ module DatabaseCleaner :couch_potato elsif defined? ::Sequel :sequel + elsif defined? ::Moped + :moped else - raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, or CouchPotato loaded?" + raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, Moped, or CouchPotato loaded?" end end end @@ -130,7 +132,7 @@ module DatabaseCleaner case orm when :active_record, :data_mapper, :sequel self.strategy = :transaction - when :mongo_mapper, :mongoid, :couch_potato + when :mongo_mapper, :mongoid, :couch_potato, :moped self.strategy = :truncation end end diff --git a/lib/database_cleaner/mongoid/truncation.rb b/lib/database_cleaner/mongoid/truncation.rb index 5a5cbb6..1be296c 100644 --- a/lib/database_cleaner/mongoid/truncation.rb +++ b/lib/database_cleaner/mongoid/truncation.rb @@ -1,7 +1,7 @@ require 'database_cleaner/mongoid/base' require 'database_cleaner/generic/truncation' require 'database_cleaner/mongo/truncation_mixin' -require 'database_cleaner/moped/truncation' +require 'database_cleaner/moped/truncation_base' require 'mongoid/version' module DatabaseCleaner @@ -22,7 +22,7 @@ module DatabaseCleaner else - include ::DatabaseCleaner::Moped::Truncation + include ::DatabaseCleaner::Moped::TruncationBase private diff --git a/lib/database_cleaner/moped/base.rb b/lib/database_cleaner/moped/base.rb new file mode 100644 index 0000000..1b917e2 --- /dev/null +++ b/lib/database_cleaner/moped/base.rb @@ -0,0 +1,35 @@ +require 'database_cleaner/generic/base' + +module DatabaseCleaner + module Moped + def self.available_strategies + %w[truncation] + end + + module Base + include ::DatabaseCleaner::Generic::Base + + def db=(desired_db) + @db = desired_db + end + + def db + @db || :default + end + + def host_port=(desired_host) + @host = desired_host + end + + def host + @host || '127.0.0.1:27017' + end + + private + + def session + ::Moped::Session.new([host], database: db) + end + end + end +end diff --git a/lib/database_cleaner/moped/truncation.rb b/lib/database_cleaner/moped/truncation.rb index 815c267..3be3349 100644 --- a/lib/database_cleaner/moped/truncation.rb +++ b/lib/database_cleaner/moped/truncation.rb @@ -1,29 +1,9 @@ +require 'database_cleaner/moped/truncation_base' + module DatabaseCleaner module Moped - module Truncation - - def clean - if @only - collections.each { |c| session[c].find.remove_all if @only.include?(c) } - else - collections.each { |c| session[c].find.remove_all unless @tables_to_exclude.include?(c) } - end - true - end - - private - - def collections - if db != :default - session.use(db) - end - - session['system.namespaces'].find(:name => { '$not' => /system|\$/ }).to_a.map do |collection| - _, name = collection['name'].split('.', 2) - name - end - end - + class Truncation + include ::DatabaseCleaner::Moped::TruncationBase end end end diff --git a/lib/database_cleaner/moped/truncation_base.rb b/lib/database_cleaner/moped/truncation_base.rb new file mode 100644 index 0000000..e4d5bf3 --- /dev/null +++ b/lib/database_cleaner/moped/truncation_base.rb @@ -0,0 +1,34 @@ +require 'database_cleaner/moped/base' +require 'database_cleaner/generic/truncation' + +module DatabaseCleaner + module Moped + module TruncationBase + include ::DatabaseCleaner::Moped::Base + include ::DatabaseCleaner::Generic::Truncation + + def clean + if @only + collections.each { |c| session[c].find.remove_all if @only.include?(c) } + else + collections.each { |c| session[c].find.remove_all unless @tables_to_exclude.include?(c) } + end + true + end + + private + + def collections + if db != :default + session.use(db) + end + + session['system.namespaces'].find(:name => { '$not' => /system|\$/ }).to_a.map do |collection| + _, name = collection['name'].split('.', 2) + name + end + end + + end + end +end diff --git a/spec/database_cleaner/base_spec.rb b/spec/database_cleaner/base_spec.rb index 6cb27df..9225c6c 100644 --- a/spec/database_cleaner/base_spec.rb +++ b/spec/database_cleaner/base_spec.rb @@ -18,6 +18,7 @@ module DatabaseCleaner Temp_MO = ::Mongoid if defined?(::Mongoid) and not defined?(Temp_MO) Temp_CP = ::CouchPotato if defined?(::CouchPotato) and not defined?(Temp_CP) Temp_SQ = ::Sequel if defined?(::Sequel) and not defined?(Temp_SQ) + Temp_MP = ::Moped if defined?(::Moped) and not defined?(Temp_MP) end #Remove all ORM mocks and restore from cache @@ -28,6 +29,7 @@ module DatabaseCleaner Object.send(:remove_const, 'Mongoid') if defined?(::Mongoid) Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) Object.send(:remove_const, 'Sequel') if defined?(::Sequel) + Object.send(:remove_const, 'Moped') if defined?(::Moped) # Restore ORMs @@ -36,6 +38,7 @@ module DatabaseCleaner ::MongoMapper = Temp_MM if defined? Temp_MM ::Mongoid = Temp_MO if defined? Temp_MO ::CouchPotato = Temp_CP if defined? Temp_CP + ::Moped = Temp_MP if defined? Temp_MP end #reset the orm mocks @@ -46,6 +49,7 @@ module DatabaseCleaner Object.send(:remove_const, 'Mongoid') if defined?(::Mongoid) Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) Object.send(:remove_const, 'Sequel') if defined?(::Sequel) + Object.send(:remove_const, 'Moped') if defined?(::Moped) end let(:cleaner) { DatabaseCleaner::Base.new :autodetect } @@ -61,6 +65,7 @@ module DatabaseCleaner Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') + Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :active_record cleaner.should be_auto_detected @@ -72,6 +77,7 @@ module DatabaseCleaner Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') + Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :data_mapper cleaner.should be_auto_detected @@ -82,6 +88,7 @@ module DatabaseCleaner Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') + Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :mongo_mapper cleaner.should be_auto_detected @@ -91,6 +98,7 @@ module DatabaseCleaner Object.const_set('Mongoid', 'Mongoid mock') Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') + Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :mongoid cleaner.should be_auto_detected @@ -99,17 +107,26 @@ module DatabaseCleaner it "should detect CouchPotato fifth" do Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') + Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :couch_potato cleaner.should be_auto_detected end - - it "should detect Sequel last" do + + it "should detect Sequel sixth" do Object.const_set('Sequel', 'Sequel mock') + Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :sequel cleaner.should be_auto_detected end + + it "should detect Moped seventh" do + Object.const_set('Moped', 'Moped mock') + + cleaner.orm.should == :moped + cleaner.should be_auto_detected + end end describe "orm_module" do @@ -330,8 +347,7 @@ module DatabaseCleaner describe "strategy" do subject { ::DatabaseCleaner::Base.new :a_orm } - it "returns a null strategy when strategy no set and undetectable" do - subject.instance_values["@strategy"] = nil + it "returns a null strategy when strategy is not set and undetectable" do subject.strategy.should == DatabaseCleaner::NullStrategy end @@ -487,6 +503,11 @@ module DatabaseCleaner cleaner = DatabaseCleaner::Base.new(:couch_potato) cleaner.strategy.should be_instance_of DatabaseCleaner::CouchPotato::Truncation end + + it 'sets strategy to :truncation for Moped' do + cleaner = DatabaseCleaner::Base.new(:moped) + cleaner.strategy.should be_instance_of DatabaseCleaner::Moped::Truncation + end end end diff --git a/spec/database_cleaner/configuration_spec.rb b/spec/database_cleaner/configuration_spec.rb index c77f836..9bec7a6 100644 --- a/spec/database_cleaner/configuration_spec.rb +++ b/spec/database_cleaner/configuration_spec.rb @@ -55,6 +55,13 @@ describe ::DatabaseCleaner do cleaner.orm.should == :couch_potato ::DatabaseCleaner.connections.size.should == 1 end + + it "should accept :moped" do + cleaner = ::DatabaseCleaner[:moped] + cleaner.should be_a(::DatabaseCleaner::Base) + cleaner.orm.should == :moped + ::DatabaseCleaner.connections.size.should == 1 + end end it "should accept multiple orm's" do diff --git a/spec/database_cleaner/moped/moped_examples.rb b/spec/database_cleaner/moped/moped_examples.rb new file mode 100644 index 0000000..0fd25df --- /dev/null +++ b/spec/database_cleaner/moped/moped_examples.rb @@ -0,0 +1,26 @@ +module MopedTest + class ThingBase + def self.collection + @db ||= 'database_cleaner_specs' + @session ||= ::Moped::Session.new(['127.0.0.1:27017'], database: @db) + @collection ||= @session[name] + end + + def self.count + @collection.find.count + end + + def initialize(attrs={}) + @attrs = attrs + end + + def save! + self.class.collection.insert(@attrs) + end + end + + class Widget < ThingBase + end + class Gadget < ThingBase + end +end diff --git a/spec/database_cleaner/moped/truncation_spec.rb b/spec/database_cleaner/moped/truncation_spec.rb new file mode 100644 index 0000000..43f612a --- /dev/null +++ b/spec/database_cleaner/moped/truncation_spec.rb @@ -0,0 +1,75 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'moped' +require 'database_cleaner/moped/truncation' +require File.dirname(__FILE__) + '/moped_examples' + +module DatabaseCleaner + module Moped + + describe Truncation do + let(:args) {{}} + let(:truncation) { described_class.new(args).tap { |t| t.db=@db } } + #doing this in the file root breaks autospec, doing it before(:all) just fails the specs + before(:all) do + @test_db = 'database_cleaner_specs' + @session = ::Moped::Session.new(['127.0.0.1:27017'], database: @test_db) + end + + before(:each) do + truncation.db = @test_db + end + + after(:each) do + @session.drop + end + + def ensure_counts(expected_counts) + # I had to add this sanity_check garbage because I was getting non-determinisc results from mongo at times.. + # very odd and disconcerting... + expected_counts.each do |model_class, expected_count| + model_class.count.should equal(expected_count), "#{model_class} expected to have a count of #{expected_count} but was #{model_class.count}" + end + end + + def create_widget(attrs={}) + MopedTest::Widget.new({:name => 'some widget'}.merge(attrs)).save! + end + + def create_gadget(attrs={}) + MopedTest::Gadget.new({:name => 'some gadget'}.merge(attrs)).save! + end + + it "truncates all collections by default" do + create_widget + create_gadget + ensure_counts(MopedTest::Widget => 1, MopedTest::Gadget => 1) + truncation.clean + ensure_counts(MopedTest::Widget => 0, MopedTest::Gadget => 0) + end + + context "when collections are provided to the :only option" do + let(:args) {{:only => ['MopedTest::Widget']}} + it "only truncates the specified collections" do + create_widget + create_gadget + ensure_counts(MopedTest::Widget => 1, MopedTest::Gadget => 1) + truncation.clean + ensure_counts(MopedTest::Widget => 0, MopedTest::Gadget => 1) + end + end + + context "when collections are provided to the :except option" do + let(:args) {{:except => ['MopedTest::Widget']}} + it "truncates all but the specified collections" do + create_widget + create_gadget + ensure_counts(MopedTest::Widget => 1, MopedTest::Gadget => 1) + truncation.clean + ensure_counts(MopedTest::Widget => 1, MopedTest::Gadget => 0) + end + end + + end + + end +end From 52b6f9f710011595c55b5e1e6ad4ec074c859d5a Mon Sep 17 00:00:00 2001 From: John Ferlito Date: Sun, 24 Mar 2013 13:12:34 +1100 Subject: [PATCH 04/10] Make clean_with work for multiple db connections clean_with avoids using strategy= so that it doesn't actually change the strategy. This means it was bypassing the section that set the database to actually clean and therefore it was always cleaning the default. --- lib/database_cleaner/base.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/database_cleaner/base.rb b/lib/database_cleaner/base.rb index e1830cf..1f3cc08 100644 --- a/lib/database_cleaner/base.rb +++ b/lib/database_cleaner/base.rb @@ -36,6 +36,12 @@ module DatabaseCleaner def clean_with(*args) strategy = create_strategy(*args) + if strategy.respond_to? :db= + strategy.db = self.db + elsif self.db != :default + raise ArgumentError, "You must provide a strategy object that supports non default databases when you specify a database" + end + strategy.clean strategy end From 4448362416c3524382782d0fbb757ea9bec21631 Mon Sep 17 00:00:00 2001 From: John Ferlito Date: Fri, 29 Mar 2013 18:58:23 +1100 Subject: [PATCH 05/10] refactor our common code --- lib/database_cleaner/base.rb | 16 ++++++++++------ spec/database_cleaner/base_spec.rb | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/database_cleaner/base.rb b/lib/database_cleaner/base.rb index 1f3cc08..4f82167 100644 --- a/lib/database_cleaner/base.rb +++ b/lib/database_cleaner/base.rb @@ -36,11 +36,7 @@ module DatabaseCleaner def clean_with(*args) strategy = create_strategy(*args) - if strategy.respond_to? :db= - strategy.db = self.db - elsif self.db != :default - raise ArgumentError, "You must provide a strategy object that supports non default databases when you specify a database" - end + set_strategy_db strategy, self.db strategy.clean strategy @@ -48,6 +44,14 @@ module DatabaseCleaner alias clean_with! clean_with + def set_strategy_db(strategy, desired_db) + if strategy.respond_to? :db= + strategy.db = desired_db + elsif desired_db != :default + raise ArgumentError, "You must provide a strategy object that supports non default databases when you specify a database" + end + end + def strategy=(args) strategy, *strategy_args = args if strategy.is_a?(Symbol) @@ -58,7 +62,7 @@ module DatabaseCleaner raise ArgumentError, "You must provide a strategy object, or a symbol for a known strategy along with initialization params." end - self.strategy_db = self.db + set_strategy_db @strategy, self.db @strategy end diff --git a/spec/database_cleaner/base_spec.rb b/spec/database_cleaner/base_spec.rb index 9225c6c..b590a30 100644 --- a/spec/database_cleaner/base_spec.rb +++ b/spec/database_cleaner/base_spec.rb @@ -334,7 +334,7 @@ module DatabaseCleaner it "should attempt to set strategy db" do subject.stub(:db).and_return(:my_db) - subject.should_receive(:strategy_db=).with(:my_db) + subject.should_receive(:set_strategy_db).with(mock_strategy, :my_db) subject.strategy = mock_strategy end From 947bb27a20e781a78a05b0a3a2f8aa14d58af89f Mon Sep 17 00:00:00 2001 From: Dave Brace Date: Sat, 30 Mar 2013 09:27:36 -0500 Subject: [PATCH 06/10] Removed use of Anonymous class when establishing a connection to a database via ActiveRecord since this is no longer supported in ActiveRecord 4. --- lib/database_cleaner/active_record/base.rb | 8 +------ .../active_record/base_spec.rb | 21 ++----------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/database_cleaner/active_record/base.rb b/lib/database_cleaner/active_record/base.rb index 99b0c4b..2a4fa16 100644 --- a/lib/database_cleaner/active_record/base.rb +++ b/lib/database_cleaner/active_record/base.rb @@ -38,10 +38,6 @@ module DatabaseCleaner end end - def create_connection_class - Class.new(::ActiveRecord::Base) - end - def connection_class @connection_class ||= if @db && !@db.is_a?(Symbol) @db @@ -63,9 +59,7 @@ module DatabaseCleaner end def establish_connection - strategy_class = create_connection_class - strategy_class.send :establish_connection, connection_hash - strategy_class + ::ActiveRecord::Base.establish_connection(connection_hash) end end diff --git a/spec/database_cleaner/active_record/base_spec.rb b/spec/database_cleaner/active_record/base_spec.rb index 4d8850e..4298ac7 100644 --- a/spec/database_cleaner/active_record/base_spec.rb +++ b/spec/database_cleaner/active_record/base_spec.rb @@ -119,16 +119,6 @@ my_db: end end - describe "create_connection_class" do - it "should return a class" do - subject.create_connection_class.should be_a(Class) - end - - it "should return a class extending ::ActiveRecord::Base" do - subject.create_connection_class.ancestors.should include(::ActiveRecord::Base) - end - end - describe "connection_class" do it { expect { subject.connection_class }.to_not raise_error } it "should default to ActiveRecord::Base" do @@ -158,16 +148,9 @@ my_db: before { ::ActiveRecord::Base.stub!(:respond_to?).and_return(false) } before { subject.stub(:connection_hash).and_return(hash) } - it "should create connection_class if it doesnt exist if connection_hash is set" do - subject.should_receive(:create_connection_class).and_return(mock('class').as_null_object) - subject.connection_class - end + it "establish a connection using ActiveRecord::Base" do + ::ActiveRecord::Base.should_receive(:establish_connection).with(hash) - it "should configure the class from create_connection_class if connection_hash is set" do - strategy_class = mock('strategy_class') - strategy_class.should_receive(:establish_connection).with(hash) - - subject.should_receive(:create_connection_class).and_return(strategy_class) subject.connection_class end end From e5068110040082d5a0d40a3ad62f4e3c5c41a850 Mon Sep 17 00:00:00 2001 From: John Hampton Date: Tue, 9 Apr 2013 09:02:29 -0700 Subject: [PATCH 07/10] Fixed failing active_record/transaction_spec --- spec/database_cleaner/active_record/transaction_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/database_cleaner/active_record/transaction_spec.rb b/spec/database_cleaner/active_record/transaction_spec.rb index 25aff0d..de70d7d 100644 --- a/spec/database_cleaner/active_record/transaction_spec.rb +++ b/spec/database_cleaner/active_record/transaction_spec.rb @@ -15,6 +15,7 @@ module DatabaseCleaner [:begin_transaction, :begin_db_transaction].each do |begin_transaction_method| context "using #{begin_transaction_method}" do before do + connection.stub(:transaction) connection.stub(begin_transaction_method) connection.stub(:respond_to?).with(:begin_transaction).and_return(:begin_transaction == begin_transaction_method) end @@ -35,6 +36,7 @@ module DatabaseCleaner connection.stub(:respond_to?).with(:increment_open_transactions).and_return(true) connection.stub(:increment_open_transactions) connection.should_receive(begin_transaction_method) + connection.should_receive(:transaction) Transaction.new.start end end From f70eceec6edc941203a719fdbd3bc4b16b3cd478 Mon Sep 17 00:00:00 2001 From: Ryota Arai Date: Fri, 19 Apr 2013 14:49:10 +0900 Subject: [PATCH 08/10] Fix a typo in README. --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index b6cc5b0..04bd5ff 100644 --- a/README.markdown +++ b/README.markdown @@ -98,7 +98,7 @@ Another approach is to have the transactions rolled back in the application's pr An easier, but slower, solution is to use the `:truncation` or `:deletion` strategy. -So what is fastest out of `:deletion` and `:truncation`? Well, it depends on your table structure and what percentage of tables you populate in an average test. The reasoning is out the the scope of this README but here is a [good SO answer on this topic for Postgres](http://stackoverflow.com/questions/11419536/postgresql-truncation-speed/11423886#11423886). +So what is fastest out of `:deletion` and `:truncation`? Well, it depends on your table structure and what percentage of tables you populate in an average test. The reasoning is out of the scope of this README but here is a [good SO answer on this topic for Postgres](http://stackoverflow.com/questions/11419536/postgresql-truncation-speed/11423886#11423886). Some people report much faster speeds with `:deletion` while others say `:truncation` is faster for them. The best approach therefore is it try all options on your test suite and see what is faster. From f1b215f1118ec4ae4fed9eb1252854b739290c85 Mon Sep 17 00:00:00 2001 From: "M.Shibuya" Date: Fri, 3 May 2013 23:02:34 +0900 Subject: [PATCH 09/10] Pass empty block to transaction method. Fixes #200 --- lib/database_cleaner/active_record/transaction.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/database_cleaner/active_record/transaction.rb b/lib/database_cleaner/active_record/transaction.rb index ee96ffb..551485c 100644 --- a/lib/database_cleaner/active_record/transaction.rb +++ b/lib/database_cleaner/active_record/transaction.rb @@ -9,7 +9,7 @@ module DatabaseCleaner::ActiveRecord def start # Hack to make sure that the connection is properly setup for # the clean code. - connection_class.connection.transaction + connection_class.connection.transaction{ } if connection_maintains_transaction_count? if connection_class.connection.respond_to?(:increment_open_transactions) From b70f09a3ed86e5a05d3fa419faef4801210a4fad Mon Sep 17 00:00:00 2001 From: James Conroy-Finn Date: Sat, 11 May 2013 14:16:01 +0100 Subject: [PATCH 10/10] Add Redis & Ohm support This contains the work of @hbpoison, updated to work with the current version of DatabaseCleaner. https://github.com/bmabey/database_cleaner/pull/87/files --- Gemfile | 2 + Gemfile.lock | 6 ++ README.markdown | 27 ++++++- examples/config/redis.yml | 8 +++ examples/features/support/env.rb | 9 ++- examples/lib/ohm_models.rb | 43 ++++++++++++ examples/lib/redis_models.rb | 65 +++++++++++++++++ features/cleaning.feature | 20 +++--- features/cleaning_default_strategy.feature | 2 + features/cleaning_multiple_orms.feature | 19 +++++ .../database_cleaner_steps.rb | 5 +- features/step_definitions/ohm_steps.rb | 31 ++++++++ features/step_definitions/redis_steps.rb | 31 ++++++++ lib/database_cleaner/base.rb | 8 ++- lib/database_cleaner/configuration.rb | 6 +- lib/database_cleaner/ohm/truncation.rb | 15 ++++ lib/database_cleaner/redis/base.rb | 31 ++++++++ lib/database_cleaner/redis/truncation.rb | 26 +++++++ spec/database_cleaner/base_spec.rb | 51 +++++++++++++- spec/database_cleaner/configuration_spec.rb | 9 ++- spec/database_cleaner/ohm/truncation_spec.rb | 70 +++++++++++++++++++ spec/database_cleaner/redis/base_spec.rb | 32 +++++++++ .../database_cleaner/redis/truncation_spec.rb | 63 +++++++++++++++++ 23 files changed, 559 insertions(+), 20 deletions(-) create mode 100644 examples/config/redis.yml create mode 100644 examples/lib/ohm_models.rb create mode 100644 examples/lib/redis_models.rb create mode 100644 features/step_definitions/ohm_steps.rb create mode 100644 features/step_definitions/redis_steps.rb create mode 100644 lib/database_cleaner/ohm/truncation.rb create mode 100644 lib/database_cleaner/redis/base.rb create mode 100644 lib/database_cleaner/redis/truncation.rb create mode 100644 spec/database_cleaner/ohm/truncation_spec.rb create mode 100644 spec/database_cleaner/redis/base_spec.rb create mode 100644 spec/database_cleaner/redis/truncation_spec.rb diff --git a/Gemfile b/Gemfile index 25912f1..4393d26 100755 --- a/Gemfile +++ b/Gemfile @@ -26,6 +26,8 @@ group :development do gem 'mysql', '~> 2.8.1' gem 'mysql2' gem 'pg' + gem 'sqlite3' + gem 'ohm', '~> 0.1.3' gem 'guard-rspec' end diff --git a/Gemfile.lock b/Gemfile.lock index 8c27645..cb65e90 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -135,6 +135,10 @@ GEM multi_json (1.5.0) mysql (2.8.1) mysql2 (0.3.11) + nest (1.1.2) + redis + ohm (0.1.5) + nest (~> 1.0) origin (1.0.11) pg (0.14.1) plucky (0.5.2) @@ -160,6 +164,7 @@ GEM rake (10.0.3) rdoc (3.12) json (~> 1.4) + redis (3.0.4) rest-client (1.6.7) mime-types (>= 1.16) rspec (2.12.0) @@ -213,6 +218,7 @@ DEPENDENCIES mongoid mysql (~> 2.8.1) mysql2 + ohm (~> 0.1.3) pg rake rspec-rails diff --git a/README.markdown b/README.markdown index 04bd5ff..ba20e4b 100644 --- a/README.markdown +++ b/README.markdown @@ -5,7 +5,7 @@ Database Cleaner is a set of strategies for cleaning your database in Ruby. The original use case was to ensure a clean state during tests. Each strategy is a small amount of code but is code that is usually needed in any ruby app that is testing with a database. -ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, and CouchPotato are supported. +ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, CouchPotato, Ohm and Redis are supported. [![Build Status](https://secure.travis-ci.org/bmabey/database_cleaner.png)](http://travis-ci.org/bmabey/database_cleaner) @@ -55,6 +55,18 @@ Here is an overview of the strategies supported for each library: Yes No + + Redis + Yes + No + No + + + Ohm + Yes + No + No + @@ -129,6 +141,9 @@ DatabaseCleaner.strategy = :truncation, {:only => %w[widgets dogs some_other_tab DatabaseCleaner.strategy = :truncation, {:except => %w[widgets]} ``` +With Ohm and Redis, `:only` and `:except` take a list of strings to be +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: @@ -297,6 +312,16 @@ Usage beyond that remains the same with `DatabaseCleaner.start` calling any setu DatabaseCleaner[:sequel] Multiple databases supported; specify Databasecleaner[:sequel, {:connection => Sequel.connect(uri)}] + + Redis + DatabaseCleaner[:redis] + Connection specified as Redis URI + + + Ohm + DatabaseCleaner[:ohm] + Connection specified as Redis URI + diff --git a/examples/config/redis.yml b/examples/config/redis.yml new file mode 100644 index 0000000..a3b6cba --- /dev/null +++ b/examples/config/redis.yml @@ -0,0 +1,8 @@ +test: + url: 'redis://localhost:6379/0' + +one: + url: 'redis://localhost:6379/1' + +two: + url: 'redis://localhost:6379/2' diff --git a/examples/features/support/env.rb b/examples/features/support/env.rb index 543b855..fad0cf1 100644 --- a/examples/features/support/env.rb +++ b/examples/features/support/env.rb @@ -15,6 +15,10 @@ another_orm = ENV['ANOTHER_ORM'] strategy = ENV['STRATEGY'] multiple_db = ENV['MULTIPLE_DBS'] +config = YAML::load(File.open("#{File.dirname(__FILE__)}/../../config/redis.yml")) +ENV['REDIS_URL'] = config['test']['url'] +ENV['REDIS_URL_ONE'] = config['one']['url'] +ENV['REDIS_URL_TWO'] = config['two']['url'] if orm && strategy $:.unshift(File.dirname(__FILE__) + '/../../../lib') @@ -37,6 +41,9 @@ if orm && strategy when :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 + when :redis, :ohm + DatabaseCleaner[ orm_sym, {:connection => ENV['REDIS_URL_ONE']} ].strategy = strategy.to_sym + DatabaseCleaner[ orm_sym, {:connection => ENV['REDIS_URL_TWO']} ].strategy = strategy.to_sym when :active_record DatabaseCleaner[:active_record, {:model => ActiveRecordWidgetUsingDatabaseOne} ].strategy = strategy.to_sym DatabaseCleaner[:active_record, {:model => ActiveRecordWidgetUsingDatabaseTwo} ].strategy = strategy.to_sym @@ -53,5 +60,5 @@ if orm && strategy end else - raise "Run 'ORM=ActiveRecord|DataMapper|MongoMapper|CouchPotato [ANOTHER_ORM=...] [MULTIPLE_DBS=true] STRATEGY=transaction|truncation|default cucumber examples/features'" + raise "Run 'ORM=ActiveRecord|DataMapper|MongoMapper|CouchPotato|Ohm|Redis [ANOTHER_ORM=...] [MULTIPLE_DBS=true] STRATEGY=transaction|truncation|default cucumber examples/features'" end diff --git a/examples/lib/ohm_models.rb b/examples/lib/ohm_models.rb new file mode 100644 index 0000000..12dd93d --- /dev/null +++ b/examples/lib/ohm_models.rb @@ -0,0 +1,43 @@ +require 'ohm' + +Ohm.connect :url => ENV['REDIS_URL'] + +class OhmWidget < Ohm::Model + attribute :name + + def self.create!(attrs = {}) + new({:name => 'some widget'}.merge(attrs)).save + end + + def self.count + all.count + end + +end + +class OhmWidgetUsingDatabaseOne < Ohm::Model + connect :url => ENV['REDIS_URL_ONE'] + attribute :name + + def self.create!(attrs = {}) + new({:name => 'a widget using database one'}.merge(attrs)).save + end + + def self.count + all.count + end + +end + +class OhmWidgetUsingDatabaseTwo < Ohm::Model + connect :url => ENV['REDIS_URL_TWO'] + attribute :name + + def self.create!(attrs = {}) + new({:name => 'a widget using database two'}.merge(attrs)).save + end + + def self.count + all.count + end +end diff --git a/examples/lib/redis_models.rb b/examples/lib/redis_models.rb new file mode 100644 index 0000000..d8ee053 --- /dev/null +++ b/examples/lib/redis_models.rb @@ -0,0 +1,65 @@ +require 'redis' + +class RedisWidget + + def self.redis + threaded ||= Redis.connect + end + + def self.redis=(connection) + threaded = connection + end + + def self.threaded + Thread.current[self.class.to_s] ||= {} + end + + def initialize(options = {}) + options = options.dup + @name = options[:name] + end + + def connection + self.class.redis + end + + def save + unless connection.get(self.class.to_s + ':id') + @id = 0 + connection.set(self.class.to_s + ':id', @id) + end + @id = connection.incr(self.class.to_s + ':id') + connection.set(self.class.to_s + ':%d:name' % @id, @name) + end + + def self.count + self.redis.keys(self.to_s + '*name').size + end + + def self.create! + new(:name => 'some widget').save + + end +end + +class RedisWidgetUsingDatabaseOne < RedisWidget + + def self.redis + threaded[self.class.to_s] ||= Redis.connect :url => ENV['REDIS_URL_ONE'] + end + + def self.create! + new(:name => 'a widget using database one').save + end +end + +class RedisWidgetUsingDatabaseTwo < RedisWidget + + def self.redis + threaded[self.class.to_s] ||= Redis.connect :url => ENV['REDIS_URL_TWO'] + end + + def self.create! + new(:name => 'a widget using database two').save + end +end diff --git a/features/cleaning.feature b/features/cleaning.feature index 7602e88..da1a347 100644 --- a/features/cleaning.feature +++ b/features/cleaning.feature @@ -11,12 +11,14 @@ Feature: database cleaning Then I should see all green Examples: - | ORM | Strategy | - | ActiveRecord | transaction | - | ActiveRecord | truncation | - | ActiveRecord | deletion | - | DataMapper | transaction | - | DataMapper | truncation | - | MongoMapper | truncation | - | Mongoid | truncation | - | CouchPotato | truncation | + | ORM | Strategy | + | ActiveRecord | transaction | + | ActiveRecord | truncation | + | ActiveRecord | deletion | + | DataMapper | transaction | + | DataMapper | truncation | + | MongoMapper | truncation | + | Mongoid | truncation | + | CouchPotato | truncation | + | Redis | truncation | + | Ohm | truncation | diff --git a/features/cleaning_default_strategy.feature b/features/cleaning_default_strategy.feature index 7f96ec3..cb565ab 100644 --- a/features/cleaning_default_strategy.feature +++ b/features/cleaning_default_strategy.feature @@ -17,3 +17,5 @@ Feature: database cleaning | MongoMapper | | Mongoid | | CouchPotato | + | Redis | + | Ohm | diff --git a/features/cleaning_multiple_orms.feature b/features/cleaning_multiple_orms.feature index ded7064..5368e50 100644 --- a/features/cleaning_multiple_orms.feature +++ b/features/cleaning_multiple_orms.feature @@ -15,15 +15,34 @@ Feature: database cleaning using multiple ORMs | ActiveRecord | MongoMapper | | ActiveRecord | Mongoid | | ActiveRecord | CouchPotato | + | ActiveRecord | Ohm | + | ActiveRecord | Redis | | DataMapper | ActiveRecord | | DataMapper | MongoMapper | | DataMapper | Mongoid | | DataMapper | CouchPotato | + | DataMapper | Ohm | + | DataMapper | Redis | | MongoMapper | ActiveRecord | | MongoMapper | DataMapper | | MongoMapper | Mongoid | | MongoMapper | CouchPotato | + | MongoMapper | Ohm | + | MongoMapper | Redis | | CouchPotato | ActiveRecord | | CouchPotato | DataMapper | | CouchPotato | MongoMapper | | CouchPotato | Mongoid | + | CouchPotato | Ohm | + | CouchPotato | Redis | + | Ohm | ActiveRecord | + | Ohm | DataMapper | + | Ohm | MongoMapper | + | Ohm | Mongoid | + | Ohm | CouchPotato | + | Redis | ActiveRecord | + | Redis | DataMapper | + | Redis | MongoMapper | + | Redis | Mongoid | + | Redis | CouchPotato | + | Redis | Ohm | diff --git a/features/step_definitions/database_cleaner_steps.rb b/features/step_definitions/database_cleaner_steps.rb index 1663d0a..4a663d6 100644 --- a/features/step_definitions/database_cleaner_steps.rb +++ b/features/step_definitions/database_cleaner_steps.rb @@ -1,10 +1,11 @@ +orms_pattern = /(ActiveRecord|DataMapper|MongoMapper|Mongoid|CouchPotato|Redis|Ohm)/ -Given /^I am using (ActiveRecord|DataMapper|MongoMapper|Mongoid|CouchPotato)$/ do |orm| +Given /^I am using #{orms_pattern}$/ do |orm| @feature_runner = FeatureRunner.new @feature_runner.orm = orm end -Given /^I am using (ActiveRecord|DataMapper|MongoMapper|CouchPotato|Mongoid) and (ActiveRecord|DataMapper|MongoMapper|CouchPotato|Mongoid)$/ do |orm1,orm2| +Given /^I am using #{orms_pattern} and #{orms_pattern}$/ do |orm1,orm2| @feature_runner = FeatureRunner.new @feature_runner.orm = orm1 @feature_runner.another_orm = orm2 diff --git a/features/step_definitions/ohm_steps.rb b/features/step_definitions/ohm_steps.rb new file mode 100644 index 0000000..89670f8 --- /dev/null +++ b/features/step_definitions/ohm_steps.rb @@ -0,0 +1,31 @@ +Given /^I have setup database cleaner to clean multiple databases using ohm$/ do + #DatabaseCleaner + # require "#{File.dirname(__FILE__)}/../../../lib/ohm_models" + # + # DatabaseCleaner[:ohm, {:connection => ENV['REDIS_URL_ONE']} ].strategy = :truncation + # DatabaseCleaner[:ohm, {:connection => ENV['REDIS_URL_TWO']} ].strategy = :truncation +end + +When /^I create a widget using ohm$/ do + OhmWidget.create! +end + +Then /^I should see ([\d]+) widget using ohm$/ do |widget_count| + OhmWidget.count.should == widget_count.to_i +end + +When /^I create a widget in one db using ohm$/ do + OhmWidgetUsingDatabaseOne.create! +end + +When /^I create a widget in another db using ohm$/ do + OhmWidgetUsingDatabaseTwo.create! +end + +Then /^I should see ([\d]+) widget in one db using ohm$/ do |widget_count| + OhmWidgetUsingDatabaseOne.count.should == widget_count.to_i +end + +Then /^I should see ([\d]+) widget in another db using ohm$/ do |widget_count| + OhmWidgetUsingDatabaseTwo.count.should == widget_count.to_i +end diff --git a/features/step_definitions/redis_steps.rb b/features/step_definitions/redis_steps.rb new file mode 100644 index 0000000..80611a0 --- /dev/null +++ b/features/step_definitions/redis_steps.rb @@ -0,0 +1,31 @@ +Given /^I have setup database cleaner to clean multiple databases using redis$/ do + #DatabaseCleaner + # require "#{File.dirname(__FILE__)}/../../../lib/redis_models" + # + # DatabaseCleaner[:redis, {:connection => ENV['REDIS_URL_ONE']} ].strategy = :truncation + # DatabaseCleaner[:redis, {:connection => ENV['REDIS_URL_TWO']} ].strategy = :truncation +end + +When /^I create a widget using redis$/ do + RedisWidget.create! +end + +Then /^I should see ([\d]+) widget using redis$/ do |widget_count| + RedisWidget.count.should == widget_count.to_i +end + +When /^I create a widget in one db using redis$/ do + RedisWidgetUsingDatabaseOne.create! +end + +When /^I create a widget in another db using redis$/ do + RedisWidgetUsingDatabaseTwo.create! +end + +Then /^I should see ([\d]+) widget in one db using redis$/ do |widget_count| + RedisWidgetUsingDatabaseOne.count.should == widget_count.to_i +end + +Then /^I should see ([\d]+) widget in another db using redis$/ do |widget_count| + RedisWidgetUsingDatabaseTwo.count.should == widget_count.to_i +end diff --git a/lib/database_cleaner/base.rb b/lib/database_cleaner/base.rb index 4f82167..478c2d8 100644 --- a/lib/database_cleaner/base.rb +++ b/lib/database_cleaner/base.rb @@ -132,8 +132,12 @@ module DatabaseCleaner :sequel elsif defined? ::Moped :moped + elsif defined? ::Ohm + :ohm + elsif defined? ::Redis + :redis else - raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, Moped, or CouchPotato loaded?" + raise NoORMDetected, "No known ORM was detected! Is ActiveRecord, DataMapper, Sequel, MongoMapper, Mongoid, Moped, or CouchPotato, Redis or Ohm loaded?" end end end @@ -142,7 +146,7 @@ module DatabaseCleaner case orm when :active_record, :data_mapper, :sequel self.strategy = :transaction - when :mongo_mapper, :mongoid, :couch_potato, :moped + when :mongo_mapper, :mongoid, :couch_potato, :moped, :ohm, :redis self.strategy = :truncation end end diff --git a/lib/database_cleaner/configuration.rb b/lib/database_cleaner/configuration.rb index 01665c1..5bebcda 100644 --- a/lib/database_cleaner/configuration.rb +++ b/lib/database_cleaner/configuration.rb @@ -11,7 +11,7 @@ module DatabaseCleaner # ghetto ordered hash.. maintains 1.8 compat and old API @connections ||= [] end - + def [](orm,opts = {}) raise NoORMDetected unless orm init_cleaners @@ -113,6 +113,10 @@ module DatabaseCleaner DatabaseCleaner::CouchPotato when :sequel DatabaseCleaner::Sequel + when :ohm + DatabaseCleaner::Ohm + when :redis + DatabaseCleaner::Redis end end end diff --git a/lib/database_cleaner/ohm/truncation.rb b/lib/database_cleaner/ohm/truncation.rb new file mode 100644 index 0000000..1747a32 --- /dev/null +++ b/lib/database_cleaner/ohm/truncation.rb @@ -0,0 +1,15 @@ +require 'database_cleaner/redis/truncation' + +module DatabaseCleaner + module Ohm + class Truncation < ::DatabaseCleaner::Redis::Truncation + + private + + def default_redis + ::Ohm.redis + end + + end + end +end diff --git a/lib/database_cleaner/redis/base.rb b/lib/database_cleaner/redis/base.rb new file mode 100644 index 0000000..2e0e054 --- /dev/null +++ b/lib/database_cleaner/redis/base.rb @@ -0,0 +1,31 @@ +require 'database_cleaner/generic/base' + +module DatabaseCleaner + module Redis + def self.available_strategies + %w{truncation} + end + + module Base + include ::DatabaseCleaner::Generic::Base + + def db=(desired_db) + @db = desired_db + end + + def db + @db || :default + end + + alias url db + + private + + def connection + @connection ||= url == :default ? ::Redis.connect : ::Redis.connect(:url => url) + end + + end + end +end + diff --git a/lib/database_cleaner/redis/truncation.rb b/lib/database_cleaner/redis/truncation.rb new file mode 100644 index 0000000..32badcc --- /dev/null +++ b/lib/database_cleaner/redis/truncation.rb @@ -0,0 +1,26 @@ +require 'database_cleaner/redis/base' +require 'database_cleaner/generic/truncation' + +module DatabaseCleaner + module Redis + class Truncation + include ::DatabaseCleaner::Redis::Base + include ::DatabaseCleaner::Generic::Truncation + + def clean + if @only + @only.each do |term| + connection.keys(term).each { |k| connection.del k } + end + elsif @tables_to_exclude + keys_except = [] + @tables_to_exclude.each { |term| keys_except += connection.keys(term) } + connection.keys.each { |k| connection.del(k) unless keys_except.include?(k) } + else + connection.flushdb + end + connection.quit unless url == :default + end + end + end +end diff --git a/spec/database_cleaner/base_spec.rb b/spec/database_cleaner/base_spec.rb index b590a30..5fca85e 100644 --- a/spec/database_cleaner/base_spec.rb +++ b/spec/database_cleaner/base_spec.rb @@ -19,6 +19,8 @@ module DatabaseCleaner Temp_CP = ::CouchPotato if defined?(::CouchPotato) and not defined?(Temp_CP) Temp_SQ = ::Sequel if defined?(::Sequel) and not defined?(Temp_SQ) Temp_MP = ::Moped if defined?(::Moped) and not defined?(Temp_MP) + Temp_RS = ::Redis if defined?(::Redis) and not defined?(Temp_RS) + Temp_OH = ::Ohm if defined?(::Ohm) and not defined?(Temp_OH) end #Remove all ORM mocks and restore from cache @@ -30,6 +32,8 @@ module DatabaseCleaner Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) Object.send(:remove_const, 'Sequel') if defined?(::Sequel) Object.send(:remove_const, 'Moped') if defined?(::Moped) + Object.send(:remove_const, 'Ohm') if defined?(::Ohm) + Object.send(:remove_const, 'Redis') if defined?(::Redis) # Restore ORMs @@ -39,6 +43,8 @@ module DatabaseCleaner ::Mongoid = Temp_MO if defined? Temp_MO ::CouchPotato = Temp_CP if defined? Temp_CP ::Moped = Temp_MP if defined? Temp_MP + ::Ohm = Temp_OH if defined? Temp_OH + ::Redis = Temp_RS if defined? Temp_RS end #reset the orm mocks @@ -50,8 +56,10 @@ module DatabaseCleaner Object.send(:remove_const, 'CouchPotato') if defined?(::CouchPotato) Object.send(:remove_const, 'Sequel') if defined?(::Sequel) Object.send(:remove_const, 'Moped') if defined?(::Moped) + Object.send(:remove_const, 'Ohm') if defined?(::Ohm) + Object.send(:remove_const, 'Redis') if defined?(::Redis) end - + let(:cleaner) { DatabaseCleaner::Base.new :autodetect } it "should raise an error when no ORM is detected" do @@ -66,6 +74,8 @@ module DatabaseCleaner Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') cleaner.orm.should == :active_record cleaner.should be_auto_detected @@ -78,6 +88,8 @@ module DatabaseCleaner Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') cleaner.orm.should == :data_mapper cleaner.should be_auto_detected @@ -89,6 +101,8 @@ module DatabaseCleaner Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') cleaner.orm.should == :mongo_mapper cleaner.should be_auto_detected @@ -99,6 +113,8 @@ module DatabaseCleaner Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') cleaner.orm.should == :mongoid cleaner.should be_auto_detected @@ -108,6 +124,8 @@ module DatabaseCleaner Object.const_set('CouchPotato', 'Couching mock potatos') Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') cleaner.orm.should == :couch_potato cleaner.should be_auto_detected @@ -116,12 +134,29 @@ module DatabaseCleaner it "should detect Sequel sixth" do Object.const_set('Sequel', 'Sequel mock') Object.const_set('Moped', 'Moped mock') + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') cleaner.orm.should == :sequel cleaner.should be_auto_detected end - it "should detect Moped seventh" do + it 'detects Ohm seventh' do + Object.const_set('Ohm', 'Ohm mock') + Object.const_set('Redis', 'Redis mock') + + cleaner.orm.should == :ohm + cleaner.should be_auto_detected + end + + it 'detects Redis last' do + Object.const_set('Redis', 'Redis mock') + + cleaner.orm.should == :redis + cleaner.should be_auto_detected + end + + it 'detects Moped seventh' do Object.const_set('Moped', 'Moped mock') cleaner.orm.should == :moped @@ -177,7 +212,7 @@ module DatabaseCleaner cleaner = ::DatabaseCleaner::Base.new "mongoid" cleaner.orm.should == :mongoid end - + it "is autodetected if orm is not provided" do cleaner = ::DatabaseCleaner::Base.new cleaner.should be_auto_detected @@ -508,6 +543,16 @@ module DatabaseCleaner cleaner = DatabaseCleaner::Base.new(:moped) cleaner.strategy.should be_instance_of DatabaseCleaner::Moped::Truncation end + + it 'sets strategy to :truncation for Ohm' do + cleaner = DatabaseCleaner::Base.new(:ohm) + cleaner.strategy.should be_instance_of DatabaseCleaner::Ohm::Truncation + end + + it 'sets strategy to :truncation for Redis' do + cleaner = DatabaseCleaner::Base.new(:redis) + cleaner.strategy.should be_instance_of DatabaseCleaner::Redis::Truncation + end end end diff --git a/spec/database_cleaner/configuration_spec.rb b/spec/database_cleaner/configuration_spec.rb index 9bec7a6..81babd4 100644 --- a/spec/database_cleaner/configuration_spec.rb +++ b/spec/database_cleaner/configuration_spec.rb @@ -62,6 +62,13 @@ describe ::DatabaseCleaner do cleaner.orm.should == :moped ::DatabaseCleaner.connections.size.should == 1 end + + it 'accepts :ohm' do + cleaner = ::DatabaseCleaner[:ohm] + cleaner.should be_a(::DatabaseCleaner::Base) + cleaner.orm.should == :ohm + ::DatabaseCleaner.connections.size.should == 1 + end end it "should accept multiple orm's" do @@ -126,7 +133,7 @@ describe ::DatabaseCleaner do it "should give me a default (autodetection) databasecleaner by default" do cleaner = mock("cleaner").as_null_object ::DatabaseCleaner::Base.stub!(:new).and_return(cleaner) - + ::DatabaseCleaner.connections.should == [cleaner] end end diff --git a/spec/database_cleaner/ohm/truncation_spec.rb b/spec/database_cleaner/ohm/truncation_spec.rb new file mode 100644 index 0000000..d638b0a --- /dev/null +++ b/spec/database_cleaner/ohm/truncation_spec.rb @@ -0,0 +1,70 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'ohm' +require 'database_cleaner/ohm/truncation' + +module DatabaseCleaner + module Ohm + + class Widget < ::Ohm::Model + attribute :name + end + + class Gadget < ::Ohm::Model + attribute :name + end + + describe Truncation do + before(:all) do + config = YAML::load(File.open("#{File.dirname(__FILE__)}/../../../examples/config/redis.yml")) + ::Ohm.connect :url => config['test']['url'] + @redis = ::Ohm.redis + end + + before(:each) do + @redis.flushdb + end + + it "should flush the database" do + Truncation.new.clean + end + + def create_widget(attrs={}) + Widget.new({:name => 'some widget'}.merge(attrs)).save + end + + def create_gadget(attrs={}) + Gadget.new({:name => 'some gadget'}.merge(attrs)).save + end + + it "truncates all keys by default" do + create_widget + create_gadget + @redis.keys.size.should == 6 + Truncation.new.clean + @redis.keys.size.should == 0 + end + + context "when keys are provided to the :only option" do + it "only truncates the specified keys" do + create_widget + create_gadget + @redis.keys.size.should == 6 + Truncation.new(:only => ['*Widget*']).clean + @redis.keys.size.should == 3 + @redis.get('DatabaseCleaner::Ohm::Gadget:id').should == '1' + end + end + + context "when keys are provided to the :except option" do + it "truncates all but the specified keys" do + create_widget + create_gadget + @redis.keys.size.should == 6 + Truncation.new(:except => ['*Widget*']).clean + @redis.keys.size.should == 3 + @redis.get('DatabaseCleaner::Ohm::Widget:id').should == '1' + end + end + end + end +end diff --git a/spec/database_cleaner/redis/base_spec.rb b/spec/database_cleaner/redis/base_spec.rb new file mode 100644 index 0000000..89704e5 --- /dev/null +++ b/spec/database_cleaner/redis/base_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' +require 'database_cleaner/redis/base' +require 'database_cleaner/shared_strategy' + +module DatabaseCleaner + describe Redis do + it { should respond_to(:available_strategies) } + end + + module Redis + class ExampleStrategy + include ::DatabaseCleaner::Redis::Base + end + + describe ExampleStrategy do + + it_should_behave_like "a generic strategy" + it { should respond_to(:db) } + it { should respond_to(:db=) } + + it "should store my describe db" do + url = 'redis://localhost:6379/2' + subject.db = 'redis://localhost:6379/2' + subject.db.should == url + end + + it "should default to :default" do + subject.db.should == :default + end + end + end +end diff --git a/spec/database_cleaner/redis/truncation_spec.rb b/spec/database_cleaner/redis/truncation_spec.rb new file mode 100644 index 0000000..5406306 --- /dev/null +++ b/spec/database_cleaner/redis/truncation_spec.rb @@ -0,0 +1,63 @@ +require File.dirname(__FILE__) + '/../../spec_helper' +require 'redis' +require 'database_cleaner/redis/truncation' + + +module DatabaseCleaner + module Redis + + describe Truncation do + before(:all) do + config = YAML::load(File.open("#{File.dirname(__FILE__)}/../../../examples/config/redis.yml")) + @redis = ::Redis.connect :url => config['test']['url'] + end + + before(:each) do + @redis.flushdb + end + + it "should flush the database" do + Truncation.new.clean + end + + def create_widget(attrs={}) + @redis.set 'Widget', 1 + end + + def create_gadget(attrs={}) + @redis.set 'Gadget', 1 + end + + it "truncates all keys by default" do + create_widget + create_gadget + @redis.keys.size.should == 2 + Truncation.new.clean + @redis.keys.size.should == 0 + end + + context "when keys are provided to the :only option" do + it "only truncates the specified keys" do + create_widget + create_gadget + @redis.keys.size.should == 2 + Truncation.new(:only => ['Widge*']).clean + @redis.keys.size.should == 1 + @redis.get('Gadget').should == '1' + end + end + + context "when keys are provided to the :except option" do + it "truncates all but the specified keys" do + create_widget + create_gadget + @redis.keys.size.should == 2 + Truncation.new(:except => ['Widg*']).clean + @redis.keys.size.should == 1 + @redis.get('Widget').should == '1' + end + end + end + end +end +