require 'rails_helper' RSpec::Matchers.define_negated_matcher :not_change, :change RSpec.describe Scheduler do before do module SpecSpace class DelayedJobBackend def self.start # noop end # rubocop:disable Style/TrivialAccessors def self.reschedule=(reschedule) @reschedule = reschedule end def self.reschedule?(_delayed_job) @reschedule || false end end end end after do SpecSpace.send(:remove_const, :DelayedJobBackend) end describe '.cleanup' do it 'gets called by .threads' do expect(described_class).to receive(:cleanup).and_throw(:called) expect do described_class.threads end.to throw_symbol(:called) end context 'not called from .threads method' do it 'throws an exception' do expect do described_class.cleanup end.to raise_error(RuntimeError) end it 'throws no exception with force parameter' do expect do described_class.cleanup(force: true) end.not_to raise_error end end # helpers to avoid the throwing behaviour "describe"d above def simulate_threads_call threads end def threads described_class.cleanup end it 'keeps unlocked Delayed::Job-s' do # meta :) described_class.delay.cleanup expect do simulate_threads_call end.not_to change { Delayed::Job.count } end context 'locked Delayed::Job' do it 'gets destroyed' do # meta :) described_class.delay.cleanup # lock job (simluates interrupted scheduler task) locked_job = Delayed::Job.last locked_job.update_attribute(:locked_at, Time.zone.now) expect do simulate_threads_call end.to change { Delayed::Job.count }.by(-1) end context 'respond to reschedule?' do it 'gets rescheduled for positive responses' do SpecSpace::DelayedJobBackend.reschedule = true SpecSpace::DelayedJobBackend.delay.start # lock job (simluates interrupted scheduler task) locked_job = Delayed::Job.last locked_job.update_attribute(:locked_at, Time.zone.now) expect do simulate_threads_call end.to not_change { Delayed::Job.count }.and change { Delayed::Job.last.locked_at } end it 'gets destroyed for negative responses' do SpecSpace::DelayedJobBackend.reschedule = false SpecSpace::DelayedJobBackend.delay.start # lock job (simluates interrupted scheduler task) locked_job = Delayed::Job.last locked_job.update_attribute(:locked_at, Time.zone.now) expect do simulate_threads_call end.to change { Delayed::Job.count }.by(-1) end end end end end