require 'spec_helper' require 'timecop' describe Roqua::Scheduling::Scheduler do before do Timecop.freeze Roqua::Scheduling::CronJob.delete_all end after { Timecop.return } subject { described_class.new } def setup_daily_and_hourly_schedule Roqua::Scheduling::Schedule.setup do |cron| cron.add_task 'hourly', next_run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_HOUR do end cron.add_task 'daily', next_run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_DAY do end end end def setup_hourly_schedule Roqua::Scheduling::Schedule.setup do |cron| cron.add_task 'hourly', next_run_at: Roqua::Scheduling::Schedule::BEGINNING_OF_EVERY_HOUR do end end end it 'creates the correct table rows' do expect { setup_daily_and_hourly_schedule } .to change { Roqua::Scheduling::CronJob.all.pluck(:name, :next_run_at, :completed_at) } .from( [] ) .to( [ ['hourly', Time.now.beginning_of_hour + 1.hour, nil], ['daily', Time.now.beginning_of_day + 1.day, nil] ] ) end it 'removes unused table rows' do setup_daily_and_hourly_schedule expect { setup_hourly_schedule } .to change { Roqua::Scheduling::CronJob.all.pluck(:name).sort } .from(['daily', 'hourly']).to(['hourly']) end it 'generates a database specific advisory lock name' do # expect(ActiveRecord::Base.connection_config[:database]).to eql(':memory:') expect(subject.advisory_lock_name).to eql ':memory:_cron_lock' end describe 'with a run_at in the future' do before do Roqua::Scheduling::Schedule.setup do |cron| cron.add_task 'hourly', next_run_at: proc { 1.minute.from_now } do end end end it 'the task will not be run' do expect(subject.schedule.tasks['hourly']).to_not receive(:run) subject.ping end end describe 'callbacks' do let(:callback_spy) { spy(:callback) } before do Roqua::Scheduling::Schedule.setup do |cron| cron.add_task 'hourly', next_run_at: proc { 1.minute.ago } do callback_spy.execute end end end it 'get executed' do expect(callback_spy).to receive(:execute) subject.ping end it 'counts task calls' do expect(Appsignal).to receive(:increment_counter).with('scheduler.completed', 1) expect(Appsignal).to receive(:increment_counter).with('scheduler.run_task.completed', 1, task_name: 'hourly') subject.ping end end describe 'when running multiple times' do before do Timecop.freeze(60.seconds.ago) Roqua::Scheduling::Schedule.setup do |cron| cron.add_task 'task', next_run_at: proc { 30.seconds.from_now } do end end end let(:schedule) { Roqua::Scheduling::Schedule.current_schedule } it 'the task is only called once' do expect(schedule.tasks['task']).to receive(:run).once Timecop.return 3.times { Roqua::Scheduling::Scheduler.new.ping } end end end