require 'rails_helper' module PandaPal PandaPal::Organization RSpec.describe OrganizationConcerns::TaskScheduling, type: :model do let!(:organization) { create(:panda_pal_organization) } let(:schedules) { {} } before :each do Organization.instance_variable_set(:@_schedule_descriptors, nil) Organization.scheduled_task('0 0 0 * * *', :ident) { } allow(Sidekiq).to receive(:remove_schedule) allow(Sidekiq).to receive(:get_schedule) { schedules } end def descriptors Organization.instance_variable_get(:@_schedule_descriptors) end def descriptor descriptors[descriptors.keys[0]] end describe '.scheduled_task' do it 'adds to the set of descriptors' do expect(descriptors).to match( 'ident' => { :key=>"ident", :schedule=>"0 0 0 * * *", :worker=>Proc, :queue=>"default", } ) end end describe '.sync_schedules' do it 'adds new schedules' do expect(Sidekiq).to receive(:set_schedule).with(/org:\w+-ident/, anything) Organization.sync_schedules end it 'removes schedules for deleted Orgs' do schedules['org:deleted_org-schedule'] = {} expect(Sidekiq).to receive(:remove_schedule).with('org:deleted_org-schedule') Organization.sync_schedules end it 'keeps schedules created from other sources' do schedules['other-schedule'] = {} expect(Sidekiq).not_to receive(:remove_schedule).with('other-schedule') Organization.sync_schedules end end describe '#generate_schedule' do it 'generates the expected schedule' do expect(organization.generate_schedule).to eq({ "org:#{organization.name}-ident" => { "cron"=>"0 0 0 * * *", "queue"=>"default", "class"=>"PandaPal::OrganizationConcerns::TaskScheduling::ScheduledTaskExecutor", "args"=>[organization.name, "ident"], "enabled" => true, } }) end end describe '#schedule_task_cron_time' do before :each do organization.settings = { timezone: 'America/Denver' } end it 'includes timezone if in settings' do expect(organization.send(:schedule_task_cron_time, descriptor)).to eq '0 0 0 * * * America/Denver' end it 'does not re-append timezone if already present' do descriptor[:schedule] = '1 1 1 * * * America/Chicago' expect(organization.send(:schedule_task_cron_time, descriptor)).to eq '1 1 1 * * * America/Chicago' end end describe '#sync_schedule' do it 'adds new schedules' do expect(Sidekiq).to receive(:set_schedule).with(/org:\w+-ident/, anything) organization.sync_schedule end it 'removes old jobs' do schedules["org:#{organization.name}-old_schedule"] = {} expect(Sidekiq).to receive(:remove_schedule).with("org:#{organization.name}-old_schedule") organization.sync_schedule end end describe 'SettingsValidation' do before :each do organization.settings = {} end it 'passes a valid timezone' do organization.settings[:timezone] = 'America/Denver' expect(organization).to be_valid end it 'fails an invalid timezone' do organization.settings[:timezone] = 'Timezone/Blorg' expect(organization).not_to be_valid end it 'allows [:task_schedules] entry to be missing' do expect(organization).to be_valid end it 'does not require [:task_schedules] sub-entries' do organization.settings[:task_schedules] = {} expect(organization).to be_valid end it 'allows task entry to be false' do organization.settings[:task_schedules] = { ident: false } expect(organization).to be_valid end it 'allows task entry to be a valid cron string' do organization.settings[:task_schedules] = { ident: '0 0 0 * * * America/Denver' } expect(organization).to be_valid end it 'does not allow task entry to be an invalid cron string' do organization.settings[:task_schedules] = { ident: 'blort' } expect(organization).not_to be_valid end it 'does not allow sub-entries for unknown tasks' do organization.settings[:task_schedules] = { missing_ident: '0 0 0 * * * America/Denver' } expect(organization).not_to be_valid end end end end