Deadlock detected by capybara-webkit

I am trying to pass this specification:

scenario "Edit a service", js: true do service = create_service_for(provider, title: "First service") fill_edit_service_form(service) expect(page).to have_css('#price', text: '10,00 $') end 

This is the standard rail specification using capybara. I use capybara-webkit for all javascript scripts. When I try to transfer it, sometimes it works, sometimes it notes what the database is missing from, and sometime I get this error:

 Run options: include {:locations=>{"./spec/acceptances/provider_services_spec.rb"=>[31]}} [K 1) Provider Services Edit a service Failure/Error: Unable to find matching line from backtrace ActiveRecord::StatementInvalid: PG::TRDeadlockDetected: ERROR: deadlock detected DETAIL: Process 24164 waits for AccessExclusiveLock on relation 3446991 of database 3446538; blocked by process 24184. Process 24184 waits for AccessShareLock on relation 3446902 of database 3446538; blocked by process 24164. HINT: See server log for query details. : ALTER TABLE "active_admin_comments" DISABLE TRIGGER ALL;ALTER TABLE "provider_service_territory_provideds" DISABLE TRIGGER ALL;ALTER TABLE "provider_services" DISABLE TRIGGER ALL;ALTER TABLE "provider_divisions" DISABLE TRIGGER ALL;ALTER TABLE "provider_profiles" DISABLE TRIGGER ALL;ALTER TABLE "provider_service_intervention_level_provideds" DISABLE TRIGGER ALL;ALTER TABLE "provider_service_medium_provideds" DISABLE TRIGGER ALL;ALTER TABLE "provider_service_service_provideds" DISABLE TRIGGER ALL;ALTER TABLE "regions" DISABLE TRIGGER ALL;ALTER TABLE "service_formulas" DISABLE TRIGGER ALL;ALTER TABLE "region_translations" DISABLE TRIGGER ALL;ALTER TABLE "artists" DISABLE TRIGGER ALL;ALTER TABLE "admin_users" DISABLE TRIGGER ALL;ALTER TABLE "schema_migrations" DISABLE TRIGGER ALL;ALTER TABLE "services" DISABLE TRIGGER ALL;ALTER TABLE "services_provided" DISABLE TRIGGER ALL;ALTER TABLE "territories_provided" DISABLE TRIGGER ALL;ALTER TABLE "users" DISABLE TRIGGER ALL;ALTER TABLE "countries" DISABLE TRIGGER ALL;ALTER TABLE "coupons" DISABLE TRIGGER ALL;ALTER TABLE "currencies" DISABLE TRIGGER ALL;ALTER TABLE "formulas" DISABLE TRIGGER ALL;ALTER TABLE "collector_profiles" DISABLE TRIGGER ALL;ALTER TABLE "country_translations" DISABLE TRIGGER ALL;ALTER TABLE "images" DISABLE TRIGGER ALL;ALTER TABLE "intervention_levels_provided" DISABLE TRIGGER ALL;ALTER TABLE "measure_units" DISABLE TRIGGER ALL;ALTER TABLE "media_provided" DISABLE TRIGGER ALL;ALTER TABLE "messages" DISABLE TRIGGER ALL;ALTER TABLE "page_part_translations" DISABLE TRIGGER ALL;ALTER TABLE "orders" DISABLE TRIGGER ALL;ALTER TABLE "painting_categories" DISABLE TRIGGER ALL;ALTER TABLE "page_services" DISABLE TRIGGER ALL;ALTER TABLE "page_translations" DISABLE TRIGGER ALL;ALTER TABLE "painting_category_translations" DISABLE TRIGGER ALL;ALTER TABLE "page_parts" DISABLE TRIGGER ALL;ALTER TABLE "pages" DISABLE TRIGGER ALL;ALTER TABLE "painting_provenances" DISABLE TRIGGER ALL;ALTER TABLE "painting_prices" DISABLE TRIGGER ALL;ALTER TABLE "painting_technic_translations" DISABLE TRIGGER ALL;ALTER TABLE "painting_technics" DISABLE TRIGGER ALL;ALTER TABLE "painting_type_translations" DISABLE TRIGGER ALL;ALTER TABLE "period_translations" DISABLE TRIGGER ALL;ALTER TABLE "painting_types" DISABLE TRIGGER ALL;ALTER TABLE "paintings" DISABLE TRIGGER ALL;ALTER TABLE "periods" DISABLE TRIGGER ALL # -e:1:in `<main>' 1/1 |========================= 100 ==========================>| Time: 00:00:03 Finished in 3.41 seconds 1 example, 1 failure Failed examples: rspec ./spec/acceptances/provider_services_spec.rb:29 # Provider Services Edit a service Screenshot: /home/dougui/rails/lescollectionneurs/tmp/capybara/screenshot_2014-02-20-18-22-55.658.png Randomized with seed 34053 

I have a lock on a table. This is not always the same table.

Better when I do this:

 Capybara.reset_sessions! DatabaseCleaner.clean 

Before and after the specification, but it does not always work. If I run all my specifications in one file, I am not working.

It is added when I worked on unrelated things. He works with a poltergeist.

This is my spec_helper file:

 ENV["RAILS_ENV"] ||= 'test' require 'rubygems' require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'rspec/autorun' require 'capybara/rails' require 'capybara-webkit' require 'database_cleaner' require 'capybara/firebug' require 'capybara-screenshot/rspec' if defined?(Spring) Spring.watch "#{Rails.root}/spec/factories" else require 'shoulda-matchers' end Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} RSpec.configure do |config| config.infer_base_class_for_anonymous_controllers = false config.use_transactional_fixtures = false config.order = "random" config.include FactoryGirl::Syntax::Methods config.include Warden::Test::Helpers, type: :feature config.include FeatureHelpers, type: :feature config.include Devise::TestHelpers, type: :controller config.include ControllerHelpers, type: :controller config.include EmailSpec::Helpers config.include EmailSpec::Matchers config.before(:suite) do DatabaseCleaner.strategy = :transaction DatabaseCleaner.clean_with(:truncation) end config.before(:each) do if example.metadata[:js] DatabaseCleaner.strategy = :truncation else DatabaseCleaner.start end end config.after(:each) do DatabaseCleaner.clean DatabaseCleaner.strategy = :transaction if example.metadata[:js] end end Capybara.javascript_driver = :webkit include ActionDispatch::TestProcess I18n.locale = :fr Geocoder.configure(:lookup => :test) Geocoder::Lookup::Test.set_default_stub( [ { 'latitude' => 40.7143528, 'longitude' => -74.0059731, 'address' => 'New York, NY, USA', 'state' => 'New York', 'state_code' => 'NY', 'country' => 'United States', 'country_code' => 'US' } ] ) 

The gem used here is: https://github.com/GCorbel/lescollectionneursassocies/blob/master/Gemfile .

Any suggestions?

See the Github repository for more details: https://github.com/GCorbel/lescollectionneursassocies/ .

+7
source share
4 answers

This is because you have two threads: test and query, modifying the database asynchronously. It looks like you experimented correctly with various configurations in your spec_helper. I spent a lot of time trying to solve this problem and came up with the following:

 # adapted from https://gist.github.com/moonfly/4950750 require 'database_cleaner' RSpec.configure do |config| config.use_transactional_fixtures = false config.before( :suite ) do DatabaseCleaner.clean_with :truncation DatabaseCleaner.strategy = :transaction end config.around( :each ) do |spec| if spec.metadata[:js] # JS => does not share connections => can't use transactions spec.run DatabaseCleaner.clean_with :deletion else # No JS/Devise => run with Rack::Test => transactions are ok DatabaseCleaner.start spec.run DatabaseCleaner.clean # see https://github.com/bmabey/database_cleaner/issues/99 begin ActiveRecord::Base.connection.send :rollback_transaction_records, true rescue end end end end 

I store all this in support / database_cleaner_configuration.rb, which is also suitable for you, or you can simply replace what is in your spec_helper. If this does not work, let me know - I have several other ideas, but they are stranger, and you should not delve into it if it works, which will probably be ...

Note:

It may be worth mentioning that Rails 5. 1+ solves the database problem. Eileen Teacher from the Rails team made the changes necessary to run so that the test threads and the Rails server can work in the same process by sharing a database connection.

+16
source

You have a dead end when there are two threads that run tests. For example, open a tab in a terminal and run tests using the rspec . Immediately open the second tab in the terminal and run the tests there with the same command.

So, I think you just ran all the tests in one tab and tried to run a specific test using the rspec spec/acceptances/provider_services_spec.rb:31 command in another tab.

0
source

The most likely reason is that some query passing through the ajax / database cleaner prematurely truncates the database while the sql query is being executed. One way is to force the webkit driver to wait for the ajax request to complete. Add this method to the test helpers and call it after you click the button / submit the ajax form.

  def wait_for_ajax_to_finish looping = true loop do sleep 1 begin count = page.evaluate_script('window.running_ajax_calls').to_i looping = false if count == 0 rescue => e if e.message.include? 'HTMLunitCorejsJavascript::Undefined' raise "For 'wait for the AJAX call to finish' to work, please include culerity.js after including jQuery." else raise e end end end end 
0
source

I had different tests with an error randomly (for example, one test out of 500, every time I ran the package).

This may not be the most suitable solution, but I solved the problem by simply soldering and repeating the database cleanup after 2 seconds, for example:

 config.after(:each) do |example| begin DatabaseCleaner.clean rescue Exception => e # Recover from thread locks and retry the database clean after a slight delay sleep 2 DatabaseCleaner.clean end end 
0
source

All Articles