diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8fe73e..cab34a6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,10 +4,7 @@ concurrency: group: ${{ github.ref }} cancel-in-progress: true -on: - push: - branches: [ master ] - pull_request: +on: [push,pull_request,workflow_dispatch] jobs: test: @@ -29,6 +26,8 @@ jobs: - 2.7 - 3.0 - 3.1 + - 3.2 + - 3.3 steps: - uses: actions/checkout@v3 diff --git a/spec/hutch/error_handlers/bugsnag_spec.rb b/spec/hutch/error_handlers/bugsnag_spec.rb index 3b64a5e..8b4616a 100644 --- a/spec/hutch/error_handlers/bugsnag_spec.rb +++ b/spec/hutch/error_handlers/bugsnag_spec.rb @@ -8,6 +8,7 @@ before do Bugsnag.configure do |bugsnag| bugsnag.api_key = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + bugsnag.logger = Logger.new(File::NULL) # suppress logging end end diff --git a/spec/hutch/tracers/datadog_spec.rb b/spec/hutch/tracers/datadog_spec.rb index 237ad2b..d27d893 100644 --- a/spec/hutch/tracers/datadog_spec.rb +++ b/spec/hutch/tracers/datadog_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' RSpec.describe Hutch::Tracers::Datadog do + ::Datadog.logger.level = Logger::FATAL # suppress logging + describe "#handle" do subject(:handle) { tracer.handle(message) } diff --git a/spec/hutch/worker_spec.rb b/spec/hutch/worker_spec.rb index 3ca0eda..fa73b31 100644 --- a/spec/hutch/worker_spec.rb +++ b/spec/hutch/worker_spec.rb @@ -69,29 +69,32 @@ end describe '#handle_message' do + subject { worker.handle_message(consumer, delivery_info, properties, payload) } let(:payload) { '{}' } let(:consumer_instance) { double('Consumer instance') } let(:delivery_info) { double('Delivery Info', routing_key: '', delivery_tag: 'dt') } let(:properties) { double('Properties', message_id: nil, content_type: "application/json") } + let(:log) { StringIO.new } before { allow(consumer).to receive_messages(new: consumer_instance) } before { allow(broker).to receive(:ack) } before { allow(broker).to receive(:nack) } before { allow(consumer_instance).to receive(:broker=) } before { allow(consumer_instance).to receive(:delivery_info=) } + before { allow(Hutch::Logging).to receive(:logger).and_return(Logger.new(log)) } it 'passes the message to the consumer' do expect(consumer_instance).to receive(:process). with(an_instance_of(Hutch::Message)) expect(consumer_instance).to receive(:message_rejected?).and_return(false) - worker.handle_message(consumer, delivery_info, properties, payload) + subject end it 'acknowledges the message' do allow(consumer_instance).to receive(:process) expect(broker).to receive(:ack).with(delivery_info.delivery_tag) expect(consumer_instance).to receive(:message_rejected?).and_return(false) - worker.handle_message(consumer, delivery_info, properties, payload) + subject end context 'when the consumer fails and a requeue is configured' do @@ -108,40 +111,79 @@ expect(broker).to_not receive(:nack) expect(broker).to receive(:requeue) - worker.handle_message(consumer, delivery_info, properties, payload) + subject end end context 'when the consumer raises an exception' do + let(:expected_log) { /ERROR .+ error in consumer .+ RuntimeError .+ backtrace:/m } before { allow(consumer_instance).to receive(:process).and_raise('a consumer error') } it 'logs the error' do - Hutch::Config[:error_handlers].each do |backend| - expect(backend).to receive(:handle) - end - worker.handle_message(consumer, delivery_info, properties, payload) + expect { subject }.to change { log.tap(&:rewind).read }.from("").to(expected_log) end it 'rejects the message' do expect(broker).to receive(:nack).with(delivery_info.delivery_tag) - worker.handle_message(consumer, delivery_info, properties, payload) + subject + end + + context 'when a custom error handler supports delivery info' do + let(:error_handler) do + Class.new(Hutch::ErrorHandlers::Base) do + def handle(_properties, _payload, _consumer, _ex, delivery_info) + raise unless delivery_info.delivery_tag == 'dt' + puts 'handled!' + end + end + end + + around do |example| + original = Hutch::Config[:error_handlers] + Hutch::Config[:error_handlers] = [error_handler.new] + example.run + Hutch::Config[:error_handlers] = original + end + + it 'calls the custom handler with delivery info' do + expect { subject }.to output("handled!\n").to_stdout + end + end + + context 'when a custom error handler does not support delivery info' do + let(:error_handler) do + Class.new(Hutch::ErrorHandlers::Base) do + def handle(_properties, _payload, _consumer, _ex) + puts 'handled!' + end + end + end + + around do |example| + original = Hutch::Config[:error_handlers] + Hutch::Config[:error_handlers] = [error_handler.new] + example.run + Hutch::Config[:error_handlers] = original + end + + it 'calls the custom handler with delivery info' do + expect { subject }.to output("handled!\n").to_stdout + end end end context "when the payload is not valid json" do let(:payload) { "Not Valid JSON" } + let(:expected_log) { /ERROR .+ error in consumer .+ MultiJson::ParseError .+ backtrace:/m } it 'logs the error' do - Hutch::Config[:error_handlers].each do |backend| - expect(backend).to receive(:handle) - end - worker.handle_message(consumer, delivery_info, properties, payload) + expect { subject }.to change { log.tap(&:rewind).read }.from("").to(expected_log) end it 'rejects the message' do expect(broker).to receive(:nack).with(delivery_info.delivery_tag) - worker.handle_message(consumer, delivery_info, properties, payload) + subject end end end