DEV Community

Pavel Tkachenko
Pavel Tkachenko

Posted on

How to RSpec your sidekiq-scheduler

sidekiq-scheduler is a pretty awesome tool to cron your sidekiq jobs. All you need is to add a schedule to your sidekiq.yml file.

Let's look at simple job with sidekiq-scheduler and yaml schedule itself.

# hello-scheduler.rbs
class HelloWorld < ApplicationJob
  def perform
    puts "Hello world"
  end
end
# config/sidekiq.yml

:schedule:
  hello_world:
    cron: '0 0 * * * *'  # Runs every hour
    class: HelloWorld

But how you can test it to be sure that schedule does't have errors, cron syntax is correct and job class exists? You know that it's very easy to mess up your cron syntax! I will show and explain a snippet you can copy-paste to your project which will automatically check your sidekiq.yml file for errors.

Create file sidekiq_schedululer_spec.rb in spec/jobs folder. Sidekiq-scheduler uses fugit under the hood to evaluate cron schedule. We will use it too, but for cron syntax checking. You don't need to add it in your Gemfile, because it's already included as a dependency in sidekiq-scheduler. The only thing is that you have to require it. Then we need to load our sidekiq.yml file and parse it to ruby hash and store in schedule variable.

require "rails_helper"
require "fugit"

RSpec.describe "sidekiq-scheduler" do
  sidekiq_file = File.join(Rails.root, "config", "sidekiq.yml")
  schedule = YAML.load_file(sidekiq_file)[:schedule]

  describe "cron syntax"
  describe "job classes"
  describe "job names" # optional
end

Here I defined three specs. We need to check that cron syntax (0 0 * * * *) is correct, job class (HelloWorld) exists and job name in schedule (hello_world) is similar to job class.

First is cron. We just take every value in the file and pass it to Fugit. If Fugit raises error because it is not able to parse cron string, test fails.

describe "cron syntax" do
  schedule.each do |k, v|
    cron = v["cron"]
    it "#{k} has correct cron syntax" do
      expect { Fugit.do_parse(cron) }.not_to raise_error
    end
  end
end

Second, we need to check that job class exists. We just need to constantize our class string and if it raises error, test fails.

describe "job classes" do
  schedule.each do |k, v|
    klass = v["class"]
    it "#{k} has #{klass} class in /jobs" do
      expect { klass.constantize }.not_to raise_error
    end
  end
end

Third, we can check that job name (hello_world) is similar to class name(HelloWorld). It can be easily done by underscoring class name and compare it with job name.

describe "job names" do
  schedule.each do |k, v|
    klass = v["class"]
    it "#{k} has correct name" do
      expect(k).to eq(klass.underscore)
    end
  end
end

Full snippet is here. You can just copy and paste it in your project.

require "rails_helper"
require "fugit"

RSpec.describe "sidekiq-scheduler" do
  sidekiq_file = File.join(Rails.root, "config", "sidekiq.yml")
  schedule = YAML.load_file(sidekiq_file)[:schedule]

  describe "cron syntax" do
    schedule.each do |k, v|
      cron = v["cron"]
      it "#{k} has correct cron syntax" do
        expect { Fugit.do_parse(cron) }.not_to raise_error
      end
    end
  end

  describe "job classes" do
    schedule.each do |k, v|
      klass = v["class"]
      it "#{k} has #{klass} class in /jobs" do
        expect { klass.constantize }.not_to raise_error
      end
    end
  end

  describe "job names" do
    schedule.each do |k, v|
      klass = v["class"]
      it "#{k} has correct name" do
        expect(k).to eq(klass.underscore)
      end
    end
  end
end

This technique is usefull not only for sidekiq-scheduler. You can parse and test any yaml/json files in your projects in this way. Good luck with your RSpec experiments!

Top comments (3)

Collapse
 
exocode profile image
Jan

Just wanna mention, that sidekiq-scheduler support more options than cron: only: there is also every:, in:, at:. To not having failing specs you could add these options too:


  describe "cron syntax" do
    schedule.each do |k, v|
      cron = v["cron"] || v["every"] || v["at"] || v["in"]
      it "#{k} has correct cron syntax" do
        expect { Fugit.do_parse(cron) }.not_to raise_error
      end
    end
  end

Enter fullscreen mode Exit fullscreen mode
Collapse
 
mikhail profile image
Миша Лопандя • Edited

Have you tested cron job triggering?
so what I want to test:
if my job will be triggered on may 5 2020 10:25:00 +0200
with my sidekiq cron:

"Job Alerts: Daily sending - every day at 10:25":
  cron: "25 10 * * *"
  class: "JobAlertsWorker"
Enter fullscreen mode Exit fullscreen mode

what is the best way to do it?

Collapse
 
margonzalez profile image
Martin Gonzalez

Just created an account to comment this post because doesn't have any. Nice work dude!