用capybara-webkit检测到死锁

我正试图通过这个规范:

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 

这是使用水豚的标准导轨规格。 我使用capybara-webkit用于javascript的所有场景。 当我试图传递它时,有时候它会起作用,有时它标记的数据库中有一条丢失的记录,有时候我有这个错误:

 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 `' 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 

我把桌子锁了。 这并不总是相同的表。

当我这样做时,它会更好:

 Capybara.reset_sessions! DatabaseCleaner.clean 

规范之前和之后但并不总是有效。 如果我在同一个文件中运行所有规范,我就无法工作。

它在我处理不相关的事情时附加。 它与恶作剧者合作。

这是我的spec_helper文件:

 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' } ] ) 

以下是使用的gem: https : //github.com/GCorbel/lescollectionneursassocies/blob/master/Gemfile 。

有什么建议?

有关详细信息,请查看Github回购: https : //github.com/GCorbel/lescollectionneursassocies/ 。

发生这种情况是因为您有两个线程,即测试和请求,异步修改数据库。 您似乎正确地在spec_helper中尝试了不同的配置。 我花了相当多的时间来解决同样的问题,并提出了这个问题:

 # 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 => doesn't 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 

我把它全部保存在support / database_cleaner_configuration.rb中,这对你也有用,或者你可以简单地替换spec_helper中的内容。 如果这不起作用,请告诉我 – 我还有其他一些想法,但它们更怪异,如果这样可行则不值得进入,它可能会……

当有两个运行测试的线程时,您会遇到死锁。 例如,在终端中打开一个选项卡,然后使用rspec命令运行测试。 立即打开终端中的第二个选项卡,并使用相同的命令在那里运行测试。

所以,我想您只是在一个选项卡中运行所有测试,并尝试在其他选项卡中使用rspec spec/acceptances/provider_services_spec.rb:31命令运行特定测试。

最可能的原因是必须通过ajax / database清理器进行一些查询,在sql查询运行时过早地截断数据库。 其中一种方法是让webkit驱动程序等到ajax请求完成。 在测试助手中添加此方法,并在单击按钮/提交ajax表单后调用它。

  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 

我有不同的测试随机失败(比如500个中的1个测试,每次我运行套件)。

这可能不是最漂亮的解决方案,但我通过在2秒后拯救并重试数据库清理器来解决问题,如下所示:

 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