From 5da15c51ba0e6daaba7c97ee94c4a9245632341d Mon Sep 17 00:00:00 2001 From: Zhdanov Date: Wed, 16 Oct 2019 19:17:15 +0300 Subject: [PATCH 1/2] implement Resque.set_schedule, Resque.remove_schedule --- lib/resque_spec.rb | 12 +++++++ lib/resque_spec/matchers.rb | 54 ++++++++++++++++++++++++++++++ lib/resque_spec/scheduler.rb | 23 +++++++++++++ spec/resque_spec/matchers_spec.rb | 52 ++++++++++++++++++++++++++++ spec/resque_spec/scheduler_spec.rb | 35 +++++++++++++++++++ spec/resque_spec_spec.rb | 39 +++++++++++++++++++++ 6 files changed, 215 insertions(+) diff --git a/lib/resque_spec.rb b/lib/resque_spec.rb index 7af346b..fd51981 100644 --- a/lib/resque_spec.rb +++ b/lib/resque_spec.rb @@ -22,6 +22,14 @@ def perform_next(queue_name) perform(queue_name, queue_by_name(queue_name).shift) end + def set_schedule_with_queue(name, config) + store(name, config) + end + + def remove_schedule_from_queue(name) + reset_by_name!(name) + end + def perform_all(queue_name) queue = queue_by_name(queue_name) until queue.empty? @@ -65,6 +73,10 @@ def reset! self.inline = false end + def reset_by_name!(name) + queues[name.to_s] = [] + end + private def name_from_instance_var(klass) diff --git a/lib/resque_spec/matchers.rb b/lib/resque_spec/matchers.rb index b675dc7..49b3750 100644 --- a/lib/resque_spec/matchers.rb +++ b/lib/resque_spec/matchers.rb @@ -139,6 +139,60 @@ def schedule_queue_for(actual) end end + def scheduled_jobs_for(name) + ResqueSpec.queue_by_name(name) + end +end + +RSpec::Matchers.define :have_set_schedule do |*expected_args| + include ScheduleQueueHelper + + chain :with_cron do |cron_rule| + @cron = cron_rule + @cron_rule_info = "with cron #@cron" + end + + match do |actual| + scheduled_jobs_for(actual).any? do |entry| + args_match = match_args(expected_args, entry[:args]) + + cron_matches = if @cron + entry[:cron] == @cron + else + true + end + + args_match && cron_matches + end + end + + match_when_negated do |actual| + return true if scheduled_jobs_for(actual).empty? + + scheduled_jobs_for(actual).any? do |entry| + args_match = match_args(expected_args, entry[:args]) + + cron_matches = if @cron + entry[:cron] == @cron + else + true + end + + !(args_match && cron_matches) + end + end + + failure_message do |actual| + ["expected that schedule queue #{actual} would have [#{expected_args.join(', ')}] scheduled", @cron_rule_info].join(' ') + end + + failure_message_when_negated do |actual| + ["expected that schedule queue #{actual} would not have [#{expected_args.join(', ')}] scheduled", @cron_rule_info].join(' ') + end + + description do + "have set schedule" + end end RSpec::Matchers.define :have_scheduled do |*expected_args| diff --git a/lib/resque_spec/scheduler.rb b/lib/resque_spec/scheduler.rb index a35489a..d3309e1 100644 --- a/lib/resque_spec/scheduler.rb +++ b/lib/resque_spec/scheduler.rb @@ -11,13 +11,28 @@ def self.extended(klass) alias :enqueue_at_with_queue_without_resque_spec :enqueue_at_with_queue alias :enqueue_in_with_queue_without_resque_spec :enqueue_in_with_queue alias :remove_delayed_without_resque_spec :remove_delayed + alias :remove_scheduled_without_resque_spec :remove_schedule + alias :set_schedule_without_resque_spec :set_schedule end end + klass.extend(ResqueSpec::SchedulerExtMethods) end end module SchedulerExtMethods + def set_schedule(name, config, reload = false) + return set_schedule(name, config, reload) if ResqueSpec.disable_ext && respond_to(:set_schedule) + + ResqueSpec.set_schedule(name, config) + end + + def remove_schedule(name) + return remove_schedule(name) if ResqueSpec.disable_ext && respond_to(:remove_schedule) + + ResqueSpec.remove_schedule(name) + end + def enqueue_at(time, klass, *args) return enqueue_at_without_resque_spec(time, klass, *args) if ResqueSpec.disable_ext && respond_to?(:enqueue_at_without_resque_spec) @@ -49,6 +64,14 @@ def remove_delayed(klass, *args) end end + def set_schedule(name, config) + set_schedule_with_queue(name, config) + end + + def remove_schedule(name) + remove_schedule_from_queue(name) + end + def enqueue_at(time, klass, *args) enqueue_at_with_queue(schedule_queue_name(klass), time, klass, *args) end diff --git a/spec/resque_spec/matchers_spec.rb b/spec/resque_spec/matchers_spec.rb index 93dcbe9..6fc5b35 100644 --- a/spec/resque_spec/matchers_spec.rb +++ b/spec/resque_spec/matchers_spec.rb @@ -528,4 +528,56 @@ end end + + + describe "#have_set_schedule" do + let(:schedule_name) { "scheduler_start_method" } + let(:config) { {class: NoQueueClass, args: ["scheduler_arg"] } } + + before do + Resque.set_schedule(schedule_name, config) + end + + after :each do + Resque.remove_schedule(schedule_name) + end + + it "raises approrpiate exception" do + lambda { + schedule_name.should have_set_schedule(schedule_name + "1", config) + }.should raise_error(RSpec::Expectations::ExpectationNotMetError) + end + + it "return true if actual and schedule args are equal" do + schedule_name.should have_set_schedule("scheduler_arg") + end + + it "not exist schedule_name" do + "#{schedule_name}+1".should_not have_set_schedule("scheduler_arg") + end + + it "not existing args" do + schedule_name.should_not have_set_schedule("scheduler_other_arg") + end + + context "#cron" do + context "with rule" do + let(:config) { super().merge(cron: "0 * * * *") } + + it "fetches cron config from entry" do + schedule_name.should have_set_schedule("scheduler_arg").with_cron("0 * * * *") + end + + it "finds only with correct cron" do + schedule_name.should_not have_set_schedule("scheduler_arg").with_cron("1 * * * *") + end + end + + context "without rule" do + it "fetches empty cron config from entry" do + schedule_name.should have_set_schedule("scheduler_arg").with_cron(nil) + end + end + end + end end diff --git a/spec/resque_spec/scheduler_spec.rb b/spec/resque_spec/scheduler_spec.rb index 0b1749b..93840da 100644 --- a/spec/resque_spec/scheduler_spec.rb +++ b/spec/resque_spec/scheduler_spec.rb @@ -132,6 +132,41 @@ end end + describe "#set_schedule_with_queue" do + let(:name) { "scheduler_start_method" } + let(:config) { {class: "NoQueueClass", args: [1]} } + + before do + Resque.set_schedule(name, config) + end + + it "adds to the scheduled queue hash" do + ResqueSpec.queue_by_name(name).should_not be_empty + end + + it "sets the klass on the queue" do + ResqueSpec.queue_by_name(name).first.should include(:class => "NoQueueClass", :args => [1]) + end + end + + describe "#remove_schedule_from_queue" do + let(:name) { "scheduler_start_method" } + let(:config) { {class: "NoQueueClass", args: [1]} } + + before do + Resque.set_schedule(name, config) + Resque.remove_schedule(name) + end + + it "removes the scheduled queue hash" do + ResqueSpec.queue_by_name(name).should be_empty + end + + it "removes content from the queue" do + ResqueSpec.queue_by_name(name).should_not include(:class => "NoQueueClass") + end + end + describe "#enqueue_in_with_queue" do before do Timecop.freeze(Time.now) diff --git a/spec/resque_spec_spec.rb b/spec/resque_spec_spec.rb index 3ce7062..fd35a1f 100644 --- a/spec/resque_spec_spec.rb +++ b/spec/resque_spec_spec.rb @@ -141,6 +141,37 @@ end end + describe '#set_schedule_with_queue' do + let(:config) { {class: NameFromClassMethod.to_s, args: [1]} } + let(:name) { "scheduler_start_method" } + + it 'stores job in queue' do + ResqueSpec.set_schedule_with_queue(name, config) + + ResqueSpec.queue_by_name(name).should include(config) + end + end + + + describe '#remove_schedule_from_queue' do + let(:config) { {class: NameFromClassMethod.to_s, args: [1]} } + let(:name) { "scheduler_start_method" } + + it 'name found' do + ResqueSpec.set_schedule_with_queue(name, config) + ResqueSpec.remove_schedule_from_queue(name) + + ResqueSpec.queue_by_name(name).should_not include(config) + end + + it 'name not found' do + ResqueSpec.set_schedule_with_queue(name, config) + ResqueSpec.remove_schedule_from_queue(name) + + ResqueSpec.queue_by_name(name).should_not include(config) + end + end + describe "#perform_all" do before do ResqueSpec.enqueue(:queue_name, NameFromClassMethod, 1) @@ -281,4 +312,12 @@ ResqueSpec.inline.should == false end end + + describe "#reset_by_name!" do + it "clears the queue" do + ResqueSpec.queue_by_name('scheduler_start_method') << 'queued' + ResqueSpec.reset_by_name!('scheduler_start_method') + ResqueSpec.queue_by_name('scheduler_start_method').should be_empty + end + end end From fd5198f4693da5e399f6d99928d30217a588731d Mon Sep 17 00:00:00 2001 From: Zhdanov Date: Wed, 16 Oct 2019 20:58:20 +0300 Subject: [PATCH 2/2] add description for resque-scheduler --- README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/README.md b/README.md index 918f814..887beb6 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,47 @@ describe "#recalculate" do end ``` +Resque-scheduler +----------------------------------------------------- + +For usage with resque-scheduler gem, you may want to those methods +`Resque.set_schedule(name, config)` and dequeuing `Resque.remove_schedule(name)` + +Let's see simple example, when you need to check if it was scheduled or not. +The first example will only match for args option in config. +The second context with cron, adds more precise for matching. If you need not only to verify +whether it was scheduled, but also cron tab for performing action, you should chain `with_cron` method. +```ruby +describe "#schedule" do + before do + ResqueSpec.reset! # or you can use ResqueSpec.reset_by_name!(name), which is more precise + end + + let(:config) do + { + args: ["person_recalculation", [1, 2, 3] + cron: "0 * * * *" # hourly + } + end + + it "adds an entry to the named schedule queue with args" do + Resque.set_schedule("person_recalculation", config) + + expect("person_recalculation").to have_set_schedule([1, 2, 3]) + end + + context "with_cron" do + it "adds an entry to the named schedule queue with cron tab check" do + Resque.set_schedule("person_recalculation", config) + + expect("person_recalculation").to have_set_schedule([1, 2, 3]).with_cron("0 * * * *") + end + end +end + +``` + + Turning off ResqueSpec and calling directly to Resque -----------------------------------------------------