2016-08-28 11 views
18

私はresque-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をしようとしています。

部分的なスペック

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 

キュー仕事モジュール

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

サンプル仕様はありますか? –

+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!という2番目の戻り値を偽りましたので、今度はこのジョブが成功するはずです。

我々はカウンターをテストしたいので、彼らのために

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つの別々のテストに分けたいと思うかもしれません。彼らは発射されていることを確認するために

2)、私はあなたがRSpecの中class doubles 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 

起こって公平なビットありますので、私はローカルに実装することはできませんが、うまくいけば、これはあなたが正しい方向に軌道に乗ることができます。

関連する問題