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.93k stars 484 forks source link

Rspec tests freeze as soon as DatabaseCleaner begins to work #701

Closed toomanyjoes closed 1 year ago

toomanyjoes commented 1 year ago

I'm in the middle of a painful upgrade from Rails 5.2.7 to 6.1 (as well as Ruby 2.7.6 to 3.1.4) and DatabaseCleaner is the bulk of my headache. At this point the specs are just freezing as soon as the cleaner begins its work. My setup is rather complicated but based on everything I've pieced together I believe my syntax is correct for what I'm trying to accomplish.

I have a two database setup: Postgres and a legacy mysql database that both need to be cleaned. Here is what I currently have in my rails helper including required files which there isn't much documentation on. I have a hunch maybe I have too many or two few requires.

Relevant Gems

  capybara (~> 3.39)
  capybara-screenshot
  database_cleaner-active_record
  geckodriver-helper
  selenium-webdriver (~> 4.11)

database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: localhost

test:
  <<: *default
  database: test_db

test_legacy:
  url: <%= ENV['LEGACY_DB_TEST_URL'] %>
  adapter: mysql2
  connect_timeout:

rails_helper.rb

  require 'spec_helper'
  require 'rspec/rails'
  require 'devise'
  require 'support/devise_login_helper'
  require 'support/factory_bot'
  require 'paper_trail/frameworks/rspec'
  require 'selenium/webdriver'
  require 'capybara/rails'
  require 'database_cleaner/active_record'
  require 'support/select2_helper'
  require 'support/feature_spec_helpers/wait_for_ajax'
  require 'support/feature_spec_helpers/sessions'
  require 'capybara-screenshot/rspec'

  config.use_transactional_fixtures = false

  config.before(:suite) do
    if config.use_transactional_fixtures?
      raise(<<-MSG)
        Delete line `config.use_transactional_fixtures = true` from rails_helper.rb
        (or set it to false) to prevent uncommitted transactions being used in
        JavaScript-dependent specs.

        During testing, the app-under-test that the browser driver connects to
        uses a different database connection to the database connection used by
        the spec. The app's database connection would not be able to access
        uncommitted transaction data setup over the spec's database connection.
      MSG
    end
    DatabaseCleaner[:active_record, db: :test_legacy].clean_with(:truncation)
    DatabaseCleaner[:active_record, db: ApplicationRecord].clean_with(:truncation, { except: %w[submission_statuses submission_definitions] })
    DatabaseCleaner.strategy = :transaction
  end

  config.after(:all) do
    DatabaseCleaner[:active_record, db: :test_legacy].clean_with(:truncation)
    DatabaseCleaner[:active_record, db: ApplicationRecord].clean_with(:truncation, { except: %w[submission_statuses submission_definitions] })
  end

  config.before(:each) do |example|
    if example.metadata[:js]
      DatabaseCleaner.strategy = :truncation
    elsif example.metadata[:type] == :feature
      # :rack_test driver's Rack app under test shares database connection
      # with the specs, so continue to use transaction strategy for speed.
      driver_shares_db_connection_with_specs = Capybara.current_driver == :rack_test

      unless driver_shares_db_connection_with_specs
        # Driver is probably for an external browser with an app
        # under test that does *not* share a database connection with the
        # specs, so use truncation strategy.
        DatabaseCleaner.strategy = :truncation
      end
    end
  end

  config.before(:each) do
    DatabaseCleaner[:active_record, db: :test_legacy].start
    DatabaseCleaner[:active_record, db: ApplicationRecord].start
  end

  config.append_after(:each) do
    DatabaseCleaner[:active_record, db: :test_legacy].clean
    DatabaseCleaner[:active_record, db: ApplicationRecord].clean
  end

for the line:

DatabaseCleaner[:active_record, db: ApplicationRecord].clean_with(:truncation, { except: %w[submission_statuses submission_definitions] })

I've tried several different things including:

DatabaseCleaner[:active_record, db: :test].clean_with(:truncation, { except: %w[submission_statuses submission_definitions] })

and

DatabaseCleaner[:active_record].clean_with(:truncation, { except: %w[submission_statuses submission_definitions] })

and

DatabaseCleaner.clean_with(:truncation, { except: %w[submission_statuses submission_definitions] })

All with no success. It's frustrating because there is zero to go off of here. The test suite just stops running with no errors:

The test.log file looks like this:

   (0.2ms)  SELECT @@FOREIGN_KEY_CHECKS
   (0.1ms)  SET FOREIGN_KEY_CHECKS = 0
   (0.6ms)  select table_name from information_schema.views where table_schema = 'legacy_test'

and it only chokes on the legacy because it's cleaning comes first in the code, if I switch the order it chokes on the Postgres DB instead.

I've removed DB cleaner altogether and turned back on use_transactional_fixtures just as a test and my tests run fine until I run a test that uses the legacy database. The transactional fixtures apparently only works for the one main postgres db.

I found some old questions about this very same thing that had been closed so I wanted to post my question here to see if others are experiencing the same issue.

Looking forward to your help! Thanks!

toomanyjoes commented 1 year ago

Well after several hours of trying things I just threw up my hands and rebooted my machine and the problem seems to have gone away