loading...

How to RSpec your sidekiq-scheduler

pashagray profile image Pavel Tkachenko ・3 min read

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!

Posted on by:

pashagray profile

Pavel Tkachenko

@pashagray

Ruby Fullstack Developer. In love with Ruby and Rails. Sometimes happy with JS.

Discussion

markdown guide