2016-08-28 2 views
18

Я пытаюсь написать спецификацию, которая проверяет функциональность повтора retque-retry, и я, похоже, не могу получить тесты, чтобы правильно нажать на binding.pry. Есть ли способ проверить эту функциональность с помощью rspec 3, чтобы я мог проверить, что они функционируют по назначению?Как протестировать повторы и сбои в resque-retry и Rails 4?

Это спецификация запроса, и я пытаюсь имитировать живой запрос через приборы, но независимо от того, что я пытаюсь, я не могу заставить задание повторить попытку.

gem 'resque', require: 'resque/server' 
gem 'resque-web', require: 'resque_web' 
gem 'resque-scheduler' 
gem 'resque-retry' 
gem 'resque-lock-timeout' 

Я использую resque_rspec, и пытается это testing strategy.

Частичное Spec

it 'retries it' do 
    stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200) 
    @order_shipped_json['order']['originator_id'] = @provider_order 
    post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json 
    ResqueSpec.perform_all(queue_name) 
    ??? 
end 

очереди заданий Модули

class QueueHook 
    extend Resque::Plugins::LockTimeout 
    extend Resque::Plugins::Retry 
    extend QueueLock 
    extend QueueLogger 

    @queue = AppSettings.queues[:hook_queue_name].to_sym 
    @lock_timeout = 600 
    @retry_exceptions = [QueueError::LockFailed] 
    @retry_limit = 600 
    @retry_delay = 1 

    class << self 
    def perform(web_hook_payload_id, _whiplash_customer_id) 
     ActiveRecord::Base.clear_active_connections! 
     @web_hook_payload = WebHookPayload.find(web_hook_payload_id) 
     klass_constructor 
     @hook.process_event 
    end 

    def identifier(_web_hook_payload_id, whiplash_customer_id) 
     "lock:integration_hook:#{whiplash_customer_id}" 
    end 

    def after_perform_delete_webhook(_web_hook_payload_id, _whiplash_customer_id) 
     @web_hook_payload.destroy 
    end 

    private 

    ... 
    end 
end 

Queue Работа

module QueueLogger 
    def before_perform_log_job(*args) 
    Rails.logger.info "[Resque][#{self}] running with #{args.inspect}..." 
    end 

    def on_failure_log_job(*args) 
    message = "[Resque][#{self}] failed with #{args.inspect}..." 
    run_counters 
    Rails.logger.info message_builder(message) 
    end 

    private 

    def run_counters 
    @num_attempts += retry_attempt 
    @all_attempts += retry_limit 
    end 

    def message_builder(message) 
    return message unless @num_attempts 
    return message += " Retrying (attempt ##{@num_attempts + 1})" if @num_attempts < @all_attempts 
    message += ' Giving up.' 
    message 
    end 
end 

module QueueLock 
    def loner_enqueue_failed(*args) 
    Rails.logger.info "[Resque][#{self}] is already enqueued: #{args.inspect}..." 
    end 

    def lock_failed(*) 
    raise QueueError::LockFailed 
    end 
end 
+0

Вы должны использовать обработчики исключений. – user1735921

+1

у вас есть пример spec? –

+0

Не используйте повтор повторного использования, перехватите исключения и повторите попытку в коде – user1735921

ответ

1

Таким образом, конкретный сбой, который вы хотите протестировать, исходит из этого используемого вами крючка.

def lock_failed(*) 
    raise QueueError::LockFailed 
end 

Нам нужно вызвать это. Here - это место, где он используется в плагине. Так как вы используете тайм-аут блокировки, похоже, мы хотим заглушить .acquire_lock_algorithm!. Это опасно, так как этот метод является частью внутреннего api плагина. Имейте это в виду, когда вы обновляете плагин.

it 'retries it' do 
    stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200) 

    allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true) 

    @order_shipped_json['order']['originator_id'] = @provider_order 
    post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json 

    ResqueSpec.perform_all(queue_name) 
end 

Эта спецификация должна быть сбойной с Failure/Error: raise QueueError::LockFailed. Поскольку мы ожидаем, что мы сможем рассчитывать.

it 'retries it' do 
    stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200) 

    allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true) 

    @order_shipped_json['order']['originator_id'] = @provider_order 
    post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json 

    expect { 
    ResqueSpec.perform_all(queue_name) 
    }.to raise_error(QueueError::LockFailed) 
end 

Спецификация должна быть передана, если вы не установили ResqueSpec.inline = true. Если вы установили значение false для этой спецификации. Будет легче следовать.

Если resque-retry работает, то сбой работы должен был привести к повторной постановке задания на ResqueSpec. Мы можем добавить к этому ожидание. expect(ResqueSpec.queues[queue_name]).to be_present. Нельзя снова запустить задания. Мы высмеивали второе возвращаемое значение acquire_lock_algorithm!, чтобы быть правдой, поэтому работа должна быть успешной на этот раз.

Поскольку мы хотим, чтобы проверить счетчики позволяет добавить читателей для них

module QueueLogger 
    attr_reader :all_attempts, :num_attempts 
end 

А затем закончить спецификации ...

it 'retries it' do 
    stub_request(:any, /.*api.bigcartel.*/).to_return(body: '{}', status: 200) 

    allow(QueueHook).to receive(:acquire_lock_algorithm!).and_return(false, true) 

    @order_shipped_json['order']['originator_id'] = @provider_order 
    post "/hook/shops/#{@shop.id}", @order_shipped_json.to_json, format: :json 

    # Failing 
    expect { 
    ResqueSpec.perform_all(queue_name) 
    }.to raise_error(QueueError::LockFailed) 
    expect(ResqueSpec.queues[queue_name]).to be_present 

    # Retrying 
    ResqueSpec.perform_all(queue_name) 
    expect(QueueHook.num_attempts).to eq(2) 
    ... # Whatever else you want to test. 
end 

Если вы хотите, чтобы проверить регистрацию специально вы окурок их и установить ожидания относительно того, с чем они призваны. Это должно сделать это, у меня есть упрощенная версия, запущенная на моей собственной машине. Если нет, нам, возможно, придется вдаваться в подробности ваших тестов и конфигураций Resque.

1

Несколько Notes-

1) Как уже упоминалось, вы, вероятно, захотите отделить обратные вызовы resque от их функциональности. То есть, проверьте, стреляют ли retries, но и отдельно проверяют, что они функционируют должным образом. Вы можете разделить их на два отдельных теста.

2) Для проверки того, что они стреляют, я думаю, что вы ищете class doubles в RSpec 3.

Вам нужно будет instatiate двойной, а затем поднять исключение (docs). Это позволит вам увидеть, вызваны ли ваши retries и сколько раз они были вызваны (docs).

Так, например,

it "retries on exception n number of times" do 
    queue_hook = class_double("QueueHook") 
    expect(queue_hook).to have_received(:on_failure_log_job).exactly(n).times 
    allow(queue_hook).to receive(:perform).and_raise(ExceptionClass, "Exception message") 
    queue_hook.perform(payload_id, customer_id) 
end 

Там справедливый бит происходит, поэтому я не могу реализовать на местном уровне, но мы надеемся, что это может помочь вам получить движение в правильном направлении.

Смежные вопросы