diff --git a/.rubocop.yml b/.rubocop.yml index 63da7a0..f014f9a 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,7 +10,8 @@ AllCops: # Layout/DotPosition: - EnforcedStyle: trailing + Enabled: false + StyleGuide: https://relaxed.ruby.style/#layoutdotposition Layout/FirstHashElementIndentation: EnforcedStyle: consistent diff --git a/lib/checker_jobs/checks/base.rb b/lib/checker_jobs/checks/base.rb index 91609d0..4d9ab11 100644 --- a/lib/checker_jobs/checks/base.rb +++ b/lib/checker_jobs/checks/base.rb @@ -1,10 +1,10 @@ CheckerJobs::Checks::Base = Struct.new(:klass, :name, :options, :block) do - def perform + def perform(iteration = 0) result = CheckerJobs.configuration.around_check.call do klass.new.instance_exec(&block) end - result.tap { |res| handle_result(res) } + result.tap { |res| handle_result(res, iteration) } end private @@ -14,7 +14,19 @@ def notify(count:, entries: nil) notifier_class.new(self, count, entries).notify end - def handle_result(_result) + def handle_result(_result, _retry_count) raise NotImplementedError end + + def handle_retry(count, iteration, entries = nil) + retry?(iteration) ? perform(iteration + 1) : notify(count: count, entries: entries) + end + + def retry?(iteration) + iteration < max_retry + end + + def max_retry + @_max_retry ||= options.fetch(:retry, 0) + end end diff --git a/lib/checker_jobs/checks/ensure_fewer.rb b/lib/checker_jobs/checks/ensure_fewer.rb index 4b9250c..e0b4659 100644 --- a/lib/checker_jobs/checks/ensure_fewer.rb +++ b/lib/checker_jobs/checks/ensure_fewer.rb @@ -1,10 +1,10 @@ class CheckerJobs::Checks::EnsureFewer < CheckerJobs::Checks::Base private - def handle_result(result) + def handle_result(result, iteration) case result when Numeric - notify(count: result) if result > options.fetch(:than) + handle_retry(result, iteration) if result > options.fetch(:than) else raise ArgumentError, "Unsupported result: '#{result.class.name}' for 'ensure_less'" end diff --git a/lib/checker_jobs/checks/ensure_more.rb b/lib/checker_jobs/checks/ensure_more.rb index a27c225..853bf59 100644 --- a/lib/checker_jobs/checks/ensure_more.rb +++ b/lib/checker_jobs/checks/ensure_more.rb @@ -1,10 +1,10 @@ class CheckerJobs::Checks::EnsureMore < CheckerJobs::Checks::Base private - def handle_result(result) + def handle_result(result, iteration) case result when Numeric - notify(count: result) if result < options.fetch(:than) + handle_retry(result, iteration) if result < options.fetch(:than) else raise ArgumentError, "Unsupported result: '#{result.class.name}' for 'ensure_more'" end diff --git a/lib/checker_jobs/checks/ensure_no.rb b/lib/checker_jobs/checks/ensure_no.rb index 9cce70c..ebf2ae7 100644 --- a/lib/checker_jobs/checks/ensure_no.rb +++ b/lib/checker_jobs/checks/ensure_no.rb @@ -1,14 +1,14 @@ class CheckerJobs::Checks::EnsureNo < CheckerJobs::Checks::Base private - def handle_result(result) + def handle_result(result, iteration) case result when Numeric - notify(count: result) unless result.zero? + handle_retry(result, iteration) unless result.zero? when Enumerable - notify(count: result.size, entries: result) unless result.empty? + handle_retry(result.size, iteration, result) unless result.empty? when TrueClass, FalseClass - notify(count: 1) if result + handle_retry(1, iteration) if result else raise ArgumentError, "Unsupported result: '#{result.class.name}' for 'ensure_no'" end diff --git a/lib/checker_jobs/notifiers/email.rb b/lib/checker_jobs/notifiers/email.rb index c58a2d1..eeb1320 100644 --- a/lib/checker_jobs/notifiers/email.rb +++ b/lib/checker_jobs/notifiers/email.rb @@ -28,9 +28,9 @@ def valid? end def mailer_options - @_mailer_options ||= @defaults. - merge(email_options). - merge(@check.klass.notifier_options) + @_mailer_options ||= @defaults + .merge(email_options) + .merge(@check.klass.notifier_options) end def email_options diff --git a/spec/checker_jobs/checks/base_spec.rb b/spec/checker_jobs/checks/base_spec.rb index cb7e8b1..f4ac267 100644 --- a/spec/checker_jobs/checks/base_spec.rb +++ b/spec/checker_jobs/checks/base_spec.rb @@ -39,7 +39,7 @@ it "keeps handling the result outside the around_check delegation" do allow(instance).to receive(:handle_result).and_call_original perform - expect(instance).to have_received(:handle_result).with(0) + expect(instance).to have_received(:handle_result).with(0, 0) end end end diff --git a/spec/checker_jobs/checks/ensure_fewer_spec.rb b/spec/checker_jobs/checks/ensure_fewer_spec.rb index 70045b2..1d98e03 100644 --- a/spec/checker_jobs/checks/ensure_fewer_spec.rb +++ b/spec/checker_jobs/checks/ensure_fewer_spec.rb @@ -1,7 +1,7 @@ RSpec.describe CheckerJobs::Checks::EnsureFewer, :bugsnag, :configuration do include BugsnagHelpers - let(:instance) { described_class.new(checker_klass, "ensure_name", { than: 3 }, block) } + let(:instance) { described_class.new(checker_klass, "ensure_name", options, block) } let(:checker_klass) do Class.new do include CheckerJobs::Base @@ -9,6 +9,8 @@ end end + let(:options) { { than: 3 } } + describe "#perform" do subject(:perform) { instance.perform } @@ -29,5 +31,27 @@ include_examples "sends_a_bugsnag_notification" end + + context "when retry option is used" do + let(:options) { { than: 3, retry: 1 } } + + context "when block's result is lower than the threshold" do + let(:block) { Proc.new { 2 } } + + include_examples "does_not_send_a_bugsnag_notification" + end + + context "when block's result is greater than the threshold" do + let(:block) { Proc.new { 4 } } + + it "sends 2 sidekiq jobs" do + allow(instance).to receive(:perform).and_call_original + perform + expect(instance).to have_received(:perform).twice + end + + include_examples "sends_a_bugsnag_notification" + end + end end end diff --git a/spec/checker_jobs/checks/ensure_more_spec.rb b/spec/checker_jobs/checks/ensure_more_spec.rb index 84a7574..271ba76 100644 --- a/spec/checker_jobs/checks/ensure_more_spec.rb +++ b/spec/checker_jobs/checks/ensure_more_spec.rb @@ -1,7 +1,7 @@ RSpec.describe CheckerJobs::Checks::EnsureMore, :bugsnag, :configuration do include BugsnagHelpers - let(:instance) { described_class.new(checker_klass, "ensure_name", { than: 3 }, block) } + let(:instance) { described_class.new(checker_klass, "ensure_name", options, block) } let(:checker_klass) do Class.new do include CheckerJobs::Base @@ -9,6 +9,8 @@ end end + let(:options) { { than: 3 } } + describe "#perform" do subject(:perform) { instance.perform } @@ -29,5 +31,27 @@ include_examples "does_not_send_a_bugsnag_notification" end + + context "when retry option is used" do + let(:options) { { than: 3, retry: 1 } } + + context "when block's result is greater than the threshold" do + let(:block) { Proc.new { 4 } } + + include_examples "does_not_send_a_bugsnag_notification" + end + + context "when block's result is lower than the threshold" do + let(:block) { Proc.new { 2 } } + + it "sends 2 sidekiq jobs" do + allow(instance).to receive(:perform).and_call_original + perform + expect(instance).to have_received(:perform).twice + end + + include_examples "sends_a_bugsnag_notification" + end + end end end diff --git a/spec/checker_jobs/checks/ensure_no_spec.rb b/spec/checker_jobs/checks/ensure_no_spec.rb index cf8b8b2..1e83fd9 100644 --- a/spec/checker_jobs/checks/ensure_no_spec.rb +++ b/spec/checker_jobs/checks/ensure_no_spec.rb @@ -1,13 +1,16 @@ +require "support/checkers" + RSpec.describe CheckerJobs::Checks::EnsureNo, :bugsnag, :configuration do include BugsnagHelpers - let(:instance) { described_class.new(checker_klass, "ensure_name", {}, block) } + let(:instance) { described_class.new(checker_klass, "ensure_name", options, block) } let(:checker_klass) do Class.new do include CheckerJobs::Base notify :bugsnag end end + let(:options) { {} } describe "#perform" do subject(:perform) { instance.perform } @@ -47,5 +50,28 @@ include_examples "does_not_send_a_bugsnag_notification" end + + context "when retry option is used" do + let(:options) { { retry: 1 } } + + context "when block's result is 0" do + let(:block) { Proc.new { 0 } } + + include_examples "does_not_send_a_bugsnag_notification" + end + + context "when block's result is > 0" do + include_context "when SidekiqChecker is available" + let(:block) { Proc.new { 2 } } + + it "sends 2 sidekiq jobs" do + allow(instance).to receive(:perform).and_call_original + perform + expect(instance).to have_received(:perform).twice + end + + include_examples "sends_a_bugsnag_notification" + end + end end end diff --git a/spec/checker_jobs/notifiers/bugsnag_spec.rb b/spec/checker_jobs/notifiers/bugsnag_spec.rb index db4ad30..38791a8 100644 --- a/spec/checker_jobs/notifiers/bugsnag_spec.rb +++ b/spec/checker_jobs/notifiers/bugsnag_spec.rb @@ -23,7 +23,7 @@ expect(::Bugsnag).to have_received(:deliver_notification).once end - describe "notify's resulting payload" do + describe "notifies resulting payload" do subject(:notify_report) do report = nil diff --git a/spec/support/bugsnag_helpers.rb b/spec/support/bugsnag_helpers.rb new file mode 100644 index 0000000..b709224 --- /dev/null +++ b/spec/support/bugsnag_helpers.rb @@ -0,0 +1,17 @@ +module BugsnagHelpers + shared_examples "sends_a_bugsnag_notification" do + it do + allow(::Bugsnag).to receive(:deliver_notification) + subject + expect(::Bugsnag).to have_received(:deliver_notification).once + end + end + + shared_examples "does_not_send_a_bugsnag_notification" do + it do + allow(::Bugsnag).to receive(:deliver_notification) + subject + expect(::Bugsnag).not_to have_received(:deliver_notification) + end + end +end