spec/base_spec.rb in wayfarer-0.4.6 vs spec/base_spec.rb in wayfarer-0.4.7

- old
+ new

@@ -1,224 +1,204 @@ # frozen_string_literal: true require "spec_helpers" describe Wayfarer::Base, redis: true do - include Wayfarer::Redis::Connection + let(:task) { build(:task, :redis_pool) } - let(:url) { "https://example.com" } - let(:batch) { "batch" } - let(:task) { build(:task, batch: batch, url: url) } - let(:klass) { Class.new(Wayfarer::Base) } + before do + stub_const("DummyJob", Class.new(ActiveJob::Base).include(Wayfarer::Base)) + end - before { stub_const("DummyJob", klass) } - describe "::crawl" do it "enqueues a task" do expect(DummyJob).to receive(:perform_later).with(task) - DummyJob.crawl(url, batch: batch) + DummyJob.crawl(task.url, batch: task.batch) end it "returns a task" do - expect(DummyJob.crawl(url)).to be_a(Wayfarer::Task) + expect(DummyJob.crawl(task.url)).to be_a(Wayfarer::Task) end end - describe "Callbacks" do - let(:counter) { task.counter } + describe "#perform" do + subject(:counter) { Wayfarer::Redis::Counter.new(task) } + let!(:initial) { counter.increment } - describe "after enqueue" do - it "increments the counter" do - expect { - DummyJob.crawl(url, batch: batch) - }.to change { counter.value }.by(1) + before do + DummyJob.class_eval do + route.to :index end end - describe "after perform" do - it "decrements the counter" do - DummyJob.crawl(url, batch: batch) - task.counter.increment - expect { perform_enqueued_jobs }.to change { task.counter.value }.by(-1) + describe "succeeding job" do + before do + DummyJob.class_eval do + def index; end + end end - context "when counter reaches 0" do - it "resets the barrier" do - DummyJob.crawl(url, batch: batch) - perform_enqueued_jobs - redis do |conn| - expect(conn.exists?(task.barrier.redis_key)).to be(false) - end - end + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original - it "resets the counter" do - DummyJob.crawl(url, batch: batch) + expect { + DummyJob.perform_later(task) perform_enqueued_jobs - redis do |conn| - expect(conn.exists?(task.counter.redis_key)).to be(false) - end - end - - it "runs after batch callbacks" do - expect { |spy| - klass.after_batch(&spy) - DummyJob.crawl(url, batch: batch) - perform_enqueued_jobs - }.to yield_control - end + assert_performed_jobs 1 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) end end - end - describe "Unhandled exceptions" do - let(:klass) { Class.new(Wayfarer::Base) } - - before do - allow_any_instance_of(DummyJob).to receive(:perform).and_raise(RuntimeError.new) - end - - it "does not retry the job" do - DummyJob.crawl(url, batch: batch) - - expect { - begin - perform_enqueued_jobs - rescue StandardError - nil + describe "failing job" do + before do + DummyJob.class_eval do + def index + raise + end end - }.to change { enqueued_jobs.size }.by(-1) - end + end - it "decrements the counter" do - 3.times { task.counter.increment } + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original - DummyJob.crawl(url, batch: batch) - begin - perform_enqueued_jobs - rescue StandardError - nil + expect { + DummyJob.perform_later(task) + expect { perform_enqueued_jobs }.to raise_error(RuntimeError) + assert_performed_jobs 1 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) end - - expect(task.counter.value).to be(3) end - end - describe "Retries" do - let(:klass) do - Class.new(Wayfarer::Base) do - retry_on RuntimeError, attempts: 3 do |job, error| - Spy.call(job, error) + describe "failing job with retries" do + before do + DummyJob.class_eval do + retry_on StandardError, attempts: 3 + + def index + raise + end end end - end - before do - allow_any_instance_of(DummyJob).to receive(:perform) do |job| - task = job.arguments.first - task.metadata.job = job + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original - raise RuntimeError + expect { + DummyJob.perform_later(task) + 2.times { perform_enqueued_jobs } + expect { perform_enqueued_jobs }.to raise_error(RuntimeError) + assert_performed_jobs 3 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) end - - stub_const("Spy", spy) end - it "retries the job" do - expect(Spy).to receive(:call).exactly(:once) - .with(kind_of(DummyJob), - kind_of(RuntimeError)) + describe "discarded after retries" do + before do + DummyJob.class_eval do + ErrorA = Class.new(StandardError) + ErrorB = Class.new(StandardError) - DummyJob.crawl(url, batch: batch) + retry_on ErrorA, attempts: 5 - expect { - perform_enqueued_jobs - }.to change { enqueued_jobs.last["executions"] }.by(1) + discard_on ErrorB - expect { - perform_enqueued_jobs - }.to change { enqueued_jobs.last["executions"] }.by(1) + def index + raise ErrorB if executions == 5 - expect { - perform_enqueued_jobs - }.to change { enqueued_jobs.size }.by(-1) - end + raise ErrorA + end + end + end - it "marks the URL seen" do - task.counter.increment # otherwise barrier gets reset - DummyJob.crawl(url, batch: batch) - 3.times { perform_enqueued_jobs } - expect(task.barrier.seen?(task.url)).to be(true) - end + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original - it "decrements the counter" do - 3.times { task.counter.increment } - - DummyJob.crawl(url, batch: batch) - 3.times { perform_enqueued_jobs } - - expect(task.counter.value).to be(3) + expect { + DummyJob.perform_later(task) + 4.times { perform_enqueued_jobs } + perform_enqueued_jobs + assert_performed_jobs 5 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) + end end - it "runs after batch callbacks" do - expect { |spy| - klass.after_batch(&spy) - DummyJob.crawl(url, batch: batch) - 3.times { perform_enqueued_jobs } - }.to yield_control - end - end + describe "discarded job" do + before do + DummyJob.class_eval do + discard_on RuntimeError - describe "Discarding" do - let(:klass) do - Class.new(Wayfarer::Base) do - discard_on RuntimeError do |job, error| - Spy.call(job, error) + def index + raise "boom" + end end end - end - before do - allow_any_instance_of(DummyJob).to receive(:perform) do |job| - task = job.arguments.first - task.metadata.job = job + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original - raise RuntimeError + expect { + DummyJob.perform_later(task) + perform_enqueued_jobs + assert_performed_jobs 1 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) end - - stub_const("Spy", spy) end - it "discards the job" do - expect(Spy).to receive(:call).exactly(:once) - .with(kind_of(DummyJob), - kind_of(RuntimeError)) + describe "after_batch callback" do + let(:initial) { counter.value } - DummyJob.crawl(url, batch: batch) + describe "when after_perform callback fails" do + before do + DummyJob.class_eval do + after_perform { raise } - expect { - perform_enqueued_jobs - }.to change { enqueued_jobs.size }.by(-1) - end + def index; end + end + end - it "marks the URL seen" do - task.counter.increment # otherwise barrier gets reset - DummyJob.crawl(url, batch: batch) - perform_enqueued_jobs - expect(task.barrier.seen?(task.url)).to be(true) - end + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original - it "decrements the counter" do - 3.times { task.counter.increment } - DummyJob.crawl(url, batch: batch) - perform_enqueued_jobs - expect(task.counter.value).to be(3) - end + expect { + DummyJob.perform_later(task) + expect { perform_enqueued_jobs }.to raise_error(RuntimeError) + assert_performed_jobs 1 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) + end + end - it "runs after batch callbacks" do - expect { |spy| - klass.after_batch(&spy) - DummyJob.crawl(url, batch: batch) - perform_enqueued_jobs - }.to yield_control + describe "when after_batch callback fails" do + before do + DummyJob.class_eval do + after_batch { raise } + + def index; end + end + end + + specify do + expect_any_instance_of(Wayfarer::Redis::Counter) + .to receive(:increment).at_least(:once).and_call_original + + expect { + DummyJob.perform_later(task) + expect { perform_enqueued_jobs }.to raise_error(RuntimeError) + assert_performed_jobs 1 + expect(enqueued_jobs).to be_empty + }.not_to change { counter.value }.from(initial) + end + end end end end