continuity 0.0.1

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,191 @@
1
+ require 'helper'
2
+ require 'minitest/autorun'
3
+ require 'continuity'
4
+
5
+ include Continuity
6
+
7
+ describe CronEntry do
8
+ describe "0 * * * * * (every minute)" do
9
+ before do
10
+ @ce_short = CronEntry.new("* * * * *")
11
+ @ce = CronEntry.new("0 * * * * *")
12
+ end
13
+
14
+ it "should run at 2010-12-20 00:00:00" do
15
+ @ce_short.at?(Time.parse("2010-12-20 00:00:00")).must_equal true
16
+ @ce.at?(Time.parse("2010-12-20 00:00:00")).must_equal true
17
+ end
18
+
19
+ it "should not run at 2010-12-20 00:00:01" do
20
+ @ce_short.at?(Time.parse("2010-12-20 00:00:01")).must_equal false
21
+ @ce.at?(Time.parse("2010-12-20 00:00:01")).must_equal false
22
+ end
23
+
24
+ it "should run 60 times in a one hour period" do
25
+ count = 0
26
+ start = Time.parse("2010-12-20 00:00:00").to_i
27
+ start.upto(start + 3599) do |t|
28
+ count += 1 if @ce_short.at?(Time.at(t))
29
+ count += 1 if @ce.at?(Time.at(t))
30
+ end
31
+ count.must_equal 120
32
+ end
33
+ end
34
+
35
+ describe "0 1 * * * * (every hour)" do
36
+ before do
37
+ @ce = CronEntry.new("0 1 * * * *")
38
+ end
39
+
40
+ it "should run at 2010-12-20 01:01:00" do
41
+ @ce.at?(Time.parse("2010-12-20 01:01:00")).must_equal true
42
+ end
43
+
44
+ it "should not run at 2010-12-20 00:01:01" do
45
+ @ce.at?(Time.parse("2010-12-20 00:01:01")).must_equal false
46
+ end
47
+
48
+ it "should run 24 times in a one day period" do
49
+ count = 0
50
+ start = Time.parse("2010-12-20 00:01:00").to_i
51
+ start.upto(start + 86399) do |t|
52
+ count += 1 if @ce.at?(Time.at(t))
53
+ end
54
+ count.must_equal 24
55
+ end
56
+ end
57
+
58
+ describe "0 0 0 1 * * (first of the month)" do
59
+ before do
60
+ @ce = CronEntry.new("0 0 0 1 * *")
61
+ end
62
+
63
+ it "should run at 2010-12-01 00:00:00" do
64
+ @ce.at?(Time.parse("2010-12-01 00:00:00")).must_equal true
65
+ end
66
+
67
+ it "should run at 2010-08-01 00:00:00" do
68
+ @ce.at?(Time.parse("2010-08-01 00:00:00")).must_equal true
69
+ end
70
+
71
+ it "should not run at 2010-12-02 00:00:00" do
72
+ @ce.at?(Time.parse("2010-12-02 00:00:00")).must_equal false
73
+ end
74
+
75
+ it "should not run at 2010-12-01 01:00:00" do
76
+ @ce.at?(Time.parse("2010-12-01 01:00:00")).must_equal false
77
+ end
78
+
79
+ it "should run 12 times in a year" do
80
+ count = 0
81
+ start = Time.parse("2010-01-01 00:00:00").to_i
82
+ year_end = Time.parse("2010-12-31 23:59:59").to_i
83
+ start.step(year_end, 3600) do |t|
84
+ if @ce.at?(Time.at(t))
85
+ count += 1
86
+ end
87
+ end
88
+ count.must_equal 12
89
+ end
90
+ end
91
+
92
+ describe "0 0 0 1 1,4,7,10 * (quarterly months)" do
93
+ before do
94
+ @ce = CronEntry.new("0 0 0 1 1,4,7,10 *")
95
+ end
96
+
97
+ it "should run at 2010-04-01 00:00:00" do
98
+ @ce.at?(Time.parse("2010-04-01 00:00:00")).must_equal true
99
+ end
100
+
101
+ it "should not run at 2010-03-01 00:00:00" do
102
+ @ce.at?(Time.parse("2010-03-01 00:00:00")).must_equal false
103
+ end
104
+
105
+ it "should run 4 times in a year" do
106
+ count = 0
107
+ start = Time.parse("2010-01-01 00:00:00").to_i
108
+ year_end = Time.parse("2010-12-31 23:59:59").to_i
109
+ start.step(year_end, 3600) do |t|
110
+ if @ce.at?(Time.at(t))
111
+ count += 1
112
+ end
113
+ end
114
+ count.must_equal 4
115
+ end
116
+ end
117
+
118
+ describe "0 0 7 * * 0 (sunday @ 7am)" do
119
+ before do
120
+ @ce = CronEntry.new("0 0 7 * * 0")
121
+ end
122
+
123
+ it "should run at 2010-12-19 07:00:00" do
124
+ @ce.at?(Time.parse("2010-12-19 07:00:00")).must_equal true
125
+ end
126
+
127
+ it "should run at 2010-12-26 07:00:00" do
128
+ @ce.at?(Time.parse("2010-12-26 07:00:00")).must_equal true
129
+ end
130
+
131
+ it "should not run at 2010-12-27 07:00:00" do
132
+ @ce.at?(Time.parse("2010-12-27 07:00:00")).must_equal false
133
+ end
134
+
135
+ it "should not run at 2010-12-26 06:00:00" do
136
+ @ce.at?(Time.parse("2010-12-26 06:00:00")).must_equal false
137
+ end
138
+ end
139
+
140
+ describe "ranges w/intervals" do
141
+ before do
142
+ # 10 * 20 * 3 = 600 times in a day
143
+ @ce = CronEntry.new("0-9/2,20-39/4 40-59/1 2,4,8 * * *")
144
+ end
145
+
146
+ it "should run at 2010-12-20 04:40:06" do
147
+ @ce.at?(Time.parse("2010-12-20 04:40:06")).must_equal true
148
+ end
149
+
150
+ it "should run at 2010-12-20 02:50:24" do
151
+ @ce.at?(Time.parse("2010-12-20 02:50:24")).must_equal true
152
+ end
153
+
154
+ it "should not run at 2010-12-20 03:50:22" do
155
+ @ce.at?(Time.parse("2010-12-20 03:50:22")).must_equal false
156
+ end
157
+
158
+ it "should run 600 times in a day" do
159
+ count = 0
160
+ start = Time.parse("2010-12-20 02:40:09").to_i
161
+ start.upto(start + 86399) do |t|
162
+ if @ce.at?(Time.at(t))
163
+ count += 1
164
+ end
165
+ end
166
+ count.must_equal 600
167
+ end
168
+ end
169
+
170
+ describe "invalid intervals" do
171
+ it "should raise CronFormatError on '1 2 3'" do
172
+ lambda { CronEntry.new("1 2 3") }.must_raise CronFormatError
173
+ end
174
+
175
+ it "should raise CronFormatError on '1 2 3 4 5 6 7'" do
176
+ lambda { CronEntry.new("1 2 3 4 5 6 7") }.must_raise CronFormatError
177
+ end
178
+
179
+ it "should raise CronFormatError on 'im not a cron task'" do
180
+ lambda { CronEntry.new("im not a cron task") }.must_raise CronFormatError
181
+ end
182
+
183
+ it "should raise CronFormatError on 'SrslyFake'" do
184
+ lambda { CronEntry.new("SrslyFake") }.must_raise CronFormatError
185
+ end
186
+
187
+ it "should raise CronFormatError on '0 0 0 0 0 0'" do
188
+ lambda { CronEntry.new("0 0 0 0 0 0") }.must_raise CronFormatError
189
+ end
190
+ end
191
+ end
@@ -0,0 +1,109 @@
1
+ require 'helper'
2
+ require 'minitest/autorun'
3
+ require 'continuity'
4
+
5
+ include Continuity
6
+
7
+ describe PeriodicEntry do
8
+ describe "10s" do
9
+ before do
10
+ @pe = PeriodicEntry.new("10s")
11
+ end
12
+
13
+ it "should trigger at Time.at(10)" do
14
+ assert @pe.at?(Time.at(10))
15
+ end
16
+
17
+ it "should trigger 6 times in a minute" do
18
+ times = 0
19
+
20
+ time = Time.parse("2010-12-21 00:01:00").to_i
21
+ time.upto(time + 59) do |n|
22
+ times += 1 if @pe.at?(Time.at(n))
23
+ end
24
+
25
+ times.must_equal 6
26
+ end
27
+ end
28
+
29
+ describe "1m" do
30
+ before do
31
+ @pe = PeriodicEntry.new("1m")
32
+ end
33
+
34
+ it "should trigger on the minute" do
35
+ time = Time.parse("2010-12-21 00:01:00").to_i
36
+
37
+ assert @pe.at?(time)
38
+ end
39
+
40
+ it "should trigger 60 times in a hour" do
41
+ times = 0
42
+
43
+ time = Time.parse("2010-12-21 00:00:00").to_i
44
+ time.upto(time + 3599) do |n|
45
+ times += 1 if @pe.at?(Time.at(n))
46
+ end
47
+
48
+ times.must_equal 60
49
+ end
50
+ end
51
+
52
+ describe "2h" do
53
+ before do
54
+ @pe = PeriodicEntry.new("2h")
55
+ end
56
+
57
+ it "should trigger at 2am" do
58
+ time = Time.parse("2010-12-21 02:00:00").to_i
59
+
60
+ assert @pe.at?(time)
61
+ end
62
+
63
+ it "should trigger 12 times in a 24hour period" do
64
+ times = 0
65
+
66
+ time = Time.parse("2010-12-21 00:00:00").to_i
67
+ time.upto(time + 86399) do |n|
68
+ times += 1 if @pe.at?(Time.at(n))
69
+ end
70
+
71
+ times.must_equal 12
72
+ end
73
+ end
74
+
75
+ describe "2d" do
76
+ before do
77
+ @pe = PeriodicEntry.new("2d")
78
+ end
79
+
80
+ it "should trigger 5 times in a 10day period" do
81
+ times = 0
82
+
83
+ time = Time.parse("2010-12-21 00:00:00").to_i
84
+ time.upto(time + (86400 * 10) - 1) do |n|
85
+ times += 1 if @pe.at?(Time.at(n))
86
+ end
87
+
88
+ times.must_equal 5
89
+ end
90
+ end
91
+
92
+ describe "1w" do
93
+ before do
94
+ @pe = PeriodicEntry.new("1w")
95
+ end
96
+
97
+ it "should trigger 4 times in 28 days" do
98
+ times = 0
99
+
100
+ time = Time.parse("2010-12-01 00:00:00").to_i
101
+ time_end = Time.parse("2010-12-27 23:59:59").to_i
102
+ time.upto(time_end) do |n|
103
+ times += 1 if @pe.at?(Time.at(n))
104
+ end
105
+
106
+ times.must_equal 4
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,62 @@
1
+ require 'helper'
2
+ require 'minitest/autorun'
3
+ require 'continuity'
4
+
5
+ include Continuity
6
+
7
+ def build_scheduler
8
+ redis = Redis.new(:port => 16379)
9
+ scheduler = Continuity::Scheduler.new_using_redis(redis)
10
+ scheduler.cron("*/10 * * * * *") do
11
+ end
12
+
13
+ scheduler.every("1m") do
14
+ end
15
+
16
+ scheduler
17
+ end
18
+
19
+ WORKER_COUNT = 100
20
+ MUTEX = Mutex.new
21
+ TEST_LENGTH = 60
22
+
23
+ describe "simulation" do
24
+ before do
25
+ redis = Redis.new(:port => 16379)
26
+ redis.flushall
27
+ end
28
+
29
+ it "should schedule a continuous range" do
30
+ @workers = []
31
+ last_scheduled = nil
32
+
33
+ WORKER_COUNT.times do
34
+
35
+ @workers << Thread.new do
36
+ s = build_scheduler
37
+
38
+ loop do
39
+ sleep rand(5)
40
+ range = s.maybe_schedule
41
+
42
+ if range
43
+ MUTEX.synchronize do
44
+ if last_scheduled.nil?
45
+ last_scheduled = range.last
46
+ else
47
+ assert_equal (last_scheduled + 1), range.first
48
+ last_scheduled = range.last
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ sleep TEST_LENGTH
59
+ @workers.each { |w| w.terminate }
60
+ assert last_scheduled > Time.now.to_i - 20
61
+ end
62
+ end
@@ -0,0 +1,146 @@
1
+ require 'helper'
2
+ require 'minitest/autorun'
3
+ require 'continuity'
4
+
5
+ describe Continuity::RedisBackend do
6
+ before do
7
+ @rb = Continuity::RedisBackend.new(redis_clean, 10, 30)
8
+ end
9
+
10
+ describe "bootstrapping" do
11
+ it "should set current time as the last scheduled at time" do
12
+ now = Time.now.to_i
13
+ @rb.lock_for_scheduling(now) {}
14
+ last_scheduled_at = @rb.lock_for_scheduling(now+1) {}
15
+ last_scheduled_at.must_equal now
16
+ end
17
+
18
+ it "should yield" do
19
+ yielded = false
20
+
21
+ now = Time.now.to_i
22
+ @rb.lock_for_scheduling(now) { yielded = true }
23
+
24
+ yielded.must_equal true
25
+ end
26
+ end
27
+
28
+ describe "trying to lock before scheduling period is over" do
29
+ before do
30
+ now = Time.now.to_i
31
+ @rb.lock_for_scheduling(now) {}
32
+ end
33
+
34
+ it "should not yield" do
35
+ now = Time.now.to_i
36
+ @rb.lock_for_scheduling(now) {}
37
+
38
+ yielded = false
39
+
40
+ @rb.lock_for_scheduling(now+5) { yielded = true }
41
+
42
+ yielded.must_equal false
43
+ end
44
+ end
45
+
46
+ describe "trying to lock while another client holds to lock" do
47
+ it "should not yield" do
48
+ first_yields = false
49
+ second_yields = false
50
+ now = Time.now.to_i
51
+ @rb.lock_for_scheduling(now) {}
52
+
53
+ @rb.lock_for_scheduling(now+30) do
54
+ first_yields = true
55
+ 20.times do
56
+ @rb.lock_for_scheduling(now+35) do
57
+ second_yields = true
58
+ end
59
+ end
60
+ end
61
+
62
+ first_yields.must_equal true
63
+ second_yields.must_equal false
64
+ end
65
+ end
66
+
67
+ describe "throwing exception in the block given to lock" do
68
+ it "should release lock" do
69
+ now = Time.now.to_i
70
+ @rb.lock_for_scheduling(now) {}
71
+
72
+ begin
73
+ @rb.lock_for_scheduling(now+30) do
74
+ raise StandardError
75
+ end
76
+ rescue
77
+ end
78
+
79
+ acquired_lock = false
80
+ @rb.lock_for_scheduling(now+30) do
81
+ acquired_lock = true
82
+ end
83
+
84
+ acquired_lock.must_equal true
85
+ end
86
+ end
87
+
88
+ describe "expired lock" do
89
+ it "should be acquireable" do
90
+ now = Time.now.to_i
91
+ @rb.lock_for_scheduling(now) {}
92
+
93
+ acquired_lock_early = false
94
+ acquired_lock = false
95
+
96
+ @rb.lock_for_scheduling(now+30) do
97
+ @rb.lock_for_scheduling(now+22) do
98
+ acquired_lock_early = true
99
+ end
100
+ @rb.lock_for_scheduling(now+62) do
101
+ acquired_lock = true
102
+ end
103
+ end
104
+
105
+ acquired_lock.must_equal true
106
+ acquired_lock_early.must_equal false
107
+ end
108
+ end
109
+
110
+ describe "locking after waiting period is up" do
111
+ it "should yield" do
112
+ now = Time.now.to_i
113
+ @rb.lock_for_scheduling(now) {}
114
+
115
+ yielded = false
116
+ @rb.lock_for_scheduling(now+15) { yielded = true }
117
+ yielded.must_equal true
118
+ end
119
+
120
+ it "should yield last scheduled time" do
121
+ now = Time.now.to_i
122
+ @rb.lock_for_scheduling(now) {}
123
+
124
+ yielded = false
125
+ @rb.lock_for_scheduling(now+11) { |t|
126
+ t.must_equal now
127
+ yielded = true
128
+ }
129
+ yielded.must_equal true
130
+ end
131
+
132
+ it "should continue to yield as time goes on" do
133
+ yielded_count = 0
134
+ now = Time.now.to_i
135
+ @rb.lock_for_scheduling(now) {}
136
+
137
+ 10.times do |n|
138
+ @rb.lock_for_scheduling(now+((n+1)*30)) do
139
+ yielded_count += 1
140
+ end
141
+ end
142
+
143
+ yielded_count.must_equal 10
144
+ end
145
+ end
146
+ end