DatabaseCleaner / database_cleaner

Strategies for cleaning databases in Ruby. Can be used to ensure a clean state for testing.
https://www.rubydoc.info/github/DatabaseCleaner/database_cleaner
MIT License
2.94k stars 483 forks source link

cleaner not cleaning database records. #447

Closed paudelprerana closed 6 years ago

paudelprerana commented 8 years ago

Configuratin in spec_helper.rb is as:-

ruby RSpec.configure do |config| config.expect_with :rspec do |expectations| expectations.include_chain_clauses_in_custom_matcher_descriptions = true end config.mock_with :rspec do |mocks| mocks.verify_partial_doubles = true end

Clean up the database, database_cleaner setup with Rspec.

require 'database_cleaner'

config.before(:suite) do DatabaseCleaner.orm = 'mongoid' DatabaseCleaner.strategy = :truncation end

config.before(:each) do DatabaseCleaner.start end

config.after(:each) do DatabaseCleaner.clean end end



rails version 4.2.4, ruby version 2.1.3, database_cleaner version 1.5.1, rspec version 3.4.0, mongoid version 5.1.0
OS Linux Mint.

The main problem is same application code, when run on Ubuntu 14.04 (on mates OS) works perfectly (ie database_cleaner in cleaning all the thing and working properly), but same code base does not work on my Mint machine. Is it issue with OS(ie mint) or gems installed in my OS(ie mint) or the gem database_cleaner itself. Hoping you guys will help me out on figuring out this problem, let me know if you need additional logs. Thanks. Happy Coding.
etagwerker commented 8 years ago

@paudelprerana Could you try with database_cleaner v1.5.3 and report back?

paudelprerana commented 8 years ago

@etagwerker I tested with database_cleaner v1.5.3 and its not working.

iamanujvrma commented 8 years ago

@paudelprerana Hi , I was also facing the same issue while trying to clean my database with Database Cleaner. Then i tried to clean database in some other machine having exactly the same configuration for ruby, rails, mongoid, database cleaner version, and yes it was working fine. The issue on my machine was because of the mongo version. I have installed the latest version of mongo i.e 3.2.8 and on other machine it was an older version i.e 2.4.12. Then i installed an old release of mongo, and database cleaner started working fine. What is your mongo version ? Please install a version below 2.7 and tell me if its working.

neumachen commented 8 years ago

I'm having this issue but with Postgres, I am using Postgres 9.5 with Rails 5.

module DatabaseHelper
  def self.before_all
    self.before_suite
  end

  def self.before_suite
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  def self.establish_connection
    connection_info = Rails.configuration.database_configuration[Rails.env]
    ActiveRecord::Base.establish_connection(connection_info)
  end

  def self.around(example: example = nil, block: block = nil)
    if example
      DatabaseCleaner.cleaning do
        example.run
      end
    elsif block
      DatabaseCleaner.cleaning(&block)
    end
  end
end
RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseHelper.before_suite
  end

  config.around(:each) do |example|
    DatabaseHelper.around(example: example)
  end
end
levi-l-damian commented 7 years ago

I have the same issues, DataCleaner not cleaning. I am also using Postgres 9.5 and Rails 5.

Here is my database_cleaner.rb file:

RSpec.configure do |config| config.before(:suite) do DatabaseCleaner.clean_with(:truncation) end config.before(:each) do DatabaseCleaner.strategy = :transaction end config.before(:each, :js => true) do DatabaseCleaner.strategy = :truncation end config.before(:each) do DatabaseCleaner.start end config.after(:each) do DatabaseCleaner.clean end end

And in the file rspec_helper.rb I added a line like this: config.include FactoryGirl::Syntax::Methods

and I changed an existent one like this: config.use_transactional_fixtures = false

After each run, my records count in the table is increased: Failures:

1) OrganizationsController POST #create with valid attributes create new organization Failure/Error: expect(Organization.count).to eq(1)

   expected: 1
        got: 15
mltsy commented 7 years ago

To help narrow down these issues, you might try a blank rails 5 app with just two tests and see if you can reproduce the error by changing one thing at a time. I just tried a new rails 5 app with postgres 9.5, and it's working fine for me. Here's a start:

mkdir db-cleaner-test
cd db-cleaner-test
rails new . -T --database=postgresql
echo "gem 'rspec'" >> Gemfile
echo "gem 'database_cleaner'" >> Gemfile
bundle install
rails g rspec:install
echo "--require rails_helper" >> .rspec
rails g migration create_people
echo "class Person < ApplicationRecord; end" > app/models/person.rb

Then setup database.yml to point to a local postgres server, and run rails db:setup

Add in the default database_cleaner stuff:

spec/rails_helper.rb:

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end

Finally, add a spec that will test your person model, something like:

spec/models/person_spec.rb:

describe "Person" do
  before { Person.create }
  it "should have 1 person the first time" do
    expect(Person.count). to be 1
  end
  it "should still only have 1 person the second time" do
    expect(Person.count). to be 1
  end
end

Now... figure out how to make it fail and post back here!

P.S. Sorry, I've never used mongoid, so I'm not sure what the corresponding steps would be, but it can't be too difficult to modify :wink:

arambert commented 7 years ago

I got a similar problem with rails 5.0.2, ActiveRecord and a transaction strategy. I switched to truncation, it now works correctly.

ryanong commented 7 years ago

I added a new strategy. The transaction isn't clear across all threads

require 'database_cleaner/active_record/base'
require 'database_cleaner/generic/transaction'

module DatabaseCleaner::ActiveRecord
  class Transaction4
    include ::DatabaseCleaner::ActiveRecord::Base
    include ::DatabaseCleaner::Generic::Transaction

    def start
      @fixture_connections = enlist_fixture_connections
      @fixture_connections.each do |connection|
        connection.begin_transaction joinable: false
      end
    end

    def clean
      @fixture_connections.each do |connection|
        connection.rollback_transaction if connection.transaction_open?
      end
      @fixture_connections.clear
      connection_class.clear_active_connections!
    end

    def enlist_fixture_connections
      connection_class.connection_handler.connection_pool_list.map(&:connection)
    end
  end
end
arambert commented 7 years ago

I tried your new strategy and it works perfectly! DatabaseCleaner.strategy = DatabaseCleaner::ActiveRecord::Transaction4.new

This probably justifies a PR, don't you think?

ryanong commented 7 years ago

probably. https://github.com/rails/rails/blob/5-0-stable/activerecord/lib/active_record/fixtures.rb#L963 if you want some context around what is going on

arambert commented 7 years ago

I've switched back to truncation because event with the fix suggested by @ryanong it fails sometimes to properly reset the database 😢

Is anyone getting the same problem with the transaction strategy?

mgiagante commented 6 years ago

[SOLVED]

I'm having the same problem, with Rails 5.1.4 and PostgreSQL 9.5.10. Might this be related to environments? Does database_cleaner know it has to clean the test database without any config?

RSpec.configure do |config|
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end
end

Edit: This wasn't actually a problem in the gem. I was doing something wrong in RSpec. My code was creating the records in a before(:all) block, while the DatabaseCleaner.clean call was being performed in a before(:each) block. And as I was using the Transaction strategy, the transactions that created the records were not able to be rolled back by the gem and hence no deletion was being done.

After I added the record creation to the before(:each) block, the database cleaning worked OK. Also, it could've been "solved" by using the Truncation strategy, since it doesn't depend on the transactions.

Hope this helps to anyone having the same problem I had.

LauraKirby commented 6 years ago

@mgiagante thank you for your post! Rails: 5.1.4 MySql2: 0.4.10

I had modified spec/support/databse_cleaner.rb (remembering to include the file in rails_helper.rb below require 'support/factory_bot' and to set config.use_transactional_fixtures = false) in a variety of ways and nothing worked. Each time I ran my tests, the previous database objects persisted.

Solution:

RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.strategy = :transaction
    DatabaseCleaner.clean_with(:truncation)
  end

  config.around(:each) do |example|
    DatabaseCleaner.cleaning do
      example.run
    end
  end

  # RSpec Rails can automatically mix in different behaviours to your tests
  # based on their file location, for example enabling you to call `get` and
  # `post` in specs under `spec/controllers`.
  #
  # You can disable this behaviour by removing the line below, and instead
  # explicitly tag your specs with their type, e.g.:
  #
  #     RSpec.describe UsersController, :category => :controller do
  #       # ...
  #     end
  #
  # The different available types are documented in the features, such as in
  # https://relishapp.com/rspec/rspec-rails/docs
  config.infer_spec_type_from_file_location!

  # Filter lines from Rails gems in backtraces.
  config.filter_rails_from_backtrace!
  # arbitrary gems may also be filtered via:
  # config.filter_gems_from_backtrace("gem name")
end
jshumakerpruitt commented 6 years ago

@LauraKirby's solution worked for me. (OpenBSD 6.1, Rails 5.1.4, PostgreSQL 9.6.2)

mgiagante commented 6 years ago

@LauraKirby I'm glad to be of help! As far as I know, it doesn't matter if the configuration is split into two files or unified, as long as it is correctly defined. So don't hesitate to extract parts of it to additional files and require them if it adds up to your code organization.

ryan-plated commented 6 years ago

rails 5.1 updated their transaction strategy so I re-ported it over

require 'database_cleaner/active_record/base'
require 'database_cleaner/generic/transaction'

module DatabaseCleaner::ActiveRecord
  class Transaction5
    include ::DatabaseCleaner::ActiveRecord::Base
    include ::DatabaseCleaner::Generic::Transaction

    def start
      @fixture_connections = enlist_fixture_connections
      @fixture_connections.each do |connection|
        connection.begin_transaction joinable: false
        connection.pool.lock_thread = true
      end

      # When connections are established in the future, begin a transaction too
      @connection_subscriber = ActiveSupport::Notifications.subscribe("!connection.active_record") do |_, _, _, _, payload|
        spec_name = payload[:spec_name] if payload.key?(:spec_name)

        if spec_name
          begin
            connection = ActiveRecord::Base.connection_handler.retrieve_connection(spec_name)
          rescue ConnectionNotEstablished
            connection = nil
          end

          if connection && !@fixture_connections.include?(connection)
            connection.begin_transaction joinable: false
            connection.pool.lock_thread = true
            @fixture_connections << connection
          end
        end
      end
    end

    def clean
      ActiveSupport::Notifications.unsubscribe(@connection_subscriber) if @connection_subscriber

      @fixture_connections.each do |connection|
        connection.rollback_transaction if connection.transaction_open?
        connection.pool.lock_thread = false
      end
      @fixture_connections.clear
      connection_class.clear_active_connections!
    end

    def enlist_fixture_connections
      connection_class.connection_handler.connection_pool_list.map(&:connection)
    end
  end
end
Bodacious commented 6 years ago

I came across this issue today. Eventually, I realised that the records that weren't being cleaned were being created within a before(:all) block in one of my specs.

Posting here in case anyone else makes the same error.

ghost commented 5 years ago

@Bodacious I also met same problem like you. Below is the solution of your problem. https://github.com/DatabaseCleaner/database_cleaner/issues/489 If you don't mention the problem, I can't solve that! Thank you.