uv-rays 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +53 -0
- data/Rakefile +22 -0
- data/lib/uv-rays/abstract_tokenizer.rb +100 -0
- data/lib/uv-rays/buffered_tokenizer.rb +97 -0
- data/lib/uv-rays/connection.rb +175 -0
- data/lib/uv-rays/http/encoding.rb +119 -0
- data/lib/uv-rays/http/request.rb +150 -0
- data/lib/uv-rays/http/response.rb +119 -0
- data/lib/uv-rays/http_endpoint.rb +253 -0
- data/lib/uv-rays/scheduler/cron.rb +386 -0
- data/lib/uv-rays/scheduler/time.rb +275 -0
- data/lib/uv-rays/scheduler.rb +319 -0
- data/lib/uv-rays/tcp_server.rb +48 -0
- data/lib/uv-rays/version.rb +3 -0
- data/lib/uv-rays.rb +96 -0
- data/spec/abstract_tokenizer_spec.rb +87 -0
- data/spec/buffered_tokenizer_spec.rb +253 -0
- data/spec/connection_spec.rb +137 -0
- data/spec/http_endpoint_spec.rb +279 -0
- data/spec/scheduler_cron_spec.rb +429 -0
- data/spec/scheduler_spec.rb +90 -0
- data/spec/scheduler_time_spec.rb +132 -0
- data/uv-rays.gemspec +31 -0
- metadata +217 -0
@@ -0,0 +1,429 @@
|
|
1
|
+
require 'uv-rays'
|
2
|
+
|
3
|
+
describe UvRays::Scheduler::CronLine do
|
4
|
+
|
5
|
+
def cl(cronline_string)
|
6
|
+
UvRays::Scheduler::CronLine.new(cronline_string)
|
7
|
+
end
|
8
|
+
|
9
|
+
def match(line, time)
|
10
|
+
cl(line).matches?(time).should == true
|
11
|
+
end
|
12
|
+
def no_match(line, time)
|
13
|
+
cl(line).matches?(time).should == false
|
14
|
+
end
|
15
|
+
def to_a(line, array)
|
16
|
+
cl(line).to_array.should == array
|
17
|
+
end
|
18
|
+
def local(*args)
|
19
|
+
Time.local(*args)
|
20
|
+
end
|
21
|
+
alias lo local
|
22
|
+
|
23
|
+
def utc(*args)
|
24
|
+
Time.utc(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '.new' do
|
28
|
+
|
29
|
+
it 'interprets cron strings correctly' do
|
30
|
+
|
31
|
+
to_a '* * * * *', [ [0], nil, nil, nil, nil, nil, nil, nil ]
|
32
|
+
to_a '10-12 * * * *', [ [0], [10, 11, 12], nil, nil, nil, nil, nil, nil ]
|
33
|
+
to_a '* * * * sun,mon', [ [0], nil, nil, nil, nil, [0, 1], nil, nil ]
|
34
|
+
to_a '* * * * mon-wed', [ [0], nil, nil, nil, nil, [1, 2, 3], nil, nil ]
|
35
|
+
to_a '* * * * 7', [ [0], nil, nil, nil, nil, [0], nil, nil ]
|
36
|
+
to_a '* * * * 0', [ [0], nil, nil, nil, nil, [0], nil, nil ]
|
37
|
+
to_a '* * * * 0,1', [ [0], nil, nil, nil, nil, [0,1], nil, nil ]
|
38
|
+
to_a '* * * * 7,1', [ [0], nil, nil, nil, nil, [0,1], nil, nil ]
|
39
|
+
to_a '* * * * 7,0', [ [0], nil, nil, nil, nil, [0], nil, nil ]
|
40
|
+
to_a '* * * * sun,2-4', [ [0], nil, nil, nil, nil, [0, 2, 3, 4], nil, nil ]
|
41
|
+
|
42
|
+
to_a '* * * * sun,mon-tue', [ [0], nil, nil, nil, nil, [0, 1, 2], nil, nil ]
|
43
|
+
|
44
|
+
to_a '* * * * * *', [ nil, nil, nil, nil, nil, nil, nil, nil ]
|
45
|
+
to_a '1 * * * * *', [ [1], nil, nil, nil, nil, nil, nil, nil ]
|
46
|
+
to_a '7 10-12 * * * *', [ [7], [10, 11, 12], nil, nil, nil, nil, nil, nil ]
|
47
|
+
to_a '1-5 * * * * *', [ [1,2,3,4,5], nil, nil, nil, nil, nil, nil, nil ]
|
48
|
+
|
49
|
+
to_a '0 0 1 1 *', [ [0], [0], [0], [1], [1], nil, nil, nil ]
|
50
|
+
|
51
|
+
to_a '0 23-24 * * *', [ [0], [0], [23, 0], nil, nil, nil, nil, nil ]
|
52
|
+
#
|
53
|
+
# as reported by Aimee Rose in
|
54
|
+
# https://github.com/jmettraux/rufus-scheduler/issues/56
|
55
|
+
|
56
|
+
to_a '0 23-2 * * *', [ [0], [0], [23, 0, 1, 2], nil, nil, nil, nil, nil ]
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'rejects invalid weekday expressions' do
|
60
|
+
|
61
|
+
lambda { cl '0 17 * * MON_FRI' }.should raise_error
|
62
|
+
# underline instead of dash
|
63
|
+
|
64
|
+
lambda { cl '* * * * 9' }.should raise_error
|
65
|
+
lambda { cl '* * * * 0-12' }.should raise_error
|
66
|
+
lambda { cl '* * * * BLABLA' }.should raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'rejects invalid cronlines' do
|
70
|
+
|
71
|
+
lambda { cl '* nada * * 9' }.should raise_error(ArgumentError)
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'interprets cron strings with TZ correctly' do
|
75
|
+
|
76
|
+
to_a('* * * * * EST', [ [0], nil, nil, nil, nil, nil, nil, 'EST' ])
|
77
|
+
to_a('* * * * * * EST', [ nil, nil, nil, nil, nil, nil, nil, 'EST' ])
|
78
|
+
|
79
|
+
to_a(
|
80
|
+
'* * * * * * America/Chicago',
|
81
|
+
[ nil, nil, nil, nil, nil, nil, nil, 'America/Chicago' ])
|
82
|
+
to_a(
|
83
|
+
'* * * * * * America/New_York',
|
84
|
+
[ nil, nil, nil, nil, nil, nil, nil, 'America/New_York' ])
|
85
|
+
|
86
|
+
lambda { cl '* * * * * NotATimeZone' }.should raise_error
|
87
|
+
lambda { cl '* * * * * * NotATimeZone' }.should raise_error
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'interprets cron strings with / (slashes) correctly' do
|
91
|
+
|
92
|
+
to_a(
|
93
|
+
'0 */2 * * *',
|
94
|
+
[ [0], [0], (0..11).collect { |e| e * 2 }, nil, nil, nil, nil, nil ])
|
95
|
+
to_a(
|
96
|
+
'0 7-23/2 * * *',
|
97
|
+
[ [0], [0], (7..23).select { |e| e.odd? }, nil, nil, nil, nil, nil ])
|
98
|
+
to_a(
|
99
|
+
'*/10 * * * *',
|
100
|
+
[ [0], [0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, nil ])
|
101
|
+
|
102
|
+
# fighting https://github.com/jmettraux/rufus-scheduler/issues/65
|
103
|
+
#
|
104
|
+
to_a(
|
105
|
+
'*/10 * * * * Europe/Berlin',
|
106
|
+
[ [0], [ 0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, 'Europe/Berlin' ])
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'accepts lonely / (slashes) (like <= 2.0.19 did)' do
|
110
|
+
|
111
|
+
# fighting https://github.com/jmettraux/rufus-scheduler/issues/65
|
112
|
+
|
113
|
+
to_a(
|
114
|
+
'/10 * * * *',
|
115
|
+
[ [0], [ 0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, nil ])
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'does not support ranges for monthdays (sun#1-sun#2)' do
|
119
|
+
|
120
|
+
lambda {
|
121
|
+
UvRays::Scheduler::CronLine.new('* * * * sun#1-sun#2')
|
122
|
+
}.should raise_error(ArgumentError)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'accepts items with initial 0' do
|
126
|
+
|
127
|
+
to_a '09 * * * *', [ [0], [9], nil, nil, nil, nil, nil, nil ]
|
128
|
+
to_a '09-12 * * * *', [ [0], [9, 10, 11, 12], nil, nil, nil, nil, nil, nil ]
|
129
|
+
to_a '07-08 * * * *', [ [0], [7, 8], nil, nil, nil, nil, nil, nil ]
|
130
|
+
to_a '* */08 * * *', [ [0], nil, [0, 8, 16], nil, nil, nil, nil, nil ]
|
131
|
+
to_a '* */07 * * *', [ [0], nil, [0, 7, 14, 21], nil, nil, nil, nil, nil ]
|
132
|
+
to_a '* 01-09/04 * * *', [ [0], nil, [1, 5, 9], nil, nil, nil, nil, nil ]
|
133
|
+
to_a '* * * * 06', [ [0], nil, nil, nil, nil, [6], nil, nil ]
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'interprets cron strings with L correctly' do
|
137
|
+
|
138
|
+
to_a '* * L * *', [[0], nil, nil, ['L'], nil, nil, nil, nil ]
|
139
|
+
to_a '* * 2-5,L * *', [[0], nil, nil, [2,3,4,5,'L'], nil, nil, nil, nil ]
|
140
|
+
to_a '* * */8,L * *', [[0], nil, nil, [1,9,17,25,'L'], nil, nil, nil, nil ]
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'does not support ranges for L' do
|
144
|
+
|
145
|
+
lambda { cl '* * 15-L * *'}.should raise_error(ArgumentError)
|
146
|
+
lambda { cl '* * L/4 * *'}.should raise_error(ArgumentError)
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'does not support multiple Ls' do
|
150
|
+
|
151
|
+
lambda { cl '* * L,L * *'}.should raise_error(ArgumentError)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'raises if L is used for something else than days' do
|
155
|
+
|
156
|
+
lambda { cl '* L * * *'}.should raise_error(ArgumentError)
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'raises for out of range input' do
|
160
|
+
|
161
|
+
lambda { cl '60-62 * * * *'}.should raise_error(ArgumentError)
|
162
|
+
lambda { cl '62 * * * *'}.should raise_error(ArgumentError)
|
163
|
+
lambda { cl '60 * * * *'}.should raise_error(ArgumentError)
|
164
|
+
lambda { cl '* 25-26 * * *'}.should raise_error(ArgumentError)
|
165
|
+
lambda { cl '* 25 * * *'}.should raise_error(ArgumentError)
|
166
|
+
#
|
167
|
+
# as reported by Aimee Rose in
|
168
|
+
# https://github.com/jmettraux/rufus-scheduler/pull/58
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
describe '#next_time' do
|
173
|
+
|
174
|
+
def nt(cronline, now)
|
175
|
+
UvRays::Scheduler::CronLine.new(cronline).next_time(now)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'computes the next occurence correctly' do
|
179
|
+
|
180
|
+
now = Time.at(0).getutc # Thu Jan 01 00:00:00 UTC 1970
|
181
|
+
|
182
|
+
nt('* * * * *', now).should == now + 60
|
183
|
+
nt('* * * * sun', now).should == now + 259200
|
184
|
+
nt('* * * * * *', now).should == now + 1
|
185
|
+
nt('* * 13 * fri', now).should == now + 3715200
|
186
|
+
|
187
|
+
nt('10 12 13 12 *', now).should == now + 29938200
|
188
|
+
# this one is slow (1 year == 3 seconds)
|
189
|
+
#
|
190
|
+
# historical note:
|
191
|
+
# (comment made in 2006 or 2007, the underlying libs got better and
|
192
|
+
# that slowness is gone)
|
193
|
+
|
194
|
+
nt('0 0 * * thu', now).should == now + 604800
|
195
|
+
nt('00 0 * * thu', now).should == now + 604800
|
196
|
+
|
197
|
+
nt('0 0 * * *', now).should == now + 24 * 3600
|
198
|
+
nt('0 24 * * *', now).should == now + 24 * 3600
|
199
|
+
|
200
|
+
now = local(2008, 12, 31, 23, 59, 59, 0)
|
201
|
+
|
202
|
+
nt('* * * * *', now).should == now + 1
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'computes the next occurence correctly in UTC (TZ not specified)' do
|
206
|
+
|
207
|
+
now = utc(1970, 1, 1)
|
208
|
+
|
209
|
+
nt('* * * * *', now).should == utc(1970, 1, 1, 0, 1)
|
210
|
+
nt('* * * * sun', now).should == utc(1970, 1, 4)
|
211
|
+
nt('* * * * * *', now).should == utc(1970, 1, 1, 0, 0, 1)
|
212
|
+
nt('* * 13 * fri', now).should == utc(1970, 2, 13)
|
213
|
+
|
214
|
+
nt('10 12 13 12 *', now).should == utc(1970, 12, 13, 12, 10)
|
215
|
+
# this one is slow (1 year == 3 seconds)
|
216
|
+
nt('* * 1 6 *', now).should == utc(1970, 6, 1)
|
217
|
+
|
218
|
+
nt('0 0 * * thu', now).should == utc(1970, 1, 8)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'computes the next occurence correctly in local TZ (TZ not specified)' do
|
222
|
+
|
223
|
+
now = local(1970, 1, 1)
|
224
|
+
|
225
|
+
nt('* * * * *', now).should == local(1970, 1, 1, 0, 1)
|
226
|
+
nt('* * * * sun', now).should == local(1970, 1, 4)
|
227
|
+
nt('* * * * * *', now).should == local(1970, 1, 1, 0, 0, 1)
|
228
|
+
nt('* * 13 * fri', now).should == local(1970, 2, 13)
|
229
|
+
|
230
|
+
nt('10 12 13 12 *', now).should == local(1970, 12, 13, 12, 10)
|
231
|
+
# this one is slow (1 year == 3 seconds)
|
232
|
+
nt('* * 1 6 *', now).should == local(1970, 6, 1)
|
233
|
+
|
234
|
+
nt('0 0 * * thu', now).should == local(1970, 1, 8)
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'computes the next occurence correctly in UTC (TZ specified)' do
|
238
|
+
|
239
|
+
zone = 'Europe/Stockholm'
|
240
|
+
tz = TZInfo::Timezone.get(zone)
|
241
|
+
now = tz.local_to_utc(local(1970, 1, 1))
|
242
|
+
# Midnight in zone, UTC
|
243
|
+
|
244
|
+
nt("* * * * * #{zone}", now).should == utc(1969, 12, 31, 23, 1)
|
245
|
+
nt("* * * * sun #{zone}", now).should == utc(1970, 1, 3, 23)
|
246
|
+
nt("* * * * * * #{zone}", now).should == utc(1969, 12, 31, 23, 0, 1)
|
247
|
+
nt("* * 13 * fri #{zone}", now).should == utc(1970, 2, 12, 23)
|
248
|
+
|
249
|
+
nt("10 12 13 12 * #{zone}", now).should == utc(1970, 12, 13, 11, 10)
|
250
|
+
nt("* * 1 6 * #{zone}", now).should == utc(1970, 5, 31, 23)
|
251
|
+
|
252
|
+
nt("0 0 * * thu #{zone}", now).should == utc(1970, 1, 7, 23)
|
253
|
+
end
|
254
|
+
|
255
|
+
#it 'computes the next occurence correctly in local TZ (TZ specified)' do
|
256
|
+
# zone = 'Europe/Stockholm'
|
257
|
+
# tz = TZInfo::Timezone.get(zone)
|
258
|
+
# now = tz.local_to_utc(utc(1970, 1, 1)).localtime
|
259
|
+
# # Midnight in zone, local time
|
260
|
+
# nt("* * * * * #{zone}", now).should == local(1969, 12, 31, 18, 1)
|
261
|
+
# nt("* * * * sun #{zone}", now).should == local(1970, 1, 3, 18)
|
262
|
+
# nt("* * * * * * #{zone}", now).should == local(1969, 12, 31, 18, 0, 1)
|
263
|
+
# nt("* * 13 * fri #{zone}", now).should == local(1970, 2, 12, 18)
|
264
|
+
# nt("10 12 13 12 * #{zone}", now).should == local(1970, 12, 13, 6, 10)
|
265
|
+
# nt("* * 1 6 * #{zone}", now).should == local(1970, 5, 31, 19)
|
266
|
+
# nt("0 0 * * thu #{zone}", now).should == local(1970, 1, 7, 18)
|
267
|
+
#end
|
268
|
+
|
269
|
+
it 'computes the next time correctly when there is a sun#2 involved' do
|
270
|
+
|
271
|
+
nt('* * * * sun#1', local(1970, 1, 1)).should == local(1970, 1, 4)
|
272
|
+
nt('* * * * sun#2', local(1970, 1, 1)).should == local(1970, 1, 11)
|
273
|
+
|
274
|
+
nt('* * * * sun#2', local(1970, 1, 12)).should == local(1970, 2, 8)
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'computes the next time correctly when there is a sun#2,sun#3 involved' do
|
278
|
+
|
279
|
+
nt('* * * * sun#2,sun#3', local(1970, 1, 1)).should == local(1970, 1, 11)
|
280
|
+
nt('* * * * sun#2,sun#3', local(1970, 1, 12)).should == local(1970, 1, 18)
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'understands sun#L' do
|
284
|
+
|
285
|
+
nt('* * * * sun#L', local(1970, 1, 1)).should == local(1970, 1, 25)
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'understands sun#-1' do
|
289
|
+
|
290
|
+
nt('* * * * sun#-1', local(1970, 1, 1)).should == local(1970, 1, 25)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'understands sun#-2' do
|
294
|
+
|
295
|
+
nt('* * * * sun#-2', local(1970, 1, 1)).should == local(1970, 1, 18)
|
296
|
+
end
|
297
|
+
|
298
|
+
it 'computes the next time correctly when "L" (last day of month)' do
|
299
|
+
|
300
|
+
nt('* * L * *', lo(1970, 1, 1)).should == lo(1970, 1, 31)
|
301
|
+
nt('* * L * *', lo(1970, 2, 1)).should == lo(1970, 2, 28)
|
302
|
+
nt('* * L * *', lo(1972, 2, 1)).should == lo(1972, 2, 29)
|
303
|
+
nt('* * L * *', lo(1970, 4, 1)).should == lo(1970, 4, 30)
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'returns a time with subseconds chopped off' do
|
307
|
+
|
308
|
+
nt('* * * * *', Time.now).usec.should == 0
|
309
|
+
nt('* * * * *', Time.now).iso8601(10).match(/\.0+[^\d]/).should_not == nil
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe '#previous_time' do
|
314
|
+
|
315
|
+
def pt(cronline, now)
|
316
|
+
UvRays::Scheduler::CronLine.new(cronline).previous_time(now)
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'returns the previous time the cron should have triggered' do
|
320
|
+
|
321
|
+
pt('* * * * sun', lo(1970, 1, 1)).should == lo(1969, 12, 28, 23, 59, 00)
|
322
|
+
pt('* * 13 * *', lo(1970, 1, 1)).should == lo(1969, 12, 13, 23, 59, 00)
|
323
|
+
pt('0 12 13 * *', lo(1970, 1, 1)).should == lo(1969, 12, 13, 12, 00)
|
324
|
+
|
325
|
+
pt('* * * * * sun', lo(1970, 1, 1)).should == lo(1969, 12, 28, 23, 59, 59)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
describe '#matches?' do
|
330
|
+
|
331
|
+
it 'matches correctly in UTC (TZ not specified)' do
|
332
|
+
|
333
|
+
match '* * * * *', utc(1970, 1, 1, 0, 1)
|
334
|
+
match '* * * * sun', utc(1970, 1, 4)
|
335
|
+
match '* * * * * *', utc(1970, 1, 1, 0, 0, 1)
|
336
|
+
match '* * 13 * fri', utc(1970, 2, 13)
|
337
|
+
|
338
|
+
match '10 12 13 12 *', utc(1970, 12, 13, 12, 10)
|
339
|
+
match '* * 1 6 *', utc(1970, 6, 1)
|
340
|
+
|
341
|
+
match '0 0 * * thu', utc(1970, 1, 8)
|
342
|
+
|
343
|
+
match '0 0 1 1 *', utc(2012, 1, 1)
|
344
|
+
no_match '0 0 1 1 *', utc(2012, 1, 1, 1, 0)
|
345
|
+
end
|
346
|
+
|
347
|
+
it 'matches correctly in local TZ (TZ not specified)' do
|
348
|
+
|
349
|
+
match '* * * * *', local(1970, 1, 1, 0, 1)
|
350
|
+
match '* * * * sun', local(1970, 1, 4)
|
351
|
+
match '* * * * * *', local(1970, 1, 1, 0, 0, 1)
|
352
|
+
match '* * 13 * fri', local(1970, 2, 13)
|
353
|
+
|
354
|
+
match '10 12 13 12 *', local(1970, 12, 13, 12, 10)
|
355
|
+
match '* * 1 6 *', local(1970, 6, 1)
|
356
|
+
|
357
|
+
match '0 0 * * thu', local(1970, 1, 8)
|
358
|
+
|
359
|
+
match '0 0 1 1 *', local(2012, 1, 1)
|
360
|
+
no_match '0 0 1 1 *', local(2012, 1, 1, 1, 0)
|
361
|
+
end
|
362
|
+
|
363
|
+
it 'matches correctly in UTC (TZ specified)' do
|
364
|
+
|
365
|
+
zone = 'Europe/Stockholm'
|
366
|
+
|
367
|
+
match "* * * * * #{zone}", utc(1969, 12, 31, 23, 1)
|
368
|
+
match "* * * * sun #{zone}", utc(1970, 1, 3, 23)
|
369
|
+
match "* * * * * * #{zone}", utc(1969, 12, 31, 23, 0, 1)
|
370
|
+
match "* * 13 * fri #{zone}", utc(1970, 2, 12, 23)
|
371
|
+
|
372
|
+
match "10 12 13 12 * #{zone}", utc(1970, 12, 13, 11, 10)
|
373
|
+
match "* * 1 6 * #{zone}", utc(1970, 5, 31, 23)
|
374
|
+
|
375
|
+
match "0 0 * * thu #{zone}", utc(1970, 1, 7, 23)
|
376
|
+
end
|
377
|
+
|
378
|
+
it 'matches correctly when there is a sun#2 involved' do
|
379
|
+
|
380
|
+
match '* * 13 * fri#2', utc(1970, 2, 13)
|
381
|
+
no_match '* * 13 * fri#2', utc(1970, 2, 20)
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'matches correctly when there is a L involved' do
|
385
|
+
|
386
|
+
match '* * L * *', utc(1970, 1, 31)
|
387
|
+
no_match '* * L * *', utc(1970, 1, 30)
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'matches correctly when there is a sun#2,sun#3 involved' do
|
391
|
+
|
392
|
+
no_match '* * * * sun#2,sun#3', local(1970, 1, 4)
|
393
|
+
match '* * * * sun#2,sun#3', local(1970, 1, 11)
|
394
|
+
match '* * * * sun#2,sun#3', local(1970, 1, 18)
|
395
|
+
no_match '* * * * sun#2,sun#3', local(1970, 1, 25)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
describe '#monthdays' do
|
400
|
+
|
401
|
+
it 'returns the appropriate "sun#2"-like string' do
|
402
|
+
|
403
|
+
class UvRays::Scheduler::CronLine
|
404
|
+
public :monthdays
|
405
|
+
end
|
406
|
+
|
407
|
+
cl = UvRays::Scheduler::CronLine.new('* * * * *')
|
408
|
+
|
409
|
+
cl.monthdays(local(1970, 1, 1)).should == %w[ thu#1 thu#-5 ]
|
410
|
+
cl.monthdays(local(1970, 1, 7)).should == %w[ wed#1 wed#-4 ]
|
411
|
+
cl.monthdays(local(1970, 1, 14)).should == %w[ wed#2 wed#-3 ]
|
412
|
+
|
413
|
+
cl.monthdays(local(2011, 3, 11)).should == %w[ fri#2 fri#-3 ]
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
describe '#frequency' do
|
418
|
+
|
419
|
+
it 'returns the shortest delta between two occurrences' do
|
420
|
+
|
421
|
+
UvRays::Scheduler::CronLine.new('* * * * *').frequency.should == 60
|
422
|
+
UvRays::Scheduler::CronLine.new('* * * * * *').frequency.should == 1
|
423
|
+
|
424
|
+
UvRays::Scheduler::CronLine.new('5 23 * * *').frequency.should == 24 * 3600
|
425
|
+
UvRays::Scheduler::CronLine.new('5 * * * *').frequency.should == 3600
|
426
|
+
UvRays::Scheduler::CronLine.new('10,20,30 * * * *').frequency.should == 600
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'uv-rays'
|
2
|
+
|
3
|
+
describe UvRays::Scheduler do
|
4
|
+
before :each do
|
5
|
+
@loop = Libuv::Loop.new
|
6
|
+
@general_failure = []
|
7
|
+
@timeout = @loop.timer do
|
8
|
+
@loop.stop
|
9
|
+
@general_failure << "test timed out"
|
10
|
+
end
|
11
|
+
@timeout.start(5000)
|
12
|
+
@scheduler = @loop.scheduler
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to schedule a one shot event using 'in'" do
|
16
|
+
@loop.run { |logger|
|
17
|
+
logger.progress do |level, errorid, error|
|
18
|
+
begin
|
19
|
+
@general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
|
20
|
+
rescue Exception
|
21
|
+
@general_failure << 'error in logger'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
@event = @scheduler.in('0.5s') do |triggered, event|
|
26
|
+
@triggered_at = triggered
|
27
|
+
@result = event
|
28
|
+
@loop.stop
|
29
|
+
end
|
30
|
+
}
|
31
|
+
|
32
|
+
@general_failure.should == []
|
33
|
+
@event.should == @result
|
34
|
+
@diff = @triggered_at - @event.last_scheduled
|
35
|
+
(@diff >= 500 && @diff < 750).should == true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be able to schedule a one shot event using 'at'" do
|
39
|
+
@loop.run { |logger|
|
40
|
+
logger.progress do |level, errorid, error|
|
41
|
+
begin
|
42
|
+
@general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
|
43
|
+
rescue Exception
|
44
|
+
@general_failure << 'error in logger'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
@event = @scheduler.at(Time.now + 1) do |triggered, event|
|
49
|
+
@triggered_at = triggered
|
50
|
+
@result = event
|
51
|
+
@loop.stop
|
52
|
+
end
|
53
|
+
}
|
54
|
+
|
55
|
+
@general_failure.should == []
|
56
|
+
@event.should == @result
|
57
|
+
@diff = @triggered_at - @event.last_scheduled
|
58
|
+
(@diff >= 1000 && @diff < 1250).should == true
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should be able to schedule a repeat event" do
|
62
|
+
@loop.run { |logger|
|
63
|
+
logger.progress do |level, errorid, error|
|
64
|
+
begin
|
65
|
+
@general_failure << "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
|
66
|
+
rescue Exception
|
67
|
+
@general_failure << 'error in logger'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
@run = 0
|
72
|
+
@event = @scheduler.every('0.25s') do |triggered, event|
|
73
|
+
@triggered_at = triggered
|
74
|
+
@result = event
|
75
|
+
|
76
|
+
@run += 1
|
77
|
+
if @run == 2
|
78
|
+
@event.pause
|
79
|
+
@loop.stop
|
80
|
+
end
|
81
|
+
end
|
82
|
+
}
|
83
|
+
|
84
|
+
@general_failure.should == []
|
85
|
+
@run.should == 2
|
86
|
+
@event.should == @result
|
87
|
+
@diff = @triggered_at - @event.last_scheduled
|
88
|
+
(@diff >= 250 && @diff < 500).should == true
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
|
2
|
+
#
|
3
|
+
# Specifying rufus-scheduler
|
4
|
+
#
|
5
|
+
# Wed Apr 17 06:00:59 JST 2013
|
6
|
+
#
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
describe UvRays::Scheduler do
|
11
|
+
|
12
|
+
describe '.parse_duration' do
|
13
|
+
|
14
|
+
def pd(s)
|
15
|
+
UvRays::Scheduler.parse_duration(s)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'parses duration strings' do
|
19
|
+
|
20
|
+
pd('-1.0d1.0w1.0d').should == -777600000
|
21
|
+
pd('-1d1w1d').should == -777600000
|
22
|
+
pd('-1w2d').should == -777600000
|
23
|
+
pd('-1h10s').should == -3610000
|
24
|
+
pd('-1h').should == -3600000
|
25
|
+
pd('-5.').should == -5
|
26
|
+
pd('-2.5s').should == -2500
|
27
|
+
pd('-1s').should == -1000
|
28
|
+
pd('-500').should == -500
|
29
|
+
pd('').should == 0
|
30
|
+
pd('5.0').should == 5
|
31
|
+
pd('0.5').should == 0
|
32
|
+
pd('.5').should == 0
|
33
|
+
pd('5.').should == 5
|
34
|
+
pd('500').should == 500
|
35
|
+
pd('1000').should == 1000
|
36
|
+
pd('1').should == 1
|
37
|
+
pd('1s').should == 1000
|
38
|
+
pd('2.5s').should == 2500
|
39
|
+
pd('1h').should == 3600000
|
40
|
+
pd('1h10s').should == 3610000
|
41
|
+
pd('1w2d').should == 777600000
|
42
|
+
pd('1d1w1d').should == 777600000
|
43
|
+
pd('1.0d1.0w1.0d').should == 777600000
|
44
|
+
|
45
|
+
pd('.5m').should == 30000
|
46
|
+
pd('5.m').should == 300000
|
47
|
+
pd('1m.5s').should == 60500
|
48
|
+
pd('-.5m').should == -30000
|
49
|
+
|
50
|
+
pd('1').should == 1
|
51
|
+
pd('0.1').should == 0
|
52
|
+
pd('1s').should == 1000
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'calls #to_s on its input' do
|
56
|
+
|
57
|
+
pd(1).should == 1
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'raises on wrong duration strings' do
|
61
|
+
|
62
|
+
lambda { pd('-') }.should raise_error(ArgumentError)
|
63
|
+
lambda { pd('h') }.should raise_error(ArgumentError)
|
64
|
+
lambda { pd('whatever') }.should raise_error(ArgumentError)
|
65
|
+
lambda { pd('hms') }.should raise_error(ArgumentError)
|
66
|
+
|
67
|
+
lambda { pd(' 1h ') }.should raise_error(ArgumentError)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '.to_duration' do
|
72
|
+
|
73
|
+
def td(o, opts={})
|
74
|
+
UvRays::Scheduler.to_duration(o, opts)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'turns integers into duration strings' do
|
78
|
+
|
79
|
+
td(0).should == '0s'
|
80
|
+
td(60000).should == '1m'
|
81
|
+
td(61000).should == '1m1s'
|
82
|
+
td(3661000).should == '1h1m1s'
|
83
|
+
td(24 * 3600 * 1000).should == '1d'
|
84
|
+
td(7 * 24 * 3600 * 1000 + 1000).should == '1w1s'
|
85
|
+
td(30 * 24 * 3600 * 1000 + 1000).should == '4w2d1s'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'ignores seconds and milliseconds if :drop_seconds => true' do
|
89
|
+
|
90
|
+
td(0, :drop_seconds => true).should == '0m'
|
91
|
+
td(5000, :drop_seconds => true).should == '0m'
|
92
|
+
td(61000, :drop_seconds => true).should == '1m'
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'displays months if :months => true' do
|
96
|
+
|
97
|
+
td(1000, :months => true).should == '1s'
|
98
|
+
td(30 * 24 * 3600 * 1000 + 1000, :months => true).should == '1M1s'
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'turns floats into duration strings' do
|
102
|
+
|
103
|
+
td(100).should == '100'
|
104
|
+
td(1100).should == '1s100'
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '.to_duration_hash' do
|
109
|
+
|
110
|
+
def tdh(o, opts={})
|
111
|
+
UvRays::Scheduler.to_duration_hash(o, opts)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'turns integers duration hashes' do
|
115
|
+
|
116
|
+
tdh(0).should == {}
|
117
|
+
tdh(60000).should == { :m => 1 }
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'turns floats duration hashes' do
|
121
|
+
|
122
|
+
tdh(128).should == { :ms => 128 }
|
123
|
+
tdh(60127).should == { :m => 1, :ms => 127 }
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'drops seconds and milliseconds if :drop_seconds => true' do
|
127
|
+
|
128
|
+
tdh(61127).should == { :m => 1, :s => 1, :ms => 127 }
|
129
|
+
tdh(61127, :drop_seconds => true).should == { :m => 1 }
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/uv-rays.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path("../lib/uv-rays/version", __FILE__)
|
2
|
+
|
3
|
+
Gem::Specification.new do |gem|
|
4
|
+
gem.name = "uv-rays"
|
5
|
+
gem.version = UvRays::VERSION
|
6
|
+
gem.license = 'MIT'
|
7
|
+
gem.authors = ["Stephen von Takach"]
|
8
|
+
gem.email = ["steve@cotag.me"]
|
9
|
+
gem.homepage = "https://github.com/cotag/uv-rays"
|
10
|
+
gem.summary = "Abstractions for working with Libuv"
|
11
|
+
gem.description = "Opinionated abstractions for Libuv"
|
12
|
+
|
13
|
+
gem.required_ruby_version = '>= 1.9.2'
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
|
16
|
+
gem.add_runtime_dependency 'libuv'
|
17
|
+
gem.add_runtime_dependency 'bisect'
|
18
|
+
gem.add_runtime_dependency 'tzinfo'
|
19
|
+
gem.add_runtime_dependency 'cookiejar'
|
20
|
+
gem.add_runtime_dependency 'ipaddress'
|
21
|
+
gem.add_runtime_dependency 'addressable'
|
22
|
+
gem.add_runtime_dependency 'http-parser'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'rspec', '>= 2.14'
|
25
|
+
gem.add_development_dependency 'rake', '>= 10.1'
|
26
|
+
gem.add_development_dependency 'yard'
|
27
|
+
|
28
|
+
gem.files = Dir["{lib}/**/*"] + %w(Rakefile uv-rays.gemspec README.md LICENSE)
|
29
|
+
gem.test_files = Dir["spec/**/*"]
|
30
|
+
gem.extra_rdoc_files = ["README.md"]
|
31
|
+
end
|