sidekiq-cron 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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