我一直试图申请Square's method of including Resque in their integration tests而没有太多运气。自2010年8月以来,我不确定Resque和/或Cucumber是否发生了很大的变化。
下面你会找到我采取的方法,也许你可以:
Square的博客文章没有关于如何安装它的明确步骤,所以这就是我所做的:
features/support/cucumber_external_resque_worker.rb
config/initializers/cucumber_external_resque.rb
创建了一个执行以下操作的Rails初始值设定项:
require 'features/support/cucumber_external_resque_worker'
CucumberExternalResqueWorker.install_hooks_on_startup
cucumber_external_resque_worker.rb
中,我将Rails.env.cucumber?
的实例更改为Rails.env.test?
,因为Cucumber正在运行test
环境中的功能(我在puts Rails.env
中执行了cucumber_external_resque_worker.rb
{1}}确定。uninitialized constant WorkerBase (NameError)
而陷入困境。也许Resque改变了它命名的方式。提前致谢!
答案 0 :(得分:6)
您可以通过设置
同步运行Resque作业Resque.inline = true
我将此行添加到config/initializers/resque.rb
:
Resque.inline = Rails.env.test?
它比帖子中提出的其他方法更简洁。由于它是同步的,它会慢一点。
答案 1 :(得分:3)
今天我花了一些时间玩这个,我想我有一个解决方案。
这是一个更新的Gist,它不再需要WorkerBase。
它还包括使事情正常工作所需的配置更改(与您发现的更改相同)。
# This is adapted from this gist: https://gist.github.com/532100 by Square
# The main difference is that it doesn't require Bluth for WorkerBase
# It also calls prune_dead_workers on start so it doesn't hang on every other run
# It does not do anything special to avoid connecting to your main redis instance; you should be
# doing that elsewhere
class CucumberExternalResqueWorker
DEFAULT_STARTUP_TIMEOUT = 1.minute
COUNTER_KEY = "cucumber:counter"
class << self
attr_accessor :pid, :startup_timeout
def start
# Call from a Cucumber support file so it is run on startup
return unless Rails.env.test?
if self.pid = fork
start_parent
wait_for_worker_to_start
else
start_child
end
end
def install_hooks_on_startup
# Call from a Rails initializer
return unless Rails.env.test?
# Because otherwise crashed workers cause a fork and we pause the actual worker forever
Resque::Worker.all.each { |worker| worker.prune_dead_workers }
install_pause_on_start_hook
install_worker_base_counter_patch
end
def process_all
# Call from a Cucumber step
unpause
sleep 1 until done?
pause
end
def incr
Resque.redis.incr(COUNTER_KEY)
end
def decr
Resque.redis.decr(COUNTER_KEY)
end
def reset_counter
Resque.redis.set(COUNTER_KEY, 0)
end
private
def done?
Resque.redis.get(CucumberExternalResqueWorker::COUNTER_KEY).to_i.zero?
end
def pause(pid = self.pid)
return unless Rails.env.test?
Process.kill("USR2", pid)
end
def unpause
return unless Rails.env.test?
Process.kill("CONT", pid)
end
def start_parent
at_exit do
#reset_counter
Process.kill("KILL", pid) if pid
end
end
def start_child
# Array form of exec() is required here, otherwise the worker is not a direct child process of cucumber.
# If it's not the direct child process then the PID returned from fork() is wrong, which means we can't
# communicate with the worker.
exec('rake', 'resque:work', "QUEUE=*", "RAILS_ENV=test", "VVERBOSE=1")
end
def wait_for_worker_to_start
self.startup_timeout ||= DEFAULT_STARTUP_TIMEOUT
start = Time.now.to_i
while (Time.now.to_i - start) < startup_timeout
return if worker_started?
sleep 1
end
raise "Timeout while waiting for the worker to start. Waited #{startup_timeout} seconds."
end
def worker_started?
Resque.info[:workers].to_i > 0
end
def install_pause_on_start_hook
Resque.before_first_fork do
#reset_counter
pause(Process.pid)
end
end
def install_worker_base_counter_patch
Resque.class_eval do
class << self
def enqueue_with_counters(*args, &block)
CucumberExternalResqueWorker.incr
enqueue_without_counters(*args, &block)
end
alias_method_chain :enqueue, :counters
end
end
Resque::Job.class_eval do
def perform_with_counters(*args, &block)
perform_without_counters(*args, &block)
ensure
CucumberExternalResqueWorker.decr
end
alias_method_chain :perform, :counters
end
end
end
end
在Cucumber环境文件features/support/env.rb
后:
require 'cucumber/rails'
添加:
require 'lib/cucumber_external_resque_worker'
CucumberExternalResqueWorker.start
变化:
DatabaseCleaner.strategy = :transaction
为:
DatabaseCleaner.strategy = :truncation
另外,创建一个文件:config/initializers/cucumber_external_resque.rb
require 'lib/cucumber_external_resque_worker'
CucumberExternalResqueWorker.install_hooks_on_startup
# In my controller, I have:
def start
if params[:job] then
Resque.enqueue(DemoJob, j.id)
end
redirect_to :action => :index
end
# DemoJob:
class DemoJob
def self.queue
:demojob
end
def perform(job_id)
j = Job.find(job_id)
j.value = "done"
j.save
end
# In your actual Cucumber step file, for instance:
When /I click the start button for "([^"]*)"/ do |jobname|
CucumberExternalResqueWorker.reset_counter
Resque.remove_queue(DemoJob.queue)
click_button(jobname)
end
When /all open jobs are processed/ do
CucumberExternalResqueWorker.process_all
end
# And you cucumber feature file looks like:
# Scenario: Starting a job
# When I click the start button for "Test Job 1"
# And all open jobs are processed
# Then I am on the job index page
# And I should see an entry for "Test Job 1" with a value of "done".
答案 2 :(得分:0)