2016-08-28 1 views
18

मैं एक ऐसा नमूना लिखने की कोशिश कर रहा हूं जो पुनर्विक्रय-पुनः प्रयास की पुनः प्रयास कार्यक्षमता का परीक्षण करता है और मुझे बाध्यकारी.pry के सही तरीके से हिट करने के लिए परीक्षण नहीं मिल रहे हैं। क्या rspec 3 का उपयोग करके इस कार्यक्षमता का परीक्षण करने का कोई तरीका है, इसलिए मैं सत्यापित कर सकता हूं कि वे इरादे से काम कर रहे हैं?रीस्क-रीट्री और रेल 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

क्या आपके पास एक उदाहरण spec है? –

+0

बचाव पुनः प्रयास का उपयोग न करें, अपवाद पकड़ें और कोड – user1735921

उत्तर

1

तो आपके द्वारा लागू किए गए इस हुक से आने वाली विशिष्ट विफलता के लिए आप पुनः प्रयासों का परीक्षण करना चाहते हैं।

def lock_failed(*) 
    raise QueueError::LockFailed 
end 

हम इस को गति प्रदान करने की जरूरत है। Here वह प्लगइन में उपयोग किया जाता है। चूंकि आप लॉक टाइमआउट का उपयोग कर रहे हैं, ऐसा लगता है कि हम .acquire_lock_algorithm! स्टब करना चाहते हैं। यह खतरनाक है क्योंकि यह विधि प्लगइन के आंतरिक एपीआई का हिस्सा है। जब आप प्लगइन को अपग्रेड करते हैं तो इसे ध्यान में रखें।

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 

यह spec अब 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 निर्धारित किया है गुजर जाना चाहिए। यदि आपने इसे इस स्पेक के लिए गलत पर सेट किया है। इसका पालन करना आसान होगा।

यदि रीस्क-रीट्री काम कर रहा है तो नौकरी की विफलता के परिणामस्वरूप 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 configs के विवरण में शामिल होना पड़ सकता है।

1

कुछ notes-

1) जैसा कि अन्य लोगों ने बताया है, आप शायद resque कॉलबैक को उनकी कार्यक्षमता से अलग करना चाहते हैं। यही है, परीक्षण करें कि retries फायरिंग हैं, लेकिन अलग-अलग परीक्षण भी करते हैं कि वे अपेक्षित कार्य करते हैं। आप उन्हें दो अलग-अलग परीक्षणों में अलग करना चाहते हैं।

2) की जाँच है कि वे सक्रिय हो रहे हैं के लिए, मुझे लगता है कि आप RSpec 3. में class doubles लिए देख रहे हैं

आप डबल 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 

वहाँ एक निष्पक्ष बिट चल रहा है, तो मैं स्थानीय रूप से लागू नहीं कर सकते, लेकिन उम्मीद है कि इस मदद कर सकते हैं सही दिशा में जा रहा हो।

संबंधित मुद्दे