How do you integrate Resque functions in Cucumber?

I am trying to apply the Square method of including Resque in my integration tests without much luck. I'm not sure if Resque and / or Cucumber have changed much since August 2010.

Below you will find the approach I took, and perhaps you can:

  • Tell me where I made a mistake and how I can fix it.
  • Recommend a completely new way to integrate Resque features into Cucumber

What i did to install it

There were no explicit installation steps on the blog, so I did this:

  • Downloaded their gist in features/support/cucumber_external_resque_worker.rb
  • Created a Rails initializer in config/initializers/cucumber_external_resque.rb , which did the following:
    • require 'features/support/cucumber_external_resque_worker'
    • CucumberExternalResqueWorker.install_hooks_on_startup
  • In cucumber_external_resque_worker.rb have I changed instances of Rails.env.cucumber? on Rails.env.test? because Cucumber ran functions in the test environment (I did a few puts Rails.env in cucumber_external_resque_worker.rb ).
  • I run functions. At this point, I'm stuck because I get an uninitialized constant WorkerBase (NameError) . Perhaps Resque has changed the way he calls things.

Thanks in advance!

+4
source share
3 answers

You can simply run the Resque task synchronously by setting

 Resque.inline = true 

I added this line to my config/initializers/resque.rb :

 Resque.inline = Rails.env.test? 

This is more concise than other approaches suggested in the post. Since it is synchronous, it will be a little slower.

+6
source

Today I spent time with this, and I think I have a solution.

Here's an updated Gist that eliminates the need for WorkerBase.

It also includes the configuration changes needed to get the job to work (identical to the changes you discovered).


 # 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 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 

In the Cucumber features/support/env.rb environment file

After:

 require 'cucumber/rails' 

Add

 require 'lib/cucumber_external_resque_worker' CucumberExternalResqueWorker.start 

Edit:

  DatabaseCleaner.strategy = :transaction 

in

  DatabaseCleaner.strategy = :truncation 

Also create a file: 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". 
+3
source

I try the approach described here:

Cucumbers and quests Resque

which performs processing of rezkeys synchronously. In my case, I'm not interested in testing Resque, I just want to test the functionality in my application.

0
source

All Articles