7

我正在通过 capybara-webkit 驱动程序上的 parallel_tests 运行我的规范。我有以下红宝石环境:

 ruby -v
 ruby 1.9.3p125 (2012-02-16 revision 34643) [x86_64-darwin11.4.2]

在包含以下内容的 gemset 上运行 rvm(为了相关性而截断了 capybara、rails、rspec 和 parallel_tests。如果看到我的 gemset 的更大范围会有所帮助,请告诉我):

 *** LOCAL GEMS ***

 ...
 capybara (1.1.2)
 parallel_tests (0.8.12)
 rails (3.2.11)
 rspec (2.11.0)

当我在单个进程上运行我的测试服时rake spec,我的所有测试都会运行完成。但是,在运行 parallel_tests 时,会发生以下情况:

 8 processes for 220 specs, ~ 27 specs per process

此后,这些进程最终将开始返回:

 Finished in 11 minutes 15.76 seconds
 Finished in 11 minutes 28.89 seconds

但是,在前 6 个进程返回后,parallel_spec 将无限期挂起,永远不会终止,并且永远不会打印剩余 2 个进程的输出。

我在运行 OS X Lion 的 MacBook Pro 上,配备 2.4GHz Intel i7。

所以我的问题很简单:它为什么挂起,我如何调试它挂起的原因,以及如何阻止它挂起并允许 parallel_tests 运行完成?

4

2 回答 2

2

缺少有关您的 rspec 配置和库使用的一些信息,您可能会得到答案。也就是说,在为集成规范运行 rspec 时,我在多线程环境中看到了类似的行为。

在https://github.com/grosser/parallel_tests/wiki上找到的建议在集成规范方面似乎具有误导性。试图依靠or的transaction策略保证会导致任何非阻塞数据库适配器的死锁。DatabaseCleaneruse_transactional_fixtures

Capybara 为集成规范启动了多个线程。当客户端和服务器线程尝试同时与相同的记录进行交互时,您通常会遇到超时或死锁。有时,死锁会导致您的套件运行永久挂起,直到它被手动终止。

我发现防止这种情况发生的最可靠的配置是共享ActiveRecord实例之间的连接和明智地使用DatabaseCleaner.

# integration_spec_helper.rb

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

  class ActiveRecord::Base
    class_attribute :shared_connection

    def self.connection
      self.shared_connection || retrieve_connection
    end
  end

  config.before do |example|
    ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

    if Capybara.current_driver == :webkit
      DatabaseCleaner.strategy = :deletion
    else
      DatabaseCleaner.strategy = :transaction
    end

    DatabaseCleaner.start
  end

  config.after do
    DatabaseCleaner.clean
  end
end
于 2013-06-10T14:29:28.573 回答
2

为了调试您的 Parallel 规范执行被卡住的位置,您需要知道进程的行为方式。这意味着如果一个或多个进程卡住了,他们这样做的规范是什么。

为此,您需要对 rspec 配置进行一些修改:

# Allows to access hanging spec name and source
# Throw the following command in a terminal whenever a spec is hanging
# $ ps -ef | grep rspec
RSpec.configure do |config|
  config.around :each do |example|
    title  = example.metadata[:full_description]
    source =  example.metadata[:block].source_location.join ":"
    $0 = %{rspec #{source} "#{title}"}
    example.run
  end
end

然后打开另一个终端并执行:

ps -ef | grep "rspec /"

最初它将显示几个过程,例如:

julian    7128  7073 93 10:10 pts/1    00:09:54 rspec /home/julian/Lenda/lenda/spec/models/disclosures/docusign/refinance_loan_estimate_form_spec.rb:17 "RefinanceLoanEstimateForm should be able to be generated from non-completed applications"
julian    7141  7073 93 10:10 pts/1    00:09:50 rspec /home/julian/Lenda/lenda/spec/models/disclosures/disclosure_document_spec.rb:14 "DisclosureDocument retrieves fields signed by a signer"
julian    7147  7073 94 10:10 pts/1    00:09:58 rspec /home/julian/Lenda/lenda/spec/controllers/api/v1/applications_controller_spec.rb:192 "Api::V1::ApplicationsController admin user GET #show with a valid application_id "

您需要监控这些过程,直到它们不再发生变化。当它们完成时,它们会消失,所以最后,您可能只会卡住一两个进程,但这实际上取决于您的测试套件。

从那里您需要单独调试该测试以找到问题。

于 2019-08-30T15:39:12.337 回答