require_relative 'test_helper' context 'Resque::Scheduler' do setup do Resque::Scheduler.configure do |c| c.dynamic = false c.mute = true c.env = nil c.app_name = nil end Resque.redis.flushall Resque::Scheduler.clear_schedule! Resque::Scheduler.send(:class_variable_set, :@@scheduled_jobs, {}) end test 'enqueue constantizes' do Resque::Scheduler.env = 'production' config = { 'cron' => '* * * * *', 'class' => 'SomeRealClass', 'args' => '/tmp' } Resque::Job.expects(:create).with( SomeRealClass.queue, SomeRealClass, '/tmp' ) Resque::Scheduler.enqueue_from_config(config) end test 'enqueue runs hooks' do Resque::Scheduler.env = 'production' config = { 'cron' => '* * * * *', 'class' => 'SomeRealClass', 'args' => '/tmp' } Resque::Job.expects(:create).with( SomeRealClass.queue, SomeRealClass, '/tmp' ) SomeRealClass.expects(:before_delayed_enqueue_example).with('/tmp') SomeRealClass.expects(:before_enqueue_example).with('/tmp') SomeRealClass.expects(:after_enqueue_example).with('/tmp') Resque::Scheduler.enqueue_from_config(config) end test 'enqueue_from_config respects queue params' do config = { 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'queue' => 'high' } Resque.expects(:enqueue_to).with('high', SomeIvarJob) Resque::Scheduler.enqueue_from_config(config) end test "config makes it into the rufus_scheduler" do assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size) Resque.schedule = {:some_ivar_job => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}} Resque::Scheduler.load_schedule! assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert Resque::Scheduler.scheduled_jobs.include?('some_ivar_job') end test "can reload schedule" do Resque::Scheduler.dynamic = true Resque.schedule = {"some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}} Resque::Scheduler.load_schedule! assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert Resque::Scheduler.scheduled_jobs.include?("some_ivar_job") Resque.redis.del(:schedules) Resque.redis.hset(:schedules, "some_ivar_job2", Resque.encode( 'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2" )) Resque::Scheduler.reload_schedule! assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal '/tmp/2', Resque.schedule["some_ivar_job2"]["args"] assert Resque::Scheduler.scheduled_jobs.include?("some_ivar_job2") end test 'load_schedule_job loads a schedule' do Resque::Scheduler.load_schedule_job( 'some_ivar_job', { 'cron' => '* * * * *', 'class' => 'SomeIvarJob', 'args' => '/tmp' } ) assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal(1, Resque::Scheduler.scheduled_jobs.size) assert Resque::Scheduler.scheduled_jobs.keys.include?('some_ivar_job') end test 'load_schedule_job with every with options' do Resque::Scheduler.load_schedule_job( 'some_ivar_job', { 'every' => ['30s', { 'first_in' => '60s' }], 'class' => 'SomeIvarJob', 'args' => '/tmp' } ) assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal(1, Resque::Scheduler.scheduled_jobs.size) assert Resque::Scheduler.scheduled_jobs.keys.include?('some_ivar_job') job = Resque::Scheduler.scheduled_jobs['some_ivar_job'] assert job.params.keys.include?(:first_in) end test 'load_schedule_job with cron with options' do Resque::Scheduler.load_schedule_job( 'some_ivar_job', { 'cron' => ['* * * * *', { 'allow_overlapping' => 'true' }], 'class' => 'SomeIvarJob', 'args' => '/tmp' } ) assert_equal(1, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal(1, Resque::Scheduler.scheduled_jobs.size) assert Resque::Scheduler.scheduled_jobs.keys.include?('some_ivar_job') job = Resque::Scheduler.scheduled_jobs['some_ivar_job'] assert job.params.keys.include?(:allow_overlapping) end test 'load_schedule_job without cron' do Resque::Scheduler.load_schedule_job( 'some_ivar_job', { 'class' => 'SomeIvarJob', 'args' => '/tmp' } ) assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal(0, Resque::Scheduler.scheduled_jobs.size) assert !Resque::Scheduler.scheduled_jobs.keys.include?('some_ivar_job') end test 'load_schedule_job with an empty cron' do Resque::Scheduler.load_schedule_job( 'some_ivar_job', { 'cron' => '', 'class' => 'SomeIvarJob', 'args' => '/tmp' } ) assert_equal(0, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal(0, Resque::Scheduler.scheduled_jobs.size) assert !Resque::Scheduler.scheduled_jobs.keys.include?('some_ivar_job') end test "update_schedule" do Resque::Scheduler.dynamic = true Resque.schedule = { "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}, "another_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/5"}, "stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"} } Resque::Scheduler.load_schedule! Resque.set_schedule("some_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"} ) Resque.set_schedule("new_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"} ) Resque.set_schedule("stay_put_job", {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"} ) Resque.remove_schedule("another_ivar_job") Resque::Scheduler.update_schedule assert_equal(3, Resque::Scheduler.rufus_scheduler.all_jobs.size) assert_equal(3, Resque::Scheduler.scheduled_jobs.size) %w(some_ivar_job new_ivar_job stay_put_job).each do |job_name| assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name) assert Resque.schedule.keys.include?(job_name) end assert !Resque::Scheduler.scheduled_jobs.keys.include?("another_ivar_job") assert !Resque.schedule.keys.include?("another_ivar_job") assert_equal 0, Resque.redis.scard(:schedules_changed) end test "update_schedule with mocks" do Resque::Scheduler.dynamic = true Resque.schedule = { "some_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp"}, "another_ivar_job" => {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/5"}, "stay_put_job" => {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"} } Resque::Scheduler.load_schedule! Resque::Scheduler.rufus_scheduler.expects(:unschedule).with(Resque::Scheduler.scheduled_jobs["some_ivar_job"].job_id) Resque::Scheduler.rufus_scheduler.expects(:unschedule).with(Resque::Scheduler.scheduled_jobs["another_ivar_job"].job_id) Resque.set_schedule("some_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"} ) Resque.set_schedule("new_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"} ) Resque.set_schedule("stay_put_job", {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp"} ) Resque.remove_schedule("another_ivar_job") Resque::Scheduler.update_schedule assert_equal(3, Resque::Scheduler.scheduled_jobs.size) %w(some_ivar_job new_ivar_job stay_put_job).each do |job_name| assert Resque::Scheduler.scheduled_jobs.keys.include?(job_name) assert Resque.schedule.keys.include?(job_name) end assert !Resque::Scheduler.scheduled_jobs.keys.include?("another_ivar_job") assert !Resque.schedule.keys.include?("another_ivar_job") assert_equal 0, Resque.redis.scard(:schedules_changed) end test "schedule= sets the schedule" do Resque::Scheduler.dynamic = true Resque.schedule = {"my_ivar_job" => { 'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/75" }} assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/75"}, Resque.decode(Resque.redis.hget(:schedules, "my_ivar_job"))) end test "schedule= removes schedules not present in the given schedule argument" do Resque::Scheduler.dynamic = true Resque.schedule = {"old_job" => {'cron' => "* * * * *", 'class' => 'OldJob'}} assert_equal({"old_job" => {'cron' => "* * * * *", 'class' => 'OldJob'}}, Resque.schedule) Resque.schedule = {"new_job" => {'cron' => "* * * * *", 'class' => 'NewJob'}} Resque.reload_schedule! assert_equal({"new_job" => {'cron' => "* * * * *", 'class' => 'NewJob'}}, Resque.schedule) end test "schedule= uses job name as 'class' argument if it's missing" do Resque::Scheduler.dynamic = true Resque.schedule = {"SomeIvarJob" => { 'cron' => "* * * * *", 'args' => "/tmp/75" }} assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/75"}, Resque.decode(Resque.redis.hget(:schedules, "SomeIvarJob"))) assert_equal('SomeIvarJob', Resque.schedule['SomeIvarJob']['class']) end test "schedule= does not mutate argument" do schedule = {"SomeIvarJob" => { 'cron' => "* * * * *", 'args' => "/tmp/75" }} Resque.schedule = schedule assert !schedule['SomeIvarJob'].key?('class') end test "set_schedule can set an individual schedule" do Resque.set_schedule("some_ivar_job", { 'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/22" }) assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/22"}, Resque.decode(Resque.redis.hget(:schedules, "some_ivar_job"))) assert Resque.redis.sismember(:schedules_changed, "some_ivar_job") end test "get_schedule returns a schedule" do Resque.redis.hset(:schedules, "some_ivar_job2", Resque.encode( 'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/33" )) assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/33"}, Resque.get_schedule("some_ivar_job2")) end test "remove_schedule removes a schedule" do Resque.set_schedule("some_ivar_job3", {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/44", 'persist' => true} ) Resque::Scheduler.load_schedule! Resque.remove_schedule("some_ivar_job3") assert_equal nil, Resque.redis.hget(:schedules, "some_ivar_job3") assert Resque.redis.sismember(:schedules_changed, "some_ivar_job3") assert_equal [], Resque.redis.smembers(:persisted_schedules) end test "persisted schedules" do Resque.set_schedule("some_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2", 'persist' => true} ) Resque.set_schedule("new_ivar_job", {'cron' => "* * * * *", 'class' => 'SomeJob', 'args' => "/tmp/3"} ) Resque.schedule=({ 'a_schedule' => {'cron' => "* * * * *", 'class' => 'SomeOtherJob', 'args' => '/tmp'} }) Resque::Scheduler.load_schedule! assert_equal({'cron' => "* * * * *", 'class' => 'SomeIvarJob', 'args' => "/tmp/2"}, Resque.schedule['some_ivar_job']) assert_equal(nil, Resque.schedule['some_job']) end test "adheres to lint" do assert_nothing_raised do Resque::Plugin.lint(Resque::Scheduler) Resque::Plugin.lint(ResqueScheduler) end end test 'procline contains app_name when present' do Resque::Scheduler.app_name = 'foo' assert Resque::Scheduler.send(:build_procline, 'bar') =~ /\[foo\]:/ end test 'procline omits app_name when absent' do Resque::Scheduler.app_name = nil assert Resque::Scheduler.send(:build_procline, 'bar') =~ /#{Resque::Scheduler.send(:internal_name)}: bar/ end test 'procline contains env when present' do Resque::Scheduler.env = 'derp' assert Resque::Scheduler.send(:build_procline, 'cage') =~ /\[derp\]: cage/ end test 'procline omits env when absent' do Resque::Scheduler.env = nil assert Resque::Scheduler.send(:build_procline, 'cage') =~ /#{Resque::Scheduler.send(:internal_name)}: cage/ end end