zhong 0.1.5 → 0.1.6
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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +1 -1
- data/.rubocop.yml +6 -3
- data/.travis.yml +1 -1
- data/CHANGELOG.md +10 -0
- data/Gemfile +1 -1
- data/README.md +10 -9
- data/Rakefile +4 -3
- data/lib/zhong/at.rb +40 -41
- data/lib/zhong/every.rb +9 -12
- data/lib/zhong/job.rb +6 -2
- data/lib/zhong/scheduler.rb +31 -12
- data/lib/zhong/util.rb +13 -0
- data/lib/zhong/version.rb +1 -1
- data/lib/zhong/web.rb +13 -26
- data/lib/zhong/web_helpers.rb +13 -15
- data/test/helper.rb +33 -0
- data/test/{at_test.rb → test_at.rb} +27 -1
- data/test/{every_test.rb → test_every.rb} +1 -1
- data/test/test_job.rb +74 -0
- data/test/test_library.rb +23 -0
- data/test/test_scheduler.rb +80 -0
- data/test/test_web.rb +86 -0
- data/zhong.gemspec +4 -0
- metadata +79 -14
- data/test/job_test.rb +0 -60
- data/test/library_test.rb +0 -7
- data/test/scheduler_test.rb +0 -30
- data/test/test_helper.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f1dac5a4ab2bbf39455eb3ae3aa85b8db281f71
|
4
|
+
data.tar.gz: bad4a27f7f28e8d9e09bd89e722c8d14de24135f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 09b25ced5faf77601dcc4056f32441cdf9183a542e4fcdc87ce689806e38e1fc1189613ff9ca11f776c8967e1c4fba9bab83049022860c21ab4893255c64fa4b
|
7
|
+
data.tar.gz: 50d880d5819a8d103d99740a1cacd3a828277015d0def4d486fa777d20f082daa7c1e9d6a56f89469de22f3d9c26245b056165fad4f2339b7fcc45647471a4fd
|
data/.codeclimate.yml
CHANGED
data/.rubocop.yml
CHANGED
@@ -74,7 +74,7 @@ Style/SpaceInsideBrackets:
|
|
74
74
|
Style/AndOr:
|
75
75
|
Enabled: false
|
76
76
|
|
77
|
-
Style/
|
77
|
+
Style/TrailingCommaInLiteral:
|
78
78
|
Enabled: true
|
79
79
|
|
80
80
|
Style/SpaceBeforeComma:
|
@@ -98,7 +98,7 @@ Style/SpaceAfterColon:
|
|
98
98
|
Style/SpaceAfterComma:
|
99
99
|
Enabled: true
|
100
100
|
|
101
|
-
Style/
|
101
|
+
Style/SpaceAroundKeyword:
|
102
102
|
Enabled: true
|
103
103
|
|
104
104
|
Style/SpaceAfterNot:
|
@@ -163,7 +163,7 @@ Style/StringLiterals:
|
|
163
163
|
EnforcedStyle: double_quotes
|
164
164
|
|
165
165
|
Metrics/CyclomaticComplexity:
|
166
|
-
Max:
|
166
|
+
Max: 10
|
167
167
|
|
168
168
|
Metrics/LineLength:
|
169
169
|
Max: 128
|
@@ -214,3 +214,6 @@ Metrics/ParameterLists:
|
|
214
214
|
|
215
215
|
Metrics/PerceivedComplexity:
|
216
216
|
Enabled: false
|
217
|
+
|
218
|
+
Style/Documentation:
|
219
|
+
Enabled: false
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,17 @@
|
|
1
|
+
## 0.1.6
|
2
|
+
|
3
|
+
- Add Zhong.any_running? for monitoring that any Zhong node has checked in rencently
|
4
|
+
- More code cleanup/refactoring.
|
5
|
+
|
1
6
|
## 0.1.5
|
2
7
|
|
3
8
|
- Improve the API.
|
4
9
|
- Add scheduler test.
|
10
|
+
- Add Zhong::Web to see job status, and enable/disable jobs. Activate it with:
|
11
|
+
Rails.application.routes.draw do
|
12
|
+
# ...
|
13
|
+
require "zhong/web"
|
14
|
+
mount Zhong::Web => "/zhong" # or wherever
|
5
15
|
|
6
16
|
## 0.1.4
|
7
17
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -45,20 +45,21 @@ Zhong.schedule do
|
|
45
45
|
true
|
46
46
|
end
|
47
47
|
|
48
|
+
on(:before_run) do |job, time|
|
49
|
+
puts "running #{job}"
|
50
|
+
true # can conditionally run a specific job
|
51
|
+
end
|
52
|
+
|
53
|
+
on(:after_run) do |job, time, ran|
|
54
|
+
puts "#{job} ran?: #{ran}"
|
55
|
+
end
|
56
|
+
|
48
57
|
error_handler do |e, job|
|
49
|
-
puts "
|
58
|
+
puts "dang, #{job} messed up: #{e}"
|
50
59
|
end
|
51
60
|
end
|
52
61
|
```
|
53
62
|
|
54
|
-
## TODO
|
55
|
-
- better logging
|
56
|
-
- error handling
|
57
|
-
- tests
|
58
|
-
- examples
|
59
|
-
- callbacks
|
60
|
-
- generic handler
|
61
|
-
|
62
63
|
## History
|
63
64
|
|
64
65
|
View the [changelog](https://github.com/nickelser/zhong/blob/master/CHANGELOG.md).
|
data/Rakefile
CHANGED
data/lib/zhong/at.rb
CHANGED
@@ -24,7 +24,7 @@ module Zhong
|
|
24
24
|
parse_at(at, grace)
|
25
25
|
end
|
26
26
|
rescue ArgumentError
|
27
|
-
|
27
|
+
raise FailedToParse, at
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.deserialize(at)
|
@@ -37,7 +37,7 @@ module Zhong
|
|
37
37
|
@wday = wday
|
38
38
|
@grace = grace
|
39
39
|
|
40
|
-
|
40
|
+
raise ArgumentError unless valid?
|
41
41
|
end
|
42
42
|
|
43
43
|
def next_at(time = Time.now)
|
@@ -46,11 +46,11 @@ module Zhong
|
|
46
46
|
grace_cutoff = time.change(sec: 0) - @grace
|
47
47
|
|
48
48
|
if at_time < grace_cutoff
|
49
|
-
if @wday.nil?
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
49
|
+
at_time + if @wday.nil?
|
50
|
+
@hour.nil? ? 1.hour : 1.day
|
51
|
+
else
|
52
|
+
1.week
|
53
|
+
end
|
54
54
|
else
|
55
55
|
at_time
|
56
56
|
end
|
@@ -58,10 +58,7 @@ module Zhong
|
|
58
58
|
|
59
59
|
def to_s
|
60
60
|
str = "#{formatted_time(@hour)}:#{formatted_time(@minute)}"
|
61
|
-
|
62
|
-
if @wday
|
63
|
-
str += " on #{WDAYS.invert[@wday].capitalize}"
|
64
|
-
end
|
61
|
+
str += " on #{WDAYS.invert[@wday].capitalize}" if @wday
|
65
62
|
|
66
63
|
str
|
67
64
|
end
|
@@ -74,57 +71,59 @@ module Zhong
|
|
74
71
|
MessagePack.pack(as_json)
|
75
72
|
end
|
76
73
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
if t.nil?
|
81
|
-
"**"
|
74
|
+
def self.parse_serialized(at)
|
75
|
+
if at.is_a?(Array)
|
76
|
+
MultiAt.new(at.map { |a| parse_serialized(a) })
|
82
77
|
else
|
83
|
-
|
78
|
+
new(minute: at["m"], hour: at["h"], wday: at["w"], grace: at["g"])
|
84
79
|
end
|
85
80
|
end
|
86
|
-
|
87
|
-
def ==(o)
|
88
|
-
o.class == self.class && o.state == state
|
89
|
-
end
|
90
|
-
|
91
|
-
def state
|
92
|
-
[@minute, @hour, @wday]
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
81
|
+
private_class_method :parse_serialized
|
96
82
|
|
97
83
|
def self.parse_at(at, grace)
|
98
84
|
case at
|
99
85
|
when /\A([[:alpha:]]+)\s+(.*)\z/
|
100
86
|
wday = WDAYS[$1.downcase]
|
101
87
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
fail FailedToParse, at
|
108
|
-
end
|
88
|
+
raise FailedToParse, at unless wday
|
89
|
+
|
90
|
+
parsed_time = parse_at($2, grace)
|
91
|
+
parsed_time.wday = wday
|
92
|
+
parsed_time
|
109
93
|
when /\A(\d{1,2}):(\d\d)\z/
|
110
94
|
new(minute: $2.to_i, hour: $1.to_i, grace: grace)
|
111
95
|
when /\A\*{1,2}:(\d\d)\z/
|
112
96
|
new(minute: $1.to_i, grace: grace)
|
113
97
|
when /\A(\d{1,2}):\*{1,2}\z/
|
114
98
|
new(hour: $1.to_i, grace: grace)
|
99
|
+
when /\A\*{1,2}:\*{1,2}\z/
|
100
|
+
new(grace: grace)
|
115
101
|
else
|
116
|
-
|
102
|
+
raise FailedToParse, at
|
117
103
|
end
|
118
104
|
end
|
105
|
+
private_class_method :parse_at
|
119
106
|
|
120
|
-
|
121
|
-
|
122
|
-
|
107
|
+
protected
|
108
|
+
|
109
|
+
def formatted_time(t)
|
110
|
+
if t.nil?
|
111
|
+
"**"
|
123
112
|
else
|
124
|
-
|
113
|
+
t.to_s.rjust(2, "0")
|
125
114
|
end
|
126
115
|
end
|
127
116
|
|
117
|
+
def ==(other)
|
118
|
+
other.class == self.class && other.state == state
|
119
|
+
end
|
120
|
+
|
121
|
+
def state
|
122
|
+
[@minute, @hour, @wday]
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
128
127
|
def at_time_hour_minute_adjusted(time)
|
129
128
|
if @minute && @hour
|
130
129
|
time.change(hour: @hour, min: @minute)
|
@@ -155,8 +154,8 @@ module Zhong
|
|
155
154
|
@ats = ats
|
156
155
|
end
|
157
156
|
|
158
|
-
def ==(
|
159
|
-
|
157
|
+
def ==(other)
|
158
|
+
other.class == self.class && @ats == other.ats
|
160
159
|
end
|
161
160
|
|
162
161
|
def next_at(time = Time.now)
|
data/lib/zhong/every.rb
CHANGED
@@ -15,20 +15,17 @@ module Zhong
|
|
15
15
|
def initialize(period)
|
16
16
|
@period = period
|
17
17
|
|
18
|
-
|
18
|
+
raise "`every` must be >= 1 second" unless valid?
|
19
19
|
end
|
20
20
|
|
21
21
|
def to_s
|
22
22
|
EVERY_KEYWORDS.to_a.reverse.each do |friendly, period|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return "#{rem} #{friendly}s"
|
30
|
-
end
|
31
|
-
end
|
23
|
+
next unless @period % period == 0
|
24
|
+
|
25
|
+
rem = @period / period
|
26
|
+
|
27
|
+
return "#{rem} #{friendly}" if rem == 1
|
28
|
+
return "#{rem} #{friendly}s"
|
32
29
|
end
|
33
30
|
|
34
31
|
"#{@period.to_i} second#{@period.to_i == 1 ? '' : 's'}"
|
@@ -49,11 +46,11 @@ module Zhong
|
|
49
46
|
when String, Symbol
|
50
47
|
key = every.downcase.to_sym
|
51
48
|
|
52
|
-
|
49
|
+
raise FailedToParse, every unless EVERY_KEYWORDS.key?(key)
|
53
50
|
|
54
51
|
new(EVERY_KEYWORDS[key])
|
55
52
|
else
|
56
|
-
|
53
|
+
raise FailedToParse, every
|
57
54
|
end
|
58
55
|
end
|
59
56
|
end
|
data/lib/zhong/job.rb
CHANGED
@@ -11,7 +11,7 @@ module Zhong
|
|
11
11
|
@at = config[:at] ? At.parse(config[:at], grace: config.fetch(:grace, 15.minutes)) : nil
|
12
12
|
@every = config[:every] ? Every.parse(config[:every]) : nil
|
13
13
|
|
14
|
-
|
14
|
+
raise "must specific either `at` or `every` for job: #{self}" unless @at || @every
|
15
15
|
|
16
16
|
@block = block
|
17
17
|
|
@@ -39,6 +39,7 @@ module Zhong
|
|
39
39
|
|
40
40
|
locked = false
|
41
41
|
errored = false
|
42
|
+
ran = false
|
42
43
|
|
43
44
|
begin
|
44
45
|
redis_lock.lock do
|
@@ -61,6 +62,7 @@ module Zhong
|
|
61
62
|
if @block
|
62
63
|
begin
|
63
64
|
@block.call
|
65
|
+
ran = true
|
64
66
|
rescue => boom
|
65
67
|
logger.error "#{self} failed: #{boom}"
|
66
68
|
error_handler.call(boom, self) if error_handler
|
@@ -77,6 +79,8 @@ module Zhong
|
|
77
79
|
@running = false
|
78
80
|
|
79
81
|
logger.info "unable to acquire exclusive run lock: #{self}" if !locked && !errored
|
82
|
+
|
83
|
+
ran
|
80
84
|
end
|
81
85
|
|
82
86
|
def running?
|
@@ -97,7 +101,7 @@ module Zhong
|
|
97
101
|
end
|
98
102
|
|
99
103
|
def disabled?
|
100
|
-
|
104
|
+
!@redis.get(disabled_key).nil?
|
101
105
|
end
|
102
106
|
|
103
107
|
def to_s
|
data/lib/zhong/scheduler.rb
CHANGED
@@ -19,10 +19,19 @@ module Zhong
|
|
19
19
|
@tz = @config[:tz]
|
20
20
|
@category = nil
|
21
21
|
@error_handler = nil
|
22
|
+
@running = false
|
23
|
+
end
|
24
|
+
|
25
|
+
def clear
|
26
|
+
raise "unable to clear while running; run Zhong.stop first" if @running
|
27
|
+
|
28
|
+
@jobs = {}
|
29
|
+
@callbacks = {}
|
30
|
+
@category = nil
|
22
31
|
end
|
23
32
|
|
24
33
|
def category(name)
|
25
|
-
|
34
|
+
raise "cannot nest categories: #{name} would be nested in #{@category} (#{caller.first})" if @category
|
26
35
|
|
27
36
|
@category = name.to_s
|
28
37
|
|
@@ -32,7 +41,7 @@ module Zhong
|
|
32
41
|
end
|
33
42
|
|
34
43
|
def every(period, name, opts = {}, &block)
|
35
|
-
|
44
|
+
raise "must specify a period for #{name} (#{caller.first})" unless period
|
36
45
|
|
37
46
|
job = Job.new(name, opts.merge(@config).merge(every: period, category: @category), &block)
|
38
47
|
|
@@ -50,7 +59,7 @@ module Zhong
|
|
50
59
|
end
|
51
60
|
|
52
61
|
def on(event, &block)
|
53
|
-
|
62
|
+
raise "unknown callback #{event}" unless [:before_tick, :after_tick, :before_run, :after_run].include?(event.to_sym)
|
54
63
|
(@callbacks[event.to_sym] ||= []) << block
|
55
64
|
end
|
56
65
|
|
@@ -61,7 +70,11 @@ module Zhong
|
|
61
70
|
|
62
71
|
trap_signals
|
63
72
|
|
73
|
+
raise "already running" if @running
|
74
|
+
|
64
75
|
loop do
|
76
|
+
@running = true
|
77
|
+
|
65
78
|
if fire_callbacks(:before_tick)
|
66
79
|
now = redis_time
|
67
80
|
|
@@ -83,14 +96,26 @@ module Zhong
|
|
83
96
|
break if @stop
|
84
97
|
end
|
85
98
|
|
99
|
+
@running = false
|
100
|
+
|
86
101
|
Thread.new { @logger.info "stopped" }.join
|
87
102
|
end
|
88
103
|
|
89
104
|
def stop
|
90
|
-
Thread.new { @logger.error "stopping" } # thread necessary due to trap context
|
105
|
+
Thread.new { @logger.error "stopping" } if @running # thread necessary due to trap context
|
91
106
|
@stop = true
|
92
107
|
end
|
93
108
|
|
109
|
+
def find_by_name(job_name)
|
110
|
+
@jobs[Digest::SHA256.hexdigest(job_name)]
|
111
|
+
end
|
112
|
+
|
113
|
+
def redis_time
|
114
|
+
s, ms = @redis.time # returns [seconds since epoch, microseconds]
|
115
|
+
now = Time.at(s + ms / (10**6))
|
116
|
+
@tz ? now.in_time_zone(@tz) : now
|
117
|
+
end
|
118
|
+
|
94
119
|
private
|
95
120
|
|
96
121
|
TRAPPED_SIGNALS = %w(QUIT INT TERM).freeze
|
@@ -107,9 +132,9 @@ module Zhong
|
|
107
132
|
def run_job(job, time = redis_time)
|
108
133
|
return unless fire_callbacks(:before_run, job, time)
|
109
134
|
|
110
|
-
job.run(time, error_handler)
|
135
|
+
ran = job.run(time, error_handler)
|
111
136
|
|
112
|
-
fire_callbacks(:after_run, job, time)
|
137
|
+
fire_callbacks(:after_run, job, time, ran)
|
113
138
|
end
|
114
139
|
|
115
140
|
def heartbeat(time)
|
@@ -130,11 +155,5 @@ module Zhong
|
|
130
155
|
GC.start
|
131
156
|
sleep(1.0 - Time.now.subsec + 0.0001)
|
132
157
|
end
|
133
|
-
|
134
|
-
def redis_time
|
135
|
-
s, ms = @redis.time # returns [seconds since epoch, microseconds]
|
136
|
-
now = Time.at(s + ms / (10**6))
|
137
|
-
@tz ? now.in_time_zone(@tz) : now
|
138
|
-
end
|
139
158
|
end
|
140
159
|
end
|
data/lib/zhong/util.rb
ADDED
data/lib/zhong/version.rb
CHANGED
data/lib/zhong/web.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require "tilt/erubis"
|
3
2
|
require "erb"
|
4
3
|
require "sinatra/base"
|
5
4
|
|
@@ -29,21 +28,21 @@ module Zhong
|
|
29
28
|
|
30
29
|
helpers WebHelpers
|
31
30
|
|
32
|
-
get
|
31
|
+
get "/" do
|
33
32
|
index
|
34
33
|
|
35
34
|
erb :index
|
36
35
|
end
|
37
36
|
|
38
|
-
post
|
39
|
-
if params[
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
elsif params[
|
44
|
-
|
45
|
-
|
46
|
-
|
37
|
+
post "/" do
|
38
|
+
if params["disable"]
|
39
|
+
job = Zhong.jobs[params["disable"]]
|
40
|
+
|
41
|
+
job.disable if job
|
42
|
+
elsif params["enable"]
|
43
|
+
job = Zhong.jobs[params["enable"]]
|
44
|
+
|
45
|
+
job.enable if job
|
47
46
|
end
|
48
47
|
|
49
48
|
index
|
@@ -55,30 +54,18 @@ module Zhong
|
|
55
54
|
@jobs = Zhong.jobs.values
|
56
55
|
@last_runs = zhong_mget(@jobs, "last_ran")
|
57
56
|
@disabled = zhong_mget(@jobs, "disabled")
|
58
|
-
@hosts =
|
59
|
-
host, pid = k.split("zhong:heartbeat:", 2)[1].split("#", 2)
|
60
|
-
{host: host, pid: pid, last_seen: Time.at(v.to_i)}
|
61
|
-
end
|
57
|
+
@hosts = Zhong.all_heartbeats
|
62
58
|
end
|
63
59
|
|
64
60
|
def zhong_mget(jobs, key)
|
65
61
|
keys = jobs.map(&:to_s)
|
66
|
-
ret = safe_mget(keys.map { |j| "zhong:#{key}:#{j}" })
|
62
|
+
ret = Zhong::Util.safe_mget(keys.map { |j| "zhong:#{key}:#{j}" })
|
67
63
|
Hash[keys.map { |j| [j, ret["zhong:#{key}:#{j}"]] }]
|
68
64
|
end
|
69
|
-
|
70
|
-
def safe_mget(keys)
|
71
|
-
if keys.length > 0
|
72
|
-
Zhong.redis.mapped_mget(*keys)
|
73
|
-
else
|
74
|
-
{}
|
75
|
-
end
|
76
|
-
end
|
77
65
|
end
|
78
66
|
end
|
79
67
|
|
80
|
-
if defined?(::ActionDispatch::Request::Session) &&
|
81
|
-
!::ActionDispatch::Request::Session.respond_to?(:each)
|
68
|
+
if defined?(::ActionDispatch::Request::Session) && !::ActionDispatch::Request::Session.respond_to?(:each)
|
82
69
|
# mperham/sidekiq#2460
|
83
70
|
# Rack apps can't reuse the Rails session store without
|
84
71
|
# this monkeypatch
|
data/lib/zhong/web_helpers.rb
CHANGED
@@ -7,7 +7,7 @@ module Zhong
|
|
7
7
|
# capture method from sinatra-contrib library.
|
8
8
|
def capture(&block)
|
9
9
|
block.call
|
10
|
-
eval(
|
10
|
+
eval("", block.binding)
|
11
11
|
end
|
12
12
|
|
13
13
|
def root_path
|
@@ -15,12 +15,12 @@ module Zhong
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def current_path
|
18
|
-
@current_path ||= request.path_info.gsub(
|
18
|
+
@current_path ||= request.path_info.gsub(%r(^\/),"")
|
19
19
|
end
|
20
20
|
|
21
21
|
def relative_time(time)
|
22
22
|
if time
|
23
|
-
%
|
23
|
+
%(<time datetime="#{time.getutc.iso8601}">#{time}</time>)
|
24
24
|
else
|
25
25
|
"never"
|
26
26
|
end
|
@@ -41,14 +41,12 @@ module Zhong
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def to_display(arg)
|
44
|
+
arg.inspect
|
45
|
+
rescue
|
44
46
|
begin
|
45
|
-
arg.
|
46
|
-
rescue
|
47
|
-
|
48
|
-
arg.to_s
|
49
|
-
rescue => ex
|
50
|
-
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
51
|
-
end
|
47
|
+
arg.to_s
|
48
|
+
rescue => ex
|
49
|
+
"Cannot display argument: [#{ex.class.name}] #{ex.message}"
|
52
50
|
end
|
53
51
|
end
|
54
52
|
|
@@ -59,8 +57,8 @@ module Zhong
|
|
59
57
|
return number
|
60
58
|
end
|
61
59
|
|
62
|
-
options = {delimiter:
|
63
|
-
parts = number.to_s.to_str.split(
|
60
|
+
options = {delimiter: ",", separator: "."}
|
61
|
+
parts = number.to_s.to_str.split(".")
|
64
62
|
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
65
63
|
parts.join(options[:separator])
|
66
64
|
end
|
@@ -68,13 +66,13 @@ module Zhong
|
|
68
66
|
def h(text)
|
69
67
|
::Rack::Utils.escape_html(text)
|
70
68
|
rescue ArgumentError => e
|
71
|
-
raise unless e.message.eql?(
|
72
|
-
text.encode!(
|
69
|
+
raise unless e.message.eql?("invalid byte sequence in UTF-8")
|
70
|
+
text.encode!("UTF-16", "UTF-8", invalid: :replace, replace: "").encode!("UTF-8", "UTF-16")
|
73
71
|
retry
|
74
72
|
end
|
75
73
|
|
76
74
|
def environment_title_prefix
|
77
|
-
environment = ENV[
|
75
|
+
environment = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
78
76
|
|
79
77
|
"[#{environment.upcase}] " unless environment == "production"
|
80
78
|
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
|
2
|
+
|
3
|
+
if ENV["CODECLIMATE_REPO_TOKEN"]
|
4
|
+
require "codeclimate-test-reporter"
|
5
|
+
::SimpleCov.add_filter "helper"
|
6
|
+
CodeClimate::TestReporter.start
|
7
|
+
end
|
8
|
+
|
9
|
+
require "zhong"
|
10
|
+
require "minitest/autorun"
|
11
|
+
require "rack/test"
|
12
|
+
|
13
|
+
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = "test"
|
14
|
+
|
15
|
+
def assert_contains(expected_substring, string, *args)
|
16
|
+
assert string.include?(expected_substring), *args
|
17
|
+
end
|
18
|
+
|
19
|
+
Zhong.logger = begin
|
20
|
+
l = Logger.new(STDOUT)
|
21
|
+
l.level = Logger::ERROR
|
22
|
+
l
|
23
|
+
end
|
24
|
+
|
25
|
+
Zhong.redis = Redis.new(url: ENV["REDIS_URL"] || "redis://localhost/13")
|
26
|
+
|
27
|
+
def test_default_config
|
28
|
+
@default_config ||= {
|
29
|
+
redis: Zhong.redis,
|
30
|
+
logger: Zhong.logger,
|
31
|
+
long_running_timeout: 10.seconds
|
32
|
+
}
|
33
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "helper"
|
2
2
|
|
3
3
|
# Many At tests lifted from Clockwork (thanks Clockwork!)
|
4
4
|
class TestAt < Minitest::Test
|
@@ -139,6 +139,32 @@ class TestAt < Minitest::Test
|
|
139
139
|
assert_equal time_in_day(8, 20, 3), at.next_at(time_in_day(12, 31, 2))
|
140
140
|
end
|
141
141
|
|
142
|
+
def test_to_s
|
143
|
+
at = Zhong::At.parse("thr 12:59")
|
144
|
+
|
145
|
+
assert_equal "12:59 on Thr", at.to_s
|
146
|
+
|
147
|
+
at = Zhong::At.parse(["8:20", "tues 12:30"])
|
148
|
+
|
149
|
+
assert_equal "08:20, 12:30 on Tues", at.to_s
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_as_json
|
153
|
+
at = Zhong::At.parse("tues 23:01")
|
154
|
+
|
155
|
+
assert_equal({m: 1, h: 23, w: 2, g: 0.seconds}, at.as_json)
|
156
|
+
|
157
|
+
at = Zhong::At.parse(["8:**", "sun 12:30"])
|
158
|
+
|
159
|
+
assert_equal([{m: nil, h: 8, w: nil, g: 0.seconds}, {m: 30, h: 12, w: 0, g: 0.seconds}], at.as_json)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_serialize
|
163
|
+
at = Zhong::At.parse(["8:20", "tues 12:30"])
|
164
|
+
|
165
|
+
assert_equal Zhong::At.deserialize(at.serialize), at
|
166
|
+
end
|
167
|
+
|
142
168
|
def test_invalid_time_32
|
143
169
|
assert_raises Zhong::At::FailedToParse do
|
144
170
|
Zhong::At.parse("32:00")
|
data/test/test_job.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestJob < Minitest::Test
|
4
|
+
def test_initialize
|
5
|
+
job = Zhong::Job.new("test_initialize", {at: "12:00"}.merge(test_default_config))
|
6
|
+
|
7
|
+
assert job
|
8
|
+
assert !job.running?
|
9
|
+
assert_equal "test_initialize", job.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_run
|
13
|
+
sleep 1
|
14
|
+
|
15
|
+
job = Zhong::Job.new("test_should_run", {every: 1.second}.merge(test_default_config))
|
16
|
+
|
17
|
+
assert_equal true, job.run?
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_run
|
21
|
+
success_counter = Queue.new
|
22
|
+
job = Zhong::Job.new("test_run", {every: 1.second}.merge(test_default_config)) { success_counter << 1 }
|
23
|
+
now = Time.now
|
24
|
+
|
25
|
+
assert_equal 0, success_counter.size
|
26
|
+
assert_equal true, job.run?(now)
|
27
|
+
job.run(now)
|
28
|
+
assert_equal false, job.run?(now)
|
29
|
+
assert_equal 1, success_counter.size
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_run_at
|
33
|
+
success_counter = Queue.new
|
34
|
+
job = Zhong::Job.new("test_run_at", {every: 1.second, at: ["**:**"]}.merge(test_default_config)) { success_counter << 1 }
|
35
|
+
now = Time.now
|
36
|
+
|
37
|
+
assert_equal 0, success_counter.size
|
38
|
+
assert_equal true, job.run?(now)
|
39
|
+
job.run(now)
|
40
|
+
assert_equal false, job.run?(now)
|
41
|
+
assert_equal 1, success_counter.size
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_run_at_change
|
45
|
+
success_counter = Queue.new
|
46
|
+
job = Zhong::Job.new("test_run_at_change", {every: 1.second, at: ["**:**"]}.merge(test_default_config)) { success_counter << 1 }
|
47
|
+
now = Time.now
|
48
|
+
|
49
|
+
assert_equal 0, success_counter.size
|
50
|
+
assert_equal true, job.run?(now)
|
51
|
+
job.run(now)
|
52
|
+
assert_equal false, job.run?(now)
|
53
|
+
assert_equal 1, success_counter.size
|
54
|
+
|
55
|
+
job = Zhong::Job.new("test_run_at_change", {every: 1.second, at: ["**:**", "**:**"]}.merge(test_default_config)) { success_counter << 1 }
|
56
|
+
assert_equal true, job.run?(now)
|
57
|
+
job.run(now)
|
58
|
+
assert_equal false, job.run?(now)
|
59
|
+
assert_equal 2, success_counter.size
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_disable
|
63
|
+
success_counter = Queue.new
|
64
|
+
job = Zhong::Job.new("test_disable", {every: 1.second}.merge(test_default_config)) { success_counter << 1 }
|
65
|
+
now = Time.now
|
66
|
+
|
67
|
+
job.disable
|
68
|
+
|
69
|
+
assert_equal true, job.run?(now)
|
70
|
+
job.run(now)
|
71
|
+
assert_equal true, job.run?(now)
|
72
|
+
assert_equal 0, success_counter.size
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestLibrary < Minitest::Test
|
4
|
+
def test_that_it_has_a_version_number
|
5
|
+
refute_nil ::Zhong::VERSION
|
6
|
+
end
|
7
|
+
|
8
|
+
def teardown
|
9
|
+
Zhong.stop
|
10
|
+
sleep 1
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_heartbeats
|
14
|
+
Zhong.schedule { nil }
|
15
|
+
t = Thread.new { Zhong.start }
|
16
|
+
sleep(1)
|
17
|
+
assert_equal true, Zhong.any_running?
|
18
|
+
assert_in_delta Zhong.redis_time.to_f, Time.now.to_f, 0.1
|
19
|
+
assert_in_delta Zhong.redis_time.to_f, Zhong.latest_heartbeat.to_f, 1
|
20
|
+
Zhong.stop
|
21
|
+
t.join
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
|
3
|
+
class TestScheduler < Minitest::Test
|
4
|
+
def setup
|
5
|
+
Zhong.clear
|
6
|
+
end
|
7
|
+
|
8
|
+
def test_scheduler
|
9
|
+
test_one_counter = 0
|
10
|
+
test_two_counter = 0
|
11
|
+
|
12
|
+
Zhong.schedule do
|
13
|
+
every(10.seconds, "test_one") { test_one_counter += 1 }
|
14
|
+
every(3.seconds, "test_two") { test_two_counter += 1 }
|
15
|
+
end
|
16
|
+
|
17
|
+
t = Thread.new { Zhong.start }
|
18
|
+
sleep(7)
|
19
|
+
Zhong.stop
|
20
|
+
t.join
|
21
|
+
|
22
|
+
assert_equal 1, test_one_counter
|
23
|
+
assert_equal 3, test_two_counter
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_scheduler_categories
|
27
|
+
Zhong.schedule do
|
28
|
+
category "cat1" do
|
29
|
+
every(10.seconds, "cat_test_one") { nil }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
assert_equal 1, Zhong.jobs.size
|
34
|
+
assert_equal "cat1.cat_test_one", Zhong.jobs.values.first.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_scheduler_nested_category
|
38
|
+
assert_raises RuntimeError do
|
39
|
+
Zhong.schedule do
|
40
|
+
category "cat1" do
|
41
|
+
category "cat2"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_scheduler_callbacks
|
48
|
+
test_before_tick = 0
|
49
|
+
test_after_tick = 0
|
50
|
+
test_errors = 0
|
51
|
+
test_before_run = 0
|
52
|
+
test_after_run = 0
|
53
|
+
|
54
|
+
Zhong.schedule do
|
55
|
+
on(:before_tick) { test_before_tick += 1; true }
|
56
|
+
on(:after_tick) { test_after_tick += 1 }
|
57
|
+
on(:before_run) { test_before_run += 1; true }
|
58
|
+
on(:after_run) { |_, _, ran| test_after_run += 1 if ran }
|
59
|
+
error_handler { test_errors += 1 }
|
60
|
+
|
61
|
+
every(1.second, "test_every_second") { nil }
|
62
|
+
every(1.second, "break_every_second") { raise "boom" }
|
63
|
+
end
|
64
|
+
|
65
|
+
t = Thread.new { Zhong.start }
|
66
|
+
sleep(3)
|
67
|
+
Zhong.stop
|
68
|
+
t.join
|
69
|
+
|
70
|
+
assert_operator 2, :<=, test_before_tick
|
71
|
+
assert_operator 4, :>=, test_before_tick
|
72
|
+
assert_operator 2, :<=, test_after_tick
|
73
|
+
assert_operator 4, :>=, test_after_tick
|
74
|
+
assert_operator 6, :<=, test_before_run
|
75
|
+
assert_operator 8, :>=, test_before_run
|
76
|
+
assert_operator 2, :<=, test_after_run
|
77
|
+
assert_operator 4, :>=, test_after_run
|
78
|
+
assert_operator 2, :<=, test_errors
|
79
|
+
end
|
80
|
+
end
|
data/test/test_web.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require_relative "helper"
|
2
|
+
require "zhong/web"
|
3
|
+
require "tilt/erubis"
|
4
|
+
|
5
|
+
class TestWeb < Minitest::Test
|
6
|
+
include Rack::Test::Methods
|
7
|
+
|
8
|
+
def app
|
9
|
+
Zhong::Web
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup
|
13
|
+
Zhong.clear
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_index
|
17
|
+
get "/"
|
18
|
+
assert last_response.ok?
|
19
|
+
assert_contains "<title>[TEST] Zhong</title>", last_response.body
|
20
|
+
assert_contains Zhong::VERSION, last_response.body
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_index_job
|
24
|
+
Zhong.schedule do
|
25
|
+
every(10.minutes, "test_web_job") { nil }
|
26
|
+
end
|
27
|
+
|
28
|
+
get "/"
|
29
|
+
assert last_response.ok?
|
30
|
+
assert_contains "test_web_job", last_response.body
|
31
|
+
assert_contains "every 10 minutes", last_response.body
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_disable_job
|
35
|
+
Zhong.schedule do
|
36
|
+
every(30.seconds, "test_disable_web_job") { nil }
|
37
|
+
end
|
38
|
+
|
39
|
+
job = Zhong.scheduler.find_by_name("test_disable_web_job")
|
40
|
+
|
41
|
+
job.enable
|
42
|
+
|
43
|
+
assert_equal false, job.disabled?
|
44
|
+
|
45
|
+
post "/", "disable" => job.id
|
46
|
+
assert last_response.ok?
|
47
|
+
assert_contains "test_disable_web_job", last_response.body
|
48
|
+
assert_contains "every 30 seconds", last_response.body
|
49
|
+
assert_contains 'name="enable"', last_response.body
|
50
|
+
assert_equal true, job.disabled?
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_enable_job
|
54
|
+
Zhong.schedule do
|
55
|
+
every(12.hours, "test_enable_web_job") { nil }
|
56
|
+
end
|
57
|
+
|
58
|
+
job = Zhong.scheduler.find_by_name("test_enable_web_job")
|
59
|
+
|
60
|
+
job.disable
|
61
|
+
|
62
|
+
assert_equal true, job.disabled?
|
63
|
+
|
64
|
+
post "/", "enable" => job.id
|
65
|
+
assert last_response.ok?
|
66
|
+
assert_contains "test_enable_web_job", last_response.body
|
67
|
+
assert_contains "every 12 hours", last_response.body
|
68
|
+
assert_contains 'name="disable"', last_response.body
|
69
|
+
assert_equal false, job.disabled?
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_heartbeat
|
73
|
+
hostname = `hostname`.strip
|
74
|
+
pid = Process.pid
|
75
|
+
|
76
|
+
t = Thread.new { Zhong.start }
|
77
|
+
sleep(1)
|
78
|
+
Zhong.stop
|
79
|
+
t.join
|
80
|
+
|
81
|
+
get "/"
|
82
|
+
assert last_response.ok?
|
83
|
+
assert_contains hostname, last_response.body
|
84
|
+
assert_contains "PID #{pid}", last_response.body
|
85
|
+
end
|
86
|
+
end
|
data/zhong.gemspec
CHANGED
@@ -32,4 +32,8 @@ Gem::Specification.new do |spec|
|
|
32
32
|
spec.add_development_dependency "rubocop", "~> 0.30.0"
|
33
33
|
spec.add_development_dependency "minitest", "~> 5.5.0"
|
34
34
|
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4.7"
|
35
|
+
spec.add_development_dependency "sinatra", "~> 1.4", ">= 1.4.6"
|
36
|
+
spec.add_development_dependency "rack-test", "~> 0.6"
|
37
|
+
spec.add_development_dependency "tilt"
|
38
|
+
spec.add_development_dependency "erubis"
|
35
39
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zhong
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Elser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-07-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: suo
|
@@ -136,6 +136,68 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.4.7
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sinatra
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '1.4'
|
146
|
+
- - ">="
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: 1.4.6
|
149
|
+
type: :development
|
150
|
+
prerelease: false
|
151
|
+
version_requirements: !ruby/object:Gem::Requirement
|
152
|
+
requirements:
|
153
|
+
- - "~>"
|
154
|
+
- !ruby/object:Gem::Version
|
155
|
+
version: '1.4'
|
156
|
+
- - ">="
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 1.4.6
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: rack-test
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0.6'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0.6'
|
173
|
+
- !ruby/object:Gem::Dependency
|
174
|
+
name: tilt
|
175
|
+
requirement: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - ">="
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '0'
|
180
|
+
type: :development
|
181
|
+
prerelease: false
|
182
|
+
version_requirements: !ruby/object:Gem::Requirement
|
183
|
+
requirements:
|
184
|
+
- - ">="
|
185
|
+
- !ruby/object:Gem::Version
|
186
|
+
version: '0'
|
187
|
+
- !ruby/object:Gem::Dependency
|
188
|
+
name: erubis
|
189
|
+
requirement: !ruby/object:Gem::Requirement
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
type: :development
|
195
|
+
prerelease: false
|
196
|
+
version_requirements: !ruby/object:Gem::Requirement
|
197
|
+
requirements:
|
198
|
+
- - ">="
|
199
|
+
- !ruby/object:Gem::Version
|
200
|
+
version: '0'
|
139
201
|
description: Reliable, distributed cron.
|
140
202
|
email:
|
141
203
|
- nick.elser@gmail.com
|
@@ -165,15 +227,17 @@ files:
|
|
165
227
|
- lib/zhong/every.rb
|
166
228
|
- lib/zhong/job.rb
|
167
229
|
- lib/zhong/scheduler.rb
|
230
|
+
- lib/zhong/util.rb
|
168
231
|
- lib/zhong/version.rb
|
169
232
|
- lib/zhong/web.rb
|
170
233
|
- lib/zhong/web_helpers.rb
|
171
|
-
- test/
|
172
|
-
- test/
|
173
|
-
- test/
|
174
|
-
- test/
|
175
|
-
- test/
|
176
|
-
- test/
|
234
|
+
- test/helper.rb
|
235
|
+
- test/test_at.rb
|
236
|
+
- test/test_every.rb
|
237
|
+
- test/test_job.rb
|
238
|
+
- test/test_library.rb
|
239
|
+
- test/test_scheduler.rb
|
240
|
+
- test/test_web.rb
|
177
241
|
- web/assets/javascript/application.js
|
178
242
|
- web/assets/javascript/vendor.min.js
|
179
243
|
- web/views/index.erb
|
@@ -203,10 +267,11 @@ signing_key:
|
|
203
267
|
specification_version: 4
|
204
268
|
summary: Reliable, distributed cron.
|
205
269
|
test_files:
|
206
|
-
- test/
|
207
|
-
- test/
|
208
|
-
- test/
|
209
|
-
- test/
|
210
|
-
- test/
|
211
|
-
- test/
|
270
|
+
- test/helper.rb
|
271
|
+
- test/test_at.rb
|
272
|
+
- test/test_every.rb
|
273
|
+
- test/test_job.rb
|
274
|
+
- test/test_library.rb
|
275
|
+
- test/test_scheduler.rb
|
276
|
+
- test/test_web.rb
|
212
277
|
has_rdoc:
|
data/test/job_test.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class TestJob < Minitest::Test
|
4
|
-
def default_config
|
5
|
-
@default_config ||= {
|
6
|
-
redis: Redis.new,
|
7
|
-
logger: logger,
|
8
|
-
long_running_timeout: 5.minutes
|
9
|
-
}
|
10
|
-
end
|
11
|
-
|
12
|
-
def logger
|
13
|
-
@logger ||= begin
|
14
|
-
l = Logger.new(STDOUT)
|
15
|
-
l.level = Logger::UNKNOWN
|
16
|
-
l
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def test_initialize
|
21
|
-
job = Zhong::Job.new("test_initialize", {at: "12:00"}.merge(default_config))
|
22
|
-
|
23
|
-
assert job
|
24
|
-
assert !job.running?
|
25
|
-
assert_equal "test_initialize", job.to_s
|
26
|
-
end
|
27
|
-
|
28
|
-
def test_should_run
|
29
|
-
sleep 1
|
30
|
-
|
31
|
-
job = Zhong::Job.new("test_should_run", {every: 1.second}.merge(default_config))
|
32
|
-
|
33
|
-
assert_equal true, job.run?
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_run
|
37
|
-
success_counter = Queue.new
|
38
|
-
job = Zhong::Job.new("test_run", {every: 1.second}.merge(default_config)) { success_counter << 1 }
|
39
|
-
now = Time.now
|
40
|
-
|
41
|
-
assert_equal 0, success_counter.size
|
42
|
-
assert_equal true, job.run?(now)
|
43
|
-
job.run(now)
|
44
|
-
assert_equal false, job.run?(now)
|
45
|
-
assert_equal 1, success_counter.size
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_disable
|
49
|
-
success_counter = Queue.new
|
50
|
-
job = Zhong::Job.new("test_disable", {every: 1.second}.merge(default_config)) { success_counter << 1 }
|
51
|
-
now = Time.now
|
52
|
-
|
53
|
-
job.disable
|
54
|
-
|
55
|
-
assert_equal true, job.run?(now)
|
56
|
-
job.run(now)
|
57
|
-
assert_equal true, job.run?(now)
|
58
|
-
assert_equal 0, success_counter.size
|
59
|
-
end
|
60
|
-
end
|
data/test/library_test.rb
DELETED
data/test/scheduler_test.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
|
3
|
-
class TestScheduler < Minitest::Test
|
4
|
-
def logger
|
5
|
-
@logger ||= begin
|
6
|
-
l = Logger.new(STDOUT)
|
7
|
-
l.level = Logger::UNKNOWN
|
8
|
-
l
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_scheduler
|
13
|
-
test_one_counter = 0
|
14
|
-
test_two_counter = 0
|
15
|
-
|
16
|
-
Zhong.logger = logger
|
17
|
-
|
18
|
-
Zhong.schedule do
|
19
|
-
every(10.seconds, "test_one") { test_one_counter += 1 }
|
20
|
-
every(3.seconds, "test_two") { test_two_counter += 1 }
|
21
|
-
end
|
22
|
-
|
23
|
-
t = Thread.new { Zhong.start }
|
24
|
-
sleep(7)
|
25
|
-
Zhong.stop
|
26
|
-
t.join
|
27
|
-
assert_equal 1, test_one_counter
|
28
|
-
assert_equal 3, test_two_counter
|
29
|
-
end
|
30
|
-
end
|
data/test/test_helper.rb
DELETED