2016-08-28 12 views
18

Tôi đang cố gắng viết một thông số kỹ thuật để kiểm tra chức năng thử lại của quá trình thử lại và tôi dường như không thể lấy các phép thử để đạt được giá trị của binding.pry một cách chính xác. Có cách nào để kiểm tra chức năng này bằng cách sử dụng rspec 3 để tôi có thể xác minh chúng hoạt động như dự định không?Làm thế nào để kiểm tra thử lại và thất bại trong resque-retry và Rails 4?

Đây là thông số yêu cầu và tôi đang cố gắng mô phỏng yêu cầu trực tiếp thông qua đồ đạc, nhưng cho dù tôi cố gắng làm gì, dường như tôi không thể thử lại công việc.

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

Tôi đang sử dụng resque_rspec và thử số testing strategy này.

phần 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 

Queue Job Modules

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 Job

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

Bạn phải sử dụng trình xử lý ngoại lệ. – user1735921

+1

bạn có thông số mẫu không? –

+0

không sử dụng thử lại giải cứu, bắt ngoại lệ và thử lại trong mã – user1735921

Trả lời

1

Vì vậy, lỗi cụ thể mà bạn muốn thử lại cho đến từ móc này bạn đã triển khai.

def lock_failed(*) 
    raise QueueError::LockFailed 
end 

Chúng tôi cần kích hoạt tính năng này. Here là nơi nó được sử dụng trong plugin. Vì bạn đang sử dụng thời gian chờ khóa có vẻ như chúng tôi muốn khai báo .acquire_lock_algorithm!. Điều này là nguy hiểm vì phương pháp này là một phần của api nội bộ của plugin. Hãy ghi nhớ khi bạn nâng cấp plugin.

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 

Thông số này sẽ bị lỗi với Failure/Error: raise QueueError::LockFailed. Vì đó là dự kiến, chúng tôi có thể đặt kỳ vọng.

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 

Thông số kỹ thuật hiện phải được chuyển trừ khi bạn đã đặt ResqueSpec.inline = true. Nếu bạn đã đặt nó thành false cho spec này. Nó sẽ được dễ dàng hơn để làm theo.

Nếu quá trình thử lại đang hoạt động thì lỗi của công việc sẽ khiến công việc được gửi lại cho ResqueSpec. Chúng ta có thể thêm một kỳ vọng cho điều đó. expect(ResqueSpec.queues[queue_name]).to be_present. Không phải chúng ta có thể chạy lại công việc. Chúng tôi đã giả định giá trị trả lại thứ hai là acquire_lock_algorithm! là đúng vì vậy công việc sẽ thành công trong lần này.

Vì chúng ta muốn kiểm tra các quầy cho phép thêm độc giả cho họ

module QueueLogger 
    attr_reader :all_attempts, :num_attempts 
end 

Và sau đó kết thúc spec ...

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 

Nếu bạn muốn thử nghiệm khai thác gỗ đặc biệt bạn còn sơ khai họ và đặt kỳ vọng về những gì họ được gọi. Điều đó nên làm điều đó, tôi có một phiên bản đơn giản chạy trên máy tính của riêng tôi. Nếu không, chúng tôi có thể phải nhận được vào các chi tiết của thử nghiệm của bạn và cấu hình Resque.

1

Một vài notes-

1) Như đã đề cập bởi những người khác, bạn có thể muốn tách các cuộc gọi lại resque khỏi chức năng của họ. Tức là, kiểm tra rằng retries đang kích hoạt, nhưng cũng thử nghiệm riêng biệt rằng chúng hoạt động như mong đợi. Bạn có thể muốn tách chúng thành hai bài kiểm tra riêng biệt.

2) Đối với kiểm tra rằng họ đang bắn, tôi nghĩ rằng bạn đang tìm kiếm class doubles trong RSpec 3.

Bạn sẽ cần phải instatiate các đôi và sau đó nâng cao một ngoại lệ (docs). Điều này sẽ cho phép bạn xem số điện thoại retries của bạn có được gọi hay không và bao nhiêu lần chúng được gọi (docs).

Vì vậy, ví dụ,

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 

Có một chút công bằng xảy ra, vì vậy tôi không thể thực hiện tại địa phương, nhưng hy vọng điều này có thể giúp bạn có được đi đúng hướng.

Các vấn đề liên quan