sidekiq-cron 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ en:
2
+ Job: Job
3
+ Cron: Cron
4
+ CronJobs: Cron Jobs
5
+ EnqueueNow: Enqueue Now
6
+ AreYouSureDeleteCronJob: Are you sure you want to delete the %{job} cron job?
7
+ NoCronJobsFound: "No cron jobs found"
@@ -0,0 +1,65 @@
1
+ require 'sidekiq'
2
+ require 'sidekiq/util'
3
+ require 'sidekiq/actor'
4
+ require 'sidekiq/cron'
5
+
6
+ module Sidekiq
7
+ module Cron
8
+
9
+ POLL_INTERVAL = 10
10
+
11
+ ##
12
+ # The Poller checks Redis every N seconds for sheduled cron jobs
13
+ class Poller
14
+ include Util
15
+ include Actor
16
+
17
+ def poll(first_time=false)
18
+ watchdog('scheduling cron poller thread died!') do
19
+ add_jitter if first_time
20
+
21
+ begin
22
+ time_now = Time.now
23
+
24
+ #go through all jobs
25
+ Sidekiq::Cron::Job.all.each do |job|
26
+ #test if job should be enequed
27
+ # if yes add job to queue
28
+ begin
29
+ job.test_and_enque_for_time! time_now if job && job.valid?
30
+ rescue => ex
31
+ #problem somewhere in one job
32
+ logger.error "CRON JOB: #{ex.message}"
33
+ logger.error "CRON JOB: #{ex.backtrace.first}"
34
+ end
35
+ end
36
+
37
+ rescue => ex
38
+ # Most likely a problem with redis networking.
39
+ # Punt and try again at the next interval
40
+ logger.error ex.message
41
+ logger.error ex.backtrace.first
42
+ end
43
+
44
+ after(poll_interval) { poll }
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ def poll_interval
51
+ Sidekiq.options[:poll_interval] || POLL_INTERVAL
52
+ end
53
+
54
+ def add_jitter
55
+ begin
56
+ sleep(poll_interval * rand)
57
+ rescue Celluloid::Task::TerminatedError
58
+ # Hit Ctrl-C when Sidekiq is finished booting and we have a chance
59
+ # to get here.
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,47 @@
1
+ header.row
2
+ .span5
3
+ h3 = t('CronJobs')
4
+ - if @cron_jobs.size > 0
5
+
6
+ table class="table table-hover table-bordered table-striped"
7
+ thead
8
+ th = t('Status')
9
+ th = t('Name')
10
+ th = t('Cron')
11
+ th = t('Last enque')
12
+ th = t('Arguments')
13
+ th width="253px"
14
+ = t('Actions')
15
+
16
+
17
+ - @cron_jobs.sort{|a,b| a.sort_name <=> b.sort_name }.each_with_index do |job, index|
18
+ - style = "#{job.status == 'disabled' ? "background: #ecc": ""}"
19
+ tr
20
+ td[style="#{style}"]= job.status
21
+ td[style="#{style}"]= job.name
22
+ td[style="#{style}"]
23
+ b == job.cron.gsub(" ", "&nbsp;")
24
+ td[style="#{style}"]== relative_time(job.last_run_time)
25
+ td[style="#{style}"]
26
+ - if job.message and job.message.to_s.size > 100
27
+ button data-toggle="collapse" data-target=".worker_#{index}" class="btn btn-mini" = t('ShowAll')
28
+ .toggle[class="worker_#{index}" style="display: inline;"]= job.message[0..100] + "... "
29
+ .toggle[class="worker_#{index}" style="display: none;"]= job.message
30
+ - else
31
+ = job.message
32
+ td[style="#{style}"]
33
+ -if job.status == 'enabled'
34
+ form action="#{root_path}cron/#{job.name}/enque" method="post"
35
+ input.btn.btn-small.pull-left type="submit" name="enque" value="#{t('EnqueueNow')}"
36
+ form action="#{root_path}cron/#{job.name}/disable" method="post"
37
+ input.btn.btn-small.pull-left type="submit" name="disable" value="#{t('Disable')}"
38
+ -else
39
+ form action="#{root_path}cron/#{job.name}/enque" method="post"
40
+ input.btn.btn-small.pull-left type="submit" name="enque" value="#{t('EnqueueNow')}"
41
+ form action="#{root_path}cron/#{job.name}/enable" method="post"
42
+ input.btn.btn-small.pull-left type="submit" name="enable" value="#{t('Enable')}"
43
+ form action="#{root_path}cron/#{job.name}/delete" method="post"
44
+ input.btn.btn-danger.btn-small type="submit" name="delete" value="#{t('Delete')}" data-confirm="#{t('AreYouSureDeleteCronJob', :job => job.name)}"
45
+
46
+ - else
47
+ .alert.alert-success = t('NoCronJobsFound')
@@ -0,0 +1,75 @@
1
+ module Sidekiq
2
+ module Cron
3
+ module WebExtension
4
+
5
+ def self.registered(app)
6
+
7
+ #very bad way of loading locales for cron jobs
8
+ #should be rewritten
9
+ app.helpers do
10
+
11
+ alias_method :old_strings, :strings
12
+
13
+ def strings
14
+ #only on first load!
15
+ unless @strings
16
+ #load all locales from Sidekiq
17
+ old_strings
18
+
19
+ Dir["#{File.join(File.expand_path("..", __FILE__), "locales")}/*.yml"].each do |file|
20
+ YAML.load(File.open(file)).each do |locale, translations|
21
+ translations.each do |key, value|
22
+ @strings[locale][key] = value
23
+ end
24
+ end
25
+ end
26
+ end
27
+ @strings
28
+ end
29
+ end
30
+
31
+ #index page of cron jobs
32
+ app.get '/cron' do
33
+ view_path = File.join(File.expand_path("..", __FILE__), "views")
34
+
35
+ @cron_jobs = Sidekiq::Cron::Job.all
36
+
37
+ render(:slim, File.read(File.join(view_path, "cron.slim")))
38
+ end
39
+
40
+ #enque cron job
41
+ app.post '/cron/:name/enque' do |name|
42
+ if job = Sidekiq::Cron::Job.find(name)
43
+ job.enque!
44
+ end
45
+ redirect "#{root_path}cron"
46
+ end
47
+
48
+ #delete schedule
49
+ app.post '/cron/:name/delete' do |name|
50
+ if job = Sidekiq::Cron::Job.find(name)
51
+ job.destroy
52
+ end
53
+ redirect "#{root_path}cron"
54
+ end
55
+
56
+ #enable job
57
+ app.post '/cron/:name/enable' do |name|
58
+ if job = Sidekiq::Cron::Job.find(name)
59
+ job.enable!
60
+ end
61
+ redirect "#{root_path}cron"
62
+ end
63
+
64
+ #disable job
65
+ app.post '/cron/:name/disable' do |name|
66
+ if job = Sidekiq::Cron::Job.find(name)
67
+ job.disable!
68
+ end
69
+ redirect "#{root_path}cron"
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,46 @@
1
+ require 'sidekiq/cron/poller'
2
+
3
+
4
+ # For Cron we need to add some methods to Launcher
5
+ # so look at the code bellow.
6
+ #
7
+ # we are creating new cron poller instance and
8
+ # adding start and stop commands to launcher
9
+ module Sidekiq
10
+ class Launcher
11
+
12
+ #Add cron poller to launcher
13
+ attr_reader :cron_poller
14
+
15
+
16
+ #remember old initialize
17
+ alias_method :old_initialize, :initialize
18
+
19
+ #add cron poller and execute normal initialize of Sidekiq launcher
20
+ def initialize(options)
21
+ @cron_poller = Sidekiq::Cron::Poller.new
22
+ old_initialize options
23
+ end
24
+
25
+
26
+ #remember old run
27
+ alias_method :old_run, :run
28
+
29
+ #execute normal run of launcher and run cron poller
30
+ def run
31
+ old_run
32
+ cron_poller.async.poll(true)
33
+ end
34
+
35
+
36
+ #remember old stop
37
+ alias_method :old_stop, :stop
38
+
39
+ #execute normal stop of launcher and stop cron poller
40
+ def stop
41
+ cron_poller.async.terminate if poller.alive?
42
+ old_stop
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,104 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "sidekiq-cron"
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ondrej Bartas"]
12
+ s.date = "2013-08-25"
13
+ s.description = "Enables to set jobs to be run in specified time (using CRON notation)"
14
+ s.email = "ondrej@bartas.cz"
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".travis.yml",
22
+ "Changes.md",
23
+ "Gemfile",
24
+ "LICENSE.txt",
25
+ "README.md",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "config.ru",
29
+ "examples/web-cron-ui.png",
30
+ "lib/sidekiq-cron.rb",
31
+ "lib/sidekiq/cron.rb",
32
+ "lib/sidekiq/cron/job.rb",
33
+ "lib/sidekiq/cron/locales/en.yml",
34
+ "lib/sidekiq/cron/poller.rb",
35
+ "lib/sidekiq/cron/views/cron.slim",
36
+ "lib/sidekiq/cron/web_extension.rb",
37
+ "lib/sidekiq/launcher.rb",
38
+ "sidekiq-cron.gemspec",
39
+ "test/test_helper.rb",
40
+ "test/unit/job_test.rb",
41
+ "test/unit/poller_test.rb",
42
+ "test/unit/web_extesion_test.rb"
43
+ ]
44
+ s.homepage = "http://github.com/ondrejbartas/sidekiq-cron"
45
+ s.licenses = ["MIT"]
46
+ s.require_paths = ["lib"]
47
+ s.rubygems_version = "1.8.25"
48
+ s.summary = "Sidekiq Cron helps to add repeated scheduled jobs"
49
+
50
+ if s.respond_to? :specification_version then
51
+ s.specification_version = 3
52
+
53
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
+ s.add_runtime_dependency(%q<sidekiq>, [">= 2.13.1"])
55
+ s.add_runtime_dependency(%q<parse-cron>, [">= 0.1.2"])
56
+ s.add_development_dependency(%q<bundler>, [">= 0"])
57
+ s.add_development_dependency(%q<simplecov>, [">= 0"])
58
+ s.add_development_dependency(%q<shoulda-context>, [">= 0"])
59
+ s.add_development_dependency(%q<turn>, [">= 0"])
60
+ s.add_development_dependency(%q<rack>, [">= 0"])
61
+ s.add_development_dependency(%q<rack-test>, [">= 0"])
62
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
63
+ s.add_development_dependency(%q<sdoc>, [">= 0"])
64
+ s.add_development_dependency(%q<slim>, [">= 0"])
65
+ s.add_development_dependency(%q<sinatra>, [">= 0"])
66
+ s.add_development_dependency(%q<mocha>, [">= 0"])
67
+ s.add_development_dependency(%q<coveralls>, [">= 0"])
68
+ s.add_development_dependency(%q<shotgun>, [">= 0"])
69
+ else
70
+ s.add_dependency(%q<sidekiq>, [">= 2.13.1"])
71
+ s.add_dependency(%q<parse-cron>, [">= 0.1.2"])
72
+ s.add_dependency(%q<bundler>, [">= 0"])
73
+ s.add_dependency(%q<simplecov>, [">= 0"])
74
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
75
+ s.add_dependency(%q<turn>, [">= 0"])
76
+ s.add_dependency(%q<rack>, [">= 0"])
77
+ s.add_dependency(%q<rack-test>, [">= 0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
79
+ s.add_dependency(%q<sdoc>, [">= 0"])
80
+ s.add_dependency(%q<slim>, [">= 0"])
81
+ s.add_dependency(%q<sinatra>, [">= 0"])
82
+ s.add_dependency(%q<mocha>, [">= 0"])
83
+ s.add_dependency(%q<coveralls>, [">= 0"])
84
+ s.add_dependency(%q<shotgun>, [">= 0"])
85
+ end
86
+ else
87
+ s.add_dependency(%q<sidekiq>, [">= 2.13.1"])
88
+ s.add_dependency(%q<parse-cron>, [">= 0.1.2"])
89
+ s.add_dependency(%q<bundler>, [">= 0"])
90
+ s.add_dependency(%q<simplecov>, [">= 0"])
91
+ s.add_dependency(%q<shoulda-context>, [">= 0"])
92
+ s.add_dependency(%q<turn>, [">= 0"])
93
+ s.add_dependency(%q<rack>, [">= 0"])
94
+ s.add_dependency(%q<rack-test>, [">= 0"])
95
+ s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
96
+ s.add_dependency(%q<sdoc>, [">= 0"])
97
+ s.add_dependency(%q<slim>, [">= 0"])
98
+ s.add_dependency(%q<sinatra>, [">= 0"])
99
+ s.add_dependency(%q<mocha>, [">= 0"])
100
+ s.add_dependency(%q<coveralls>, [">= 0"])
101
+ s.add_dependency(%q<shotgun>, [">= 0"])
102
+ end
103
+ end
104
+
@@ -0,0 +1,67 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+
11
+ require 'simplecov'
12
+ SimpleCov.start do
13
+ add_filter "/test/"
14
+
15
+ add_group 'SidekiqCron', 'lib/'
16
+ end
17
+ require 'coveralls'
18
+ Coveralls.wear!
19
+
20
+ require "minitest/autorun"
21
+ require 'shoulda-context'
22
+ require 'turn'
23
+ require "rack/test"
24
+ require "mocha/setup"
25
+
26
+ #SIDEKIQ Require - need to have sidekiq running!
27
+ require 'celluloid/autostart'
28
+ require 'sidekiq'
29
+ require 'sidekiq/util'
30
+ require 'sidekiq/web'
31
+
32
+ Sidekiq.logger.level = Logger::ERROR
33
+
34
+ require 'sidekiq/redis_connection'
35
+ redis_url = ENV['REDIS_URL'] || 'redis://localhost/15'
36
+ REDIS = Sidekiq::RedisConnection.create(:url => redis_url, :namespace => 'testy')
37
+
38
+ Sidekiq.configure_client do |config|
39
+ config.redis = { :url => redis_url, :namespace => 'testy' }
40
+ end
41
+
42
+
43
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
44
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
45
+ require 'sidekiq-cron'
46
+
47
+ class Test::Unit::TestCase
48
+ end
49
+
50
+
51
+ class CronTestClass
52
+ include Sidekiq::Worker
53
+
54
+ def perform args = {}
55
+ puts "super croned job #{args}"
56
+ end
57
+ end
58
+
59
+ class CronTestClassWithQueue
60
+ include Sidekiq::Worker
61
+ sidekiq_options :queue => :super, :retry => false, :backtrace => true
62
+
63
+ def perform args = {}
64
+ puts "super croned job #{args}"
65
+ end
66
+ end
67
+
@@ -0,0 +1,529 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require './test/test_helper'
3
+
4
+ class CronJobTest < Test::Unit::TestCase
5
+ context "Cron Job" do
6
+
7
+ setup do
8
+ #clear all previous saved data from redis
9
+ Sidekiq.redis do |conn|
10
+ conn.keys("cron_job*").each do |key|
11
+ conn.del(key)
12
+ end
13
+ end
14
+
15
+ #clear all queues
16
+ Sidekiq::Queue.all.each do |queue|
17
+ queue.clear
18
+ end
19
+ end
20
+
21
+ should "be initialized" do
22
+ job = Sidekiq::Cron::Job.new()
23
+ assert job.is_a?(Sidekiq::Cron::Job)
24
+ end
25
+
26
+ context "class methods" do
27
+ should "have create method" do
28
+ assert Sidekiq::Cron::Job.respond_to?(:create)
29
+ end
30
+
31
+ should "have destroy method" do
32
+ assert Sidekiq::Cron::Job.respond_to?(:destroy)
33
+ end
34
+
35
+ should "have count" do
36
+ assert Sidekiq::Cron::Job.respond_to?(:count)
37
+ end
38
+
39
+ should "have all" do
40
+ assert Sidekiq::Cron::Job.respond_to?(:all)
41
+ end
42
+
43
+ should "have find" do
44
+ assert Sidekiq::Cron::Job.respond_to?(:find)
45
+ end
46
+ end
47
+
48
+ context "instance methods" do
49
+ setup do
50
+ @job = Sidekiq::Cron::Job.new()
51
+ end
52
+
53
+ should "have save method" do
54
+ assert @job.respond_to?(:save)
55
+ end
56
+ should "have valid? method" do
57
+ assert @job.respond_to?("valid?".to_sym)
58
+ end
59
+ should "have destroy method" do
60
+ assert @job.respond_to?(:destroy)
61
+ end
62
+
63
+ should 'have sort_name - used for sorting enabled disbaled jobs on frontend' do
64
+ job = Sidekiq::Cron::Job.new(name: "TestName")
65
+ assert_equal job.sort_name, "0_testname"
66
+ end
67
+ end
68
+
69
+ context "invalid job" do
70
+
71
+ setup do
72
+ @job = Sidekiq::Cron::Job.new()
73
+ end
74
+
75
+ should "return false on valid? and errors" do
76
+ refute @job.valid?
77
+ assert @job.errors.is_a?(Array)
78
+
79
+ assert @job.errors.any?{|e| e.include?("name")}, "Should have error for name"
80
+ assert @job.errors.any?{|e| e.include?("cron")}, "Should have error for cron"
81
+ assert @job.errors.any?{|e| e.include?("klass")}, "Should have error for klass"
82
+ end
83
+
84
+ should "return false on valid? with invalid cron" do
85
+ @job.cron = "* s *"
86
+ refute @job.valid?
87
+ assert @job.errors.is_a?(Array)
88
+ assert @job.errors.any?{|e| e.include?("cron")}, "Should have error for cron"
89
+ end
90
+
91
+ should "return false on save" do
92
+ refute @job.save
93
+ end
94
+ end
95
+
96
+ context "new" do
97
+ setup do
98
+ @args = {
99
+ name: "Test",
100
+ cron: "* * * * *"
101
+ }
102
+ @job = Sidekiq::Cron::Job.new(@args)
103
+ end
104
+
105
+ should "have all setted attributes" do
106
+ @args.each do |key, value|
107
+ assert_equal @job.send(key), value, "New job should have #{key} with value #{value} but it has: #{@job.send(key)}"
108
+ end
109
+ end
110
+
111
+ should "have to_hash method" do
112
+ [:name,:klass,:cron,:args,:message,:status, :last_run_time].each do |key|
113
+ assert @job.to_hash.has_key?(key), "to_hash must have key: #{key}"
114
+ end
115
+ end
116
+ end
117
+
118
+ context "new with different class inputs" do
119
+ should "be initialized by 'klass' and Class" do
120
+ assert_nothing_raised do
121
+ Sidekiq::Cron::Job.new('klass' => CronTestClass)
122
+ end
123
+ end
124
+
125
+ should "be initialized by 'klass' and string Class" do
126
+ assert_nothing_raised do
127
+ Sidekiq::Cron::Job.new('klass' => 'CronTestClass')
128
+ end
129
+ end
130
+
131
+ should "be initialized by 'class' and string Class" do
132
+ assert_nothing_raised do
133
+ Sidekiq::Cron::Job.new('class' => 'CronTestClass')
134
+ end
135
+ end
136
+
137
+ should "be initialized by 'class' and Class" do
138
+ assert_nothing_raised do
139
+ Sidekiq::Cron::Job.new('class' => CronTestClass)
140
+ end
141
+ end
142
+ end
143
+
144
+ context "new should find klass specific settings (queue, retry ...)" do
145
+ should "nothing raise on unknown klass" do
146
+ assert_nothing_raised do
147
+ job = Sidekiq::Cron::Job.new('klass' => 'UnknownCronClass')
148
+ assert_equal job.message, {"class"=>"UnknownCronClass", "args"=>[], "queue"=>"default"}
149
+ end
150
+ end
151
+
152
+ should "be initialized with default attributes" do
153
+ assert_nothing_raised do
154
+ job = Sidekiq::Cron::Job.new('klass' => 'CronTestClass')
155
+
156
+ assert_equal job.message, {"retry"=>true, "queue"=>"default", "class"=>"CronTestClass", "args"=>[]}
157
+ end
158
+ end
159
+
160
+ should "be initialized with class specified attributes" do
161
+ assert_nothing_raised do
162
+ job = Sidekiq::Cron::Job.new('class' => 'CronTestClassWithQueue')
163
+ assert_equal job.message, {"retry"=>false,
164
+ "queue"=>:super,
165
+ "backtrace"=>true,
166
+ "class"=>"CronTestClassWithQueue",
167
+ "args"=>[]}
168
+ end
169
+ end
170
+
171
+ should "be initialized with 'class' and overwrite queue by settings" do
172
+ assert_nothing_raised do
173
+ job = Sidekiq::Cron::Job.new('class' => CronTestClassWithQueue, queue: 'my_testing_queue')
174
+
175
+ assert_equal job.message, {"retry"=>false,
176
+ "queue"=>'my_testing_queue',
177
+ "backtrace"=>true,
178
+ "class"=>"CronTestClassWithQueue",
179
+ "args"=>[]}
180
+ end
181
+ end
182
+ end
183
+
184
+ context "cron test" do
185
+ setup do
186
+ @job = Sidekiq::Cron::Job.new()
187
+ end
188
+
189
+ should "return previous minute" do
190
+ @job.cron = "* * * * *"
191
+ time = Time.now
192
+ assert_equal @job.last_time(time).strftime("%Y-%m-%d-%H-%M-%S"), time.strftime("%Y-%m-%d-%H-%M-00")
193
+ end
194
+
195
+ should "return previous hour" do
196
+ @job.cron = "1 * * * *"
197
+ time = Time.now
198
+ assert_equal @job.last_time(time).strftime("%Y-%m-%d-%H-%M-%S"), time.strftime("%Y-%m-%d-%H-01-00")
199
+ end
200
+
201
+ should "return previous day" do
202
+ @job.cron = "1 2 * * *"
203
+ time = Time.now
204
+ assert_equal @job.last_time(time).strftime("%Y-%m-%d-%H-%M-%S"), time.strftime("%Y-%m-%d-02-01-00")
205
+ end
206
+
207
+ end
208
+
209
+ context "save" do
210
+ setup do
211
+ @args = {
212
+ name: "Test",
213
+ cron: "* * * * *",
214
+ klass: "CronTestClass"
215
+ }
216
+ @job = Sidekiq::Cron::Job.new(@args)
217
+ end
218
+
219
+ should "be saved" do
220
+ assert @job.save
221
+ end
222
+
223
+
224
+ should "be saved and found by name" do
225
+ assert @job.save, "not saved"
226
+ assert Sidekiq::Cron::Job.find("Test").is_a?(Sidekiq::Cron::Job)
227
+ end
228
+ end
229
+
230
+ context "nonexisting job" do
231
+ should "not be found" do
232
+ assert Sidekiq::Cron::Job.find("nonexisting").nil?, "should return nil"
233
+ end
234
+ end
235
+
236
+ context "disabled/enabled" do
237
+ setup do
238
+ @args = {
239
+ name: "Test",
240
+ cron: "* * * * *",
241
+ klass: "CronTestClass"
242
+ }
243
+ end
244
+
245
+ should "be created and enabled" do
246
+ Sidekiq::Cron::Job.create(@args)
247
+ job = Sidekiq::Cron::Job.find(@args)
248
+ assert_equal job.status, "enabled"
249
+ end
250
+
251
+ should "be created and then enabled and disabled" do
252
+ Sidekiq::Cron::Job.create(@args)
253
+ job = Sidekiq::Cron::Job.find(@args)
254
+ assert_equal job.status, "enabled"
255
+
256
+ job.enable!
257
+ assert_equal job.status, "enabled"
258
+
259
+ job.disable!
260
+ assert_equal job.status, "disabled"
261
+ end
262
+
263
+ should "be created with status disabled" do
264
+ Sidekiq::Cron::Job.create(@args.merge(status: "disabled"))
265
+ job = Sidekiq::Cron::Job.find(@args)
266
+ assert_equal job.status, "disabled"
267
+ end
268
+
269
+ should "be created with status enabled and disable it afterwards" do
270
+ Sidekiq::Cron::Job.create(@args)
271
+ job = Sidekiq::Cron::Job.find(@args)
272
+ assert_equal job.status, "enabled"
273
+ job.disable!
274
+ assert_equal job.status, "disabled", "directly after call"
275
+ job = Sidekiq::Cron::Job.find(@args)
276
+ assert_equal job.status, "disabled", "after find"
277
+ end
278
+
279
+ should "status shouldn't be rewritten after save without status" do
280
+ Sidekiq::Cron::Job.create(@args)
281
+ job = Sidekiq::Cron::Job.find(@args)
282
+ assert_equal job.status, "enabled"
283
+ job.disable!
284
+ assert_equal job.status, "disabled", "directly after call"
285
+ job = Sidekiq::Cron::Job.find(@args)
286
+ assert_equal job.status, "disabled", "after find"
287
+
288
+ Sidekiq::Cron::Job.create(@args)
289
+ assert_equal job.status, "disabled", "after second create"
290
+ job = Sidekiq::Cron::Job.find(@args)
291
+ assert_equal job.status, "disabled", "after second find"
292
+ end
293
+ end
294
+
295
+ context "create & find methods" do
296
+ setup do
297
+ @args = {
298
+ name: "Test",
299
+ cron: "* * * * *",
300
+ klass: "CronTestClass"
301
+ }
302
+ end
303
+
304
+ should "create first three jobs" do
305
+ assert_equal Sidekiq::Cron::Job.count, 0, "Should have 0 jobs"
306
+ Sidekiq::Cron::Job.create(@args)
307
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test2"))
308
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test3"))
309
+ assert_equal Sidekiq::Cron::Job.count, 3, "Should have 3 jobs"
310
+ end
311
+
312
+ should "create first three jobs - 1 has same name" do
313
+ assert_equal Sidekiq::Cron::Job.count, 0, "Should have 0 jobs"
314
+ Sidekiq::Cron::Job.create(@args)
315
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test2"))
316
+ Sidekiq::Cron::Job.create(@args.merge(cron: "1 * * * *"))
317
+ assert_equal Sidekiq::Cron::Job.count, 2, "Should have 2 jobs"
318
+ end
319
+
320
+ should "be found by method all" do
321
+ Sidekiq::Cron::Job.create(@args)
322
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test2"))
323
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test3"))
324
+ assert_equal Sidekiq::Cron::Job.all.size, 3, "Should have 3 jobs"
325
+ assert Sidekiq::Cron::Job.all.all?{|j| j.is_a?(Sidekiq::Cron::Job)}, "All returned jobs should be Job class"
326
+ end
327
+
328
+ should "be found by method all - defect in set" do
329
+ Sidekiq::Cron::Job.create(@args)
330
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test2"))
331
+ Sidekiq::Cron::Job.create(@args.merge(name: "Test3"))
332
+
333
+ Sidekiq.redis do |conn|
334
+ conn.sadd Sidekiq::Cron::Job.jobs_key, "some_other_key"
335
+ end
336
+
337
+ assert_equal Sidekiq::Cron::Job.all.size, 3, "All have to return only valid 3 jobs"
338
+ end
339
+
340
+ should "be found by string name" do
341
+ Sidekiq::Cron::Job.create(@args)
342
+ assert Sidekiq::Cron::Job.find("Test")
343
+ end
344
+
345
+ should "be found by hash with key name" do
346
+ Sidekiq::Cron::Job.create(@args)
347
+ assert Sidekiq::Cron::Job.find(name: "Test"), "symbol keys keys"
348
+
349
+ Sidekiq::Cron::Job.create(@args)
350
+ assert Sidekiq::Cron::Job.find('name' => "Test"), "String keys"
351
+ end
352
+
353
+ end
354
+
355
+ context "destroy" do
356
+ setup do
357
+ @args = {
358
+ name: "Test",
359
+ cron: "* * * * *",
360
+ klass: "CronTestClass"
361
+ }
362
+ end
363
+
364
+ should "create and then destroy by hash" do
365
+ Sidekiq::Cron::Job.create(@args)
366
+ assert_equal Sidekiq::Cron::Job.all.size, 1, "Should have 1 job"
367
+
368
+ assert Sidekiq::Cron::Job.destroy(@args)
369
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 job after destroy"
370
+ end
371
+
372
+ should "return false on destroying nonexisting" do
373
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 jobs"
374
+ refute Sidekiq::Cron::Job.destroy("nonexisting")
375
+ end
376
+
377
+ should "return destroy by string name" do
378
+ Sidekiq::Cron::Job.create(@args)
379
+ assert Sidekiq::Cron::Job.destroy("Test")
380
+ end
381
+
382
+ should "return destroy by hash with key name" do
383
+ Sidekiq::Cron::Job.create(@args)
384
+ assert Sidekiq::Cron::Job.destroy(name: "Test"), "symbol keys keys"
385
+
386
+ Sidekiq::Cron::Job.create(@args)
387
+ assert Sidekiq::Cron::Job.destroy('name' => "Test"), "String keys"
388
+ end
389
+
390
+ end
391
+
392
+ context "test of enque" do
393
+ setup do
394
+ @args = {
395
+ name: "Test",
396
+ cron: "* * * * *",
397
+ klass: "CronTestClass"
398
+ }
399
+ #first time is allways
400
+ #after next cron time!
401
+ @time = Time.now + 120
402
+ end
403
+ should "be allways false when status is disabled" do
404
+ refute Sidekiq::Cron::Job.new(@args.merge(status: 'disabled')).should_enque? @time
405
+ refute Sidekiq::Cron::Job.new(@args.merge(status: 'disabled')).should_enque? @time - 60
406
+ refute Sidekiq::Cron::Job.new(@args.merge(status: 'disabled')).should_enque? @time - 120
407
+ assert_equal Sidekiq::Queue.all.size, 0, "Sidekiq 0 queues"
408
+ end
409
+
410
+ should "be false for same times" do
411
+ assert Sidekiq::Cron::Job.new(@args).should_enque?(@time), "First time - true"
412
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time
413
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time
414
+ end
415
+
416
+ should "be false for same times but true for next time" do
417
+ assert Sidekiq::Cron::Job.new(@args).should_enque?(@time), "First time - true"
418
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time
419
+ assert Sidekiq::Cron::Job.new(@args).should_enque? @time + 135
420
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time + 135
421
+ assert Sidekiq::Cron::Job.new(@args).should_enque? @time + 235
422
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time + 235
423
+
424
+ #just for check
425
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time
426
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time + 135
427
+ refute Sidekiq::Cron::Job.new(@args).should_enque? @time + 235
428
+ end
429
+
430
+ should "remove old enque times + should be enqeued" do
431
+ assert Sidekiq::Cron::Job.new(@args).test_and_enque_for_time!(@time), "should enqueue"
432
+ refute Sidekiq::Cron::Job.new(@args).test_and_enque_for_time!(@time), "should not enqueue"
433
+ Sidekiq.redis do |conn|
434
+ assert_equal conn.zcard(Sidekiq::Cron::Job.new(@args).send(:job_enqueued_key)), 2, "Should have two enqueued job (first was in save, second in enque)"
435
+ end
436
+ assert_equal Sidekiq::Queue.all.first.size, 1, "Sidekiq queue 1 job in queue"
437
+
438
+ # 20 hours after
439
+ assert Sidekiq::Cron::Job.new(@args).test_and_enque_for_time! @time + 1 * 60 * 60
440
+ refute Sidekiq::Cron::Job.new(@args).test_and_enque_for_time! @time + 1 * 60 * 60
441
+
442
+ Sidekiq.redis do |conn|
443
+ assert_equal conn.zcard(Sidekiq::Cron::Job.new(@args).send(:job_enqueued_key)), 3, "Should have two enqueued job + one from start"
444
+ end
445
+ assert_equal Sidekiq::Queue.all.first.size, 2, "Sidekiq queue 2 jobs in queue"
446
+
447
+ # 26 hour after
448
+ assert Sidekiq::Cron::Job.new(@args).test_and_enque_for_time! @time + 26 * 60 * 60
449
+ refute Sidekiq::Cron::Job.new(@args).test_and_enque_for_time! @time + 26 * 60 * 60
450
+
451
+ Sidekiq.redis do |conn|
452
+ assert_equal conn.zcard(Sidekiq::Cron::Job.new(@args).send(:job_enqueued_key)), 1, "Should have one enqueued job - old jobs should be deleted"
453
+ end
454
+ assert_equal Sidekiq::Queue.all.first.size, 3, "Sidekiq queue 3 jobs in queue"
455
+ end
456
+ end
457
+
458
+ context "load" do
459
+
460
+ context "from hash" do
461
+ setup do
462
+ @jobs_hash = {
463
+ 'name_of_job' => {
464
+ 'class' => 'MyClass',
465
+ 'cron' => '1 * * * *',
466
+ 'args' => '(OPTIONAL) [Array or Hash]'
467
+ },
468
+ 'My super iber cool job' => {
469
+ 'class' => 'SecondClass',
470
+ 'cron' => '*/5 * * * *'
471
+ }
472
+ }
473
+ end
474
+
475
+ should "create new jobs and update old one with same settings" do
476
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 jobs before load"
477
+ out = Sidekiq::Cron::Job.load_from_hash @jobs_hash
478
+ assert_equal out.size, 0, "should have no errors"
479
+ assert_equal Sidekiq::Cron::Job.all.size, 2, "Should have 2 jobs after load"
480
+ end
481
+
482
+ should "return errors on loaded jobs" do
483
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 jobs before load"
484
+ #set something bag to hash
485
+ @jobs_hash['name_of_job']['cron'] = "bad cron"
486
+ out = Sidekiq::Cron::Job.load_from_hash @jobs_hash
487
+ assert_equal out.size, 1, "should have 1 error"
488
+ assert_equal out, {"name_of_job"=>["'cron' -> bad cron: Bad Vixie-style specification bad"]}
489
+ assert_equal Sidekiq::Cron::Job.all.size, 1, "Should have only 1 job after load"
490
+ end
491
+
492
+ should "create new jobs and then destroy them all" do
493
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 jobs before load"
494
+ out = Sidekiq::Cron::Job.load_from_hash @jobs_hash
495
+ assert_equal out.size, 0, "should have no errors"
496
+ assert_equal Sidekiq::Cron::Job.all.size, 2, "Should have 2 jobs after load"
497
+ Sidekiq::Cron::Job.destroy_all!
498
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 jobs after destroy all"
499
+ end
500
+
501
+ end
502
+
503
+ context "from array" do
504
+ setup do
505
+ @jobs_array = [
506
+ {
507
+ 'name' => 'name_of_job',
508
+ 'class' => 'MyClass',
509
+ 'cron' => '1 * * * *',
510
+ 'args' => '(OPTIONAL) [Array or Hash]'
511
+ },
512
+ {
513
+ 'name' => 'Cool Job for Second Class',
514
+ 'class' => 'SecondClass',
515
+ 'cron' => '*/5 * * * *'
516
+ }
517
+ ]
518
+ end
519
+
520
+ should "create new jobs and update old one with same settings" do
521
+ assert_equal Sidekiq::Cron::Job.all.size, 0, "Should have 0 jobs before load"
522
+ out = Sidekiq::Cron::Job.load_from_array @jobs_array
523
+ assert_equal out.size, 0, "should have 0 error"
524
+ assert_equal Sidekiq::Cron::Job.all.size, 2, "Should have 2 jobs after load"
525
+ end
526
+ end
527
+ end
528
+ end
529
+ end