rufus-scheduler 3.1.9 → 3.2.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.
@@ -1,1113 +0,0 @@
1
-
2
- #
3
- # Specifying rufus-scheduler
4
- #
5
- # Sat Mar 21 12:55:27 JST 2009
6
- #
7
-
8
- require 'spec_helper'
9
-
10
- class Time
11
-
12
- def to_compact_s
13
-
14
- off = self.utc_offset / 3600
15
- off = off >= 0 ? "+#{off}" : off.to_s
16
-
17
- self.strftime('%H%M') + off + self.dup.utc.strftime('(%H%M)')
18
- end
19
- end
20
-
21
-
22
- describe Rufus::Scheduler::CronLine do
23
-
24
- def cl(cronline_string)
25
- Rufus::Scheduler::CronLine.new(cronline_string)
26
- end
27
-
28
- def nt(cronline, now)
29
- Rufus::Scheduler::CronLine.new(cronline).next_time(now)
30
- end
31
- def ntz(cronline, now)
32
- tz = cronline.split.last
33
- tu = nt(cronline, now).utc
34
- in_zone(tz) { tu.getlocal }
35
- end
36
-
37
- def pt(cronline, now)
38
- Rufus::Scheduler::CronLine.new(cronline).previous_time(now)
39
- end
40
- def ptz(cronline, now)
41
- tz = cronline.split.last
42
- tu = pt(cronline, now).utc
43
- in_zone(tz) { tu.getlocal }
44
- end
45
-
46
- def ns(cronline, now)
47
- Rufus::Scheduler::CronLine.new(cronline).next_second(now)
48
- end
49
- def ps(cronline, now)
50
- Rufus::Scheduler::CronLine.new(cronline).prev_second(now)
51
- end
52
-
53
- def match(line, time)
54
- expect(cl(line).matches?(time)).to eq(true)
55
- end
56
- def no_match(line, time)
57
- expect(cl(line).matches?(time)).to eq(false)
58
- end
59
- def to_a(line, array)
60
- expect(cl(line).to_array).to eq(array)
61
- end
62
-
63
- describe '.new' do
64
-
65
- it 'interprets cron strings correctly' do
66
-
67
- to_a '* * * * *', [ [0], nil, nil, nil, nil, nil, nil, nil ]
68
- to_a '10-12 * * * *', [ [0], [10, 11, 12], nil, nil, nil, nil, nil, nil ]
69
- to_a '* * * * sun,mon', [ [0], nil, nil, nil, nil, [0, 1], nil, nil ]
70
- to_a '* * * * mon-wed', [ [0], nil, nil, nil, nil, [1, 2, 3], nil, nil ]
71
- to_a '* * * * 7', [ [0], nil, nil, nil, nil, [0], nil, nil ]
72
- to_a '* * * * 0', [ [0], nil, nil, nil, nil, [0], nil, nil ]
73
- to_a '* * * * 0,1', [ [0], nil, nil, nil, nil, [0,1], nil, nil ]
74
- to_a '* * * * 7,1', [ [0], nil, nil, nil, nil, [0,1], nil, nil ]
75
- to_a '* * * * 7,0', [ [0], nil, nil, nil, nil, [0], nil, nil ]
76
- to_a '* * * * sun,2-4', [ [0], nil, nil, nil, nil, [0, 2, 3, 4], nil, nil ]
77
-
78
- to_a '* * * * sun,mon-tue', [ [0], nil, nil, nil, nil, [0, 1, 2], nil, nil ]
79
-
80
- to_a '* * * * * *', [ nil, nil, nil, nil, nil, nil, nil, nil ]
81
- to_a '1 * * * * *', [ [1], nil, nil, nil, nil, nil, nil, nil ]
82
- to_a '7 10-12 * * * *', [ [7], [10, 11, 12], nil, nil, nil, nil, nil, nil ]
83
- to_a '1-5 * * * * *', [ [1,2,3,4,5], nil, nil, nil, nil, nil, nil, nil ]
84
-
85
- to_a '0 0 1 1 *', [ [0], [0], [0], [1], [1], nil, nil, nil ]
86
-
87
- to_a '52 0 * * *', [ [0], [52], [0], nil, nil, nil, nil, nil ]
88
-
89
- #if ruby18?
90
- # to_a '0 23-24 * * *', [ [0], [0], [0, 23], nil, nil, nil, nil, nil ]
91
- #else
92
- # to_a '0 23-24 * * *', [ [0], [0], [23, 0], nil, nil, nil, nil, nil ]
93
- #end
94
- #
95
- # as reported by Aimee Rose in
96
- # https://github.com/jmettraux/rufus-scheduler/issues/56
97
- to_a '0 23-24 * * *', [ [0], [0], [0, 23], nil, nil, nil, nil, nil ]
98
-
99
- #if ruby18?
100
- # to_a '0 23-2 * * *', [ [0], [0], [0, 1, 2, 23], nil, nil, nil, nil, nil ]
101
- #else
102
- # to_a '0 23-2 * * *', [ [0], [0], [23, 0, 1, 2], nil, nil, nil, nil, nil ]
103
- #end
104
- to_a '0 23-2 * * *', [ [0], [0], [0, 1, 2, 23], nil, nil, nil, nil, nil ]
105
-
106
- # modulo forms work for five-field forms
107
- to_a '*/17 * * * *', [[0], [0, 17, 34, 51], nil, nil, nil, nil, nil, nil]
108
- to_a '13 */17 * * *', [[0], [13], [0, 17], nil, nil, nil, nil, nil]
109
-
110
- # modulo forms work for six-field forms
111
- to_a '*/17 * * * * *', [[0, 17, 34, 51], nil, nil, nil, nil, nil, nil, nil]
112
- to_a '13 */17 * * * *', [[13], [0, 17, 34, 51], nil, nil, nil, nil, nil, nil]
113
- end
114
-
115
- it 'rejects invalid weekday expressions' do
116
-
117
- expect { cl '0 17 * * MON_FRI' }.to raise_error(ArgumentError)
118
- # underline instead of dash
119
-
120
- expect { cl '* * * * 9' }.to raise_error(ArgumentError)
121
- expect { cl '* * * * 0-12' }.to raise_error(ArgumentError)
122
- expect { cl '* * * * BLABLA' }.to raise_error(ArgumentError)
123
- end
124
-
125
- it 'rejects invalid cronlines' do
126
-
127
- expect { cl '* nada * * 9' }.to raise_error(ArgumentError)
128
- end
129
-
130
- it 'interprets cron strings with TZ correctly' do
131
-
132
- to_a('* * * * * EST', [ [0], nil, nil, nil, nil, nil, nil, 'EST' ])
133
- to_a('* * * * * * EST', [ nil, nil, nil, nil, nil, nil, nil, 'EST' ])
134
-
135
- to_a(
136
- '* * * * * * America/Chicago',
137
- [ nil, nil, nil, nil, nil, nil, nil, 'America/Chicago' ])
138
- to_a(
139
- '* * * * * * America/New_York',
140
- [ nil, nil, nil, nil, nil, nil, nil, 'America/New_York' ])
141
-
142
- expect { cl '* * * * * NotATimeZone' }.to raise_error(ArgumentError)
143
- expect { cl '* * * * * * NotATimeZone' }.to raise_error(ArgumentError)
144
- end
145
-
146
- it 'interprets cron strings with / (slashes) correctly' do
147
-
148
- to_a(
149
- '0 */2 * * *',
150
- [ [0], [0], (0..23).select { |e| e.even? }, nil, nil, nil, nil, nil ])
151
- to_a(
152
- '0 0-23/2 * * *',
153
- [ [0], [0], (0..23).select { |e| e.even? }, nil, nil, nil, nil, nil ])
154
- to_a(
155
- '0 7-23/2 * * *',
156
- [ [0], [0], (7..23).select { |e| e.odd? }, nil, nil, nil, nil, nil ])
157
- to_a(
158
- '*/10 * * * *',
159
- [ [0], [0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, nil ])
160
-
161
- # fighting https://github.com/jmettraux/rufus-scheduler/issues/65
162
- #
163
- to_a(
164
- '*/10 * * * * Europe/Berlin',
165
- [ [0], [ 0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, 'Europe/Berlin' ])
166
- end
167
-
168
- it 'accepts lonely / (slashes) (like <= 2.0.19 did)' do
169
-
170
- # fighting https://github.com/jmettraux/rufus-scheduler/issues/65
171
-
172
- to_a(
173
- '/10 * * * *',
174
- [ [0], [ 0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, nil ])
175
- end
176
-
177
- it 'rejects / for days (every other wednesday)' do
178
-
179
- expect {
180
- Rufus::Scheduler::CronLine.new('* * * * wed/2')
181
- }.to raise_error(ArgumentError)
182
- end
183
-
184
- it 'does not support ranges for monthdays (sun#1-sun#2)' do
185
-
186
- expect {
187
- Rufus::Scheduler::CronLine.new('* * * * sun#1-sun#2')
188
- }.to raise_error(ArgumentError)
189
- end
190
-
191
- it 'accepts items with initial 0' do
192
-
193
- to_a(
194
- '09 * * * *', [ [0], [9], nil, nil, nil, nil, nil, nil ])
195
- to_a(
196
- '09-12 * * * *', [ [0], [9, 10, 11, 12], nil, nil, nil, nil, nil, nil ])
197
- to_a(
198
- '07-08 * * * *', [ [0], [7, 8], nil, nil, nil, nil, nil, nil ])
199
- to_a(
200
- '* */08 * * *', [ [0], nil, [0, 8, 16], nil, nil, nil, nil, nil ])
201
- to_a(
202
- '* */07 * * *', [ [0], nil, [0, 7, 14, 21], nil, nil, nil, nil, nil ])
203
- to_a(
204
- '* 01-09/04 * * *', [ [0], nil, [1, 5, 9], nil, nil, nil, nil, nil ])
205
- to_a(
206
- '* * * * 06', [ [0], nil, nil, nil, nil, [6], nil, nil ])
207
- end
208
-
209
- it 'interprets cron strings with L correctly' do
210
-
211
- to_a(
212
- '* * L * *', [[0], nil, nil, ['L'], nil, nil, nil, nil ])
213
- to_a(
214
- '* * 2-5,L * *', [[0], nil, nil, [2,3,4,5,'L'], nil, nil, nil, nil ])
215
- to_a(
216
- '* * */8,L * *', [[0], nil, nil, [1,9,17,25,'L'], nil, nil, nil, nil ])
217
- end
218
-
219
- it 'does not support ranges for L' do
220
-
221
- expect { cl '* * 15-L * *'}.to raise_error(ArgumentError)
222
- expect { cl '* * L/4 * *'}.to raise_error(ArgumentError)
223
- end
224
-
225
- it 'does not support multiple Ls' do
226
-
227
- expect { cl '* * L,L * *'}.to raise_error(ArgumentError)
228
- end
229
-
230
- it 'raises if L is used for something else than days' do
231
-
232
- expect { cl '* L * * *'}.to raise_error(ArgumentError)
233
- end
234
-
235
- it 'raises for out of range input' do
236
-
237
- expect { cl '60-62 * * * *'}.to raise_error(ArgumentError)
238
- expect { cl '62 * * * *'}.to raise_error(ArgumentError)
239
- expect { cl '60 * * * *'}.to raise_error(ArgumentError)
240
- expect { cl '* 25-26 * * *'}.to raise_error(ArgumentError)
241
- expect { cl '* 25 * * *'}.to raise_error(ArgumentError)
242
- #
243
- # as reported by Aimee Rose in
244
- # https://github.com/jmettraux/rufus-scheduler/pull/58
245
- end
246
-
247
- it 'sorts seconds' do
248
-
249
- to_a(
250
- '23,30,10 * * * * *', [ [10,23,30], nil, nil, nil, nil, nil, nil, nil ])
251
- end
252
-
253
- it 'sorts minutes' do
254
-
255
- to_a(
256
- '23,30,10 * * * * ', [ [0], [10,23,30], nil, nil, nil, nil, nil, nil ])
257
- end
258
-
259
- it 'sorts days' do
260
-
261
- to_a(
262
- '* * 14,7 * * ', [ [0], nil, nil, [7, 14], nil, nil, nil, nil ])
263
- end
264
-
265
- it 'sorts months' do
266
-
267
- to_a(
268
- '* * * 11,3,4 * ', [ [0], nil, nil, nil, [3,4,11], nil, nil, nil ])
269
- end
270
-
271
- it 'sorts days of week' do
272
-
273
- to_a(
274
- '* * * * Sun,Fri,2 ', [ [0], nil, nil, nil, nil, [0, 2, 5], nil, nil ])
275
- end
276
- end
277
-
278
- describe '#next_time' do
279
-
280
- it 'computes the next occurence correctly' do
281
-
282
- in_zone 'Europe/Berlin' do
283
-
284
- now = Time.at(0) - 3600
285
-
286
- expect(nt('* * * * *', now)).to eq(now + 60)
287
- expect(nt('* * * * sun', now)).to eq(now + 259200)
288
- expect(nt('* * * * * *', now)).to eq(now + 1)
289
- expect(nt('* * 13 * fri', now)).to eq(now + 3715200)
290
-
291
- expect(nt('10 12 13 12 *', now)).to eq(now + 29938200)
292
- # this one is slow (1 year == 3 seconds)
293
- #
294
- # historical note:
295
- # (comment made in 2006 or 2007, the underlying libs got better and
296
- # that slowness is gone)
297
-
298
- expect(nt('0 0 * * thu', now)).to eq(now + 604800)
299
- expect(nt('00 0 * * thu', now)).to eq(now + 604800)
300
-
301
- expect(nt('0 0 * * *', now)).to eq(now + 24 * 3600)
302
- expect(nt('0 24 * * *', now)).to eq(now + 24 * 3600)
303
-
304
- now = local(2008, 12, 31, 23, 59, 59, 0)
305
-
306
- expect(nt('* * * * *', now)).to eq(now + 1)
307
- end
308
- end
309
-
310
- it 'computes the next occurence correctly in local TZ (TZ not specified)' do
311
-
312
- now = local(1970, 1, 1)
313
-
314
- expect(nt('* * * * *', now)).to eq(local(1970, 1, 1, 0, 1))
315
- expect(nt('* * * * sun', now)).to eq(local(1970, 1, 4))
316
- expect(nt('* * * * * *', now)).to eq(local(1970, 1, 1, 0, 0, 1))
317
- expect(nt('* * 13 * fri', now)).to eq(local(1970, 2, 13))
318
-
319
- expect(nt('10 12 13 12 *', now)).to eq(local(1970, 12, 13, 12, 10))
320
- # this one is slow (1 year == 3 seconds)
321
- expect(nt('* * 1 6 *', now)).to eq(local(1970, 6, 1))
322
-
323
- expect(nt('0 0 * * thu', now)).to eq(local(1970, 1, 8))
324
- end
325
-
326
- it 'computes the next occurence correctly in UTC (TZ specified)' do
327
-
328
- zone = 'Europe/Stockholm'
329
- now = in_zone(zone) { Time.local(1970, 1, 1) }
330
-
331
- expect(nt("* * * * * #{zone}", now)).to eq(utc(1969, 12, 31, 23, 1))
332
- expect(nt("* * * * sun #{zone}", now)).to eq(utc(1970, 1, 3, 23))
333
- expect(nt("* * * * * * #{zone}", now)).to eq(utc(1969, 12, 31, 23, 0, 1))
334
- expect(nt("* * 13 * fri #{zone}", now)).to eq(utc(1970, 2, 12, 23))
335
-
336
- expect(nt("10 12 13 12 * #{zone}", now)).to eq(utc(1970, 12, 13, 11, 10))
337
- expect(nt("* * 1 6 * #{zone}", now)).to eq(utc(1970, 5, 31, 23))
338
-
339
- expect(nt("0 0 * * thu #{zone}", now)).to eq(utc(1970, 1, 7, 23))
340
- end
341
-
342
- it 'computes the next time correctly when there is a sun#2 involved' do
343
-
344
- expect(nt('* * * * sun#1', local(1970, 1, 1))).to eq(local(1970, 1, 4))
345
- expect(nt('* * * * sun#2', local(1970, 1, 1))).to eq(local(1970, 1, 11))
346
-
347
- expect(nt('* * * * sun#2', local(1970, 1, 12))).to eq(local(1970, 2, 8))
348
- end
349
-
350
- it 'computes next time correctly when there is a sun#2,sun#3 involved' do
351
-
352
- expect(
353
- nt('* * * * sun#2,sun#3', local(1970, 1, 1))).to eq(local(1970, 1, 11))
354
- expect(
355
- nt('* * * * sun#2,sun#3', local(1970, 1, 12))).to eq(local(1970, 1, 18))
356
- end
357
-
358
- it 'understands sun#L' do
359
-
360
- expect(nt('* * * * sun#L', local(1970, 1, 1))).to eq(local(1970, 1, 25))
361
- end
362
-
363
- it 'understands sun#-1' do
364
-
365
- expect(nt('* * * * sun#-1', local(1970, 1, 1))).to eq(local(1970, 1, 25))
366
- end
367
-
368
- it 'understands sun#-2' do
369
-
370
- expect(nt('* * * * sun#-2', local(1970, 1, 1))).to eq(local(1970, 1, 18))
371
- end
372
-
373
- it 'computes the next time correctly when "L" (last day of month)' do
374
-
375
- expect(nt('* * L * *', lo(1970, 1, 1))).to eq(lo(1970, 1, 31))
376
- expect(nt('* * L * *', lo(1970, 2, 1))).to eq(lo(1970, 2, 28))
377
- expect(nt('* * L * *', lo(1972, 2, 1))).to eq(lo(1972, 2, 29))
378
- expect(nt('* * L * *', lo(1970, 4, 1))).to eq(lo(1970, 4, 30))
379
- end
380
-
381
- it 'returns a time with subseconds chopped off' do
382
-
383
- expect(
384
- nt('* * * * *', Time.now).usec).to eq(0)
385
- expect(
386
- nt('* * * * *', Time.now).iso8601(10).match(/\.0+[^\d]/)).not_to eq(nil)
387
- end
388
-
389
- # New York EST: UTC-5
390
- # summer (dst) EDT: UTC-4
391
-
392
- # gh-127
393
- #
394
- it 'survives TZInfo::AmbiguousTime' do
395
-
396
- if ruby18? or jruby?
397
- expect(
398
- ntz(
399
- '30 1 31 10 * America/New_York',
400
- ltz('America/New_York', 2004, 10, 1)
401
- ).strftime('%Y-%m-%d %H:%M:%S')
402
- ).to eq('2004-10-31 01:30:00')
403
- else
404
- expect(
405
- ntz(
406
- '30 1 31 10 * America/New_York',
407
- ltz('America/New_York', 2004, 10, 1)
408
- )
409
- ).to eq(
410
- ltz('America/New_York', 0, 30, 1, 31, 10, 2004, nil, nil, true, nil)
411
- # EDT summer time UTC-4
412
- )
413
- end
414
- end
415
-
416
- # gh-127
417
- #
418
- it 'survives TZInfo::PeriodNotFound' do
419
-
420
- expect(
421
- ntz(
422
- '0 2 9 3 * America/New_York',
423
- ltz('America/New_York', 2014, 3, 1)
424
- )
425
- ).to eq(ltz('America/New_York', 2015, 3, 9, 2, 0, 0))
426
- end
427
-
428
- it 'understands six-field crontabs' do
429
-
430
- expect(nt('* * * * * *',local(1970,1,1,1,1,1))).to(
431
- eq(local(1970,1,1,1,1,2))
432
- )
433
- expect(nt('* * * * * *',local(1970,1,1,1,1,2))).to(
434
- eq(local(1970,1,1,1,1,3))
435
- )
436
- expect(nt('*/10 * * * * *',local(1970,1,1,1,1,0))).to(
437
- eq(local(1970,1,1,1,1,10))
438
- )
439
- expect(nt('*/10 * * * * *',local(1970,1,1,1,1,9))).to(
440
- eq(local(1970,1,1,1,1,10))
441
- )
442
- expect(nt('*/10 * * * * *',local(1970,1,1,1,1,10))).to(
443
- eq(local(1970,1,1,1,1,20))
444
- )
445
- expect(nt('*/10 * * * * *',local(1970,1,1,1,1,40))).to(
446
- eq(local(1970,1,1,1,1,50))
447
- )
448
- expect(nt('*/10 * * * * *',local(1970,1,1,1,1,49))).to(
449
- eq(local(1970,1,1,1,1,50))
450
- )
451
- expect(nt('*/10 * * * * *',local(1970,1,1,1,1,50))).to(
452
- eq(local(1970,1,1,1,2,00))
453
- )
454
- end
455
- end
456
-
457
- describe '#next_second' do
458
- [
459
- [ '*/10 * * * * *', local(1970,1,1,1,1, 0), 0 ], # 0 sec to 0s mark
460
- [ '*/10 * * * * *', local(1970,1,1,1,1, 1), 9 ], # 9 sec to 10s mark
461
- [ '*/10 * * * * *', local(1970,1,1,1,1, 9), 1 ], # 1 sec to 10s mark
462
- [ '*/10 * * * * *', local(1970,1,1,1,1,10), 0 ], # 0 sec to 10s mark
463
- [ '*/10 * * * * *', local(1970,1,1,1,1,11), 9 ], # 9 sec to 20s mark
464
- [ '*/10 * * * * *', local(1970,1,1,1,1,19), 1 ], # 1 sec to 20s mark
465
- [ '*/10 * * * * *', local(1970,1,1,1,1,20), 0 ], # 0 sec to 20s mark
466
- [ '*/10 * * * * *', local(1970,1,1,1,1,21), 9 ], # 1 sec to 30s mark
467
- # ...
468
- [ '*/10 * * * * *', local(1970,1,1,1,1,49), 1 ], # 9 sec to 50s mark
469
- [ '*/10 * * * * *', local(1970,1,1,1,1,50), 0 ], # 0 sec to 50s mark
470
- [ '*/10 * * * * *', local(1970,1,1,1,1,51), 9 ],
471
- ].each do |cronline, now, sec|
472
- it "ensures that next_second('#{cronline}', #{now}) is #{sec}" do
473
- expect(ns(cronline,now)).to eq(sec)
474
- end
475
- end
476
- end
477
-
478
- describe '#prev_second' do
479
-
480
- it 'returns the time to the closest previous second' do
481
-
482
- t = local(1970, 1, 1, 1, 1, 42)
483
-
484
- expect(ps('35,44 * * * * *', t)).to eq(7)
485
- end
486
-
487
- context 'when time sec is lower then all cron seconds (gh-177)' do
488
-
489
- it 'returns the time to the last second a minute before' do
490
-
491
- t = local(1970, 1, 1, 1, 1, 42)
492
-
493
- expect(ps('43,44 * * * * *', t)).to eq(58)
494
- end
495
- end
496
- end
497
-
498
- describe '#previous_time' do
499
-
500
- it 'returns the previous time the cron should have triggered' do
501
-
502
- expect(
503
- pt('* * * * sun', lo(1970, 1, 1))).to eq(lo(1969, 12, 28, 23, 59, 00))
504
- expect(
505
- pt('* * 13 * *', lo(1970, 1, 1))).to eq(lo(1969, 12, 13, 23, 59, 00))
506
- expect(
507
- pt('0 12 13 * *', lo(1970, 1, 1))).to eq(lo(1969, 12, 13, 12, 00))
508
- expect(
509
- pt('0 0 2 1 *', lo(1970, 1, 1))).to eq(lo(1969, 1, 2, 0, 00))
510
-
511
- expect(
512
- pt('* * * * * sun', lo(1970, 1, 1))).to eq(lo(1969, 12, 28, 23, 59, 59))
513
- end
514
-
515
- it 'jumps to the previous minute if necessary (gh-177)' do
516
-
517
- t = local(1970, 12, 31, 1, 1, 0) # vanilla
518
- expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 0, 44))
519
-
520
- t = local(1970, 12, 31, 1, 1, 30) # 30 < 43 <---- here!
521
- expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 0, 44))
522
-
523
- t = local(1970, 12, 31, 1, 1, 43) # 43 <= 43 < 44
524
- expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 0, 44))
525
-
526
- t = local(1970, 12, 31, 1, 1, 44) # 44 <= 44
527
- expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 1, 43))
528
-
529
- t = local(1970, 12, 31, 1, 1, 59) # 44 < 59
530
- expect(pt('43,44 * * * * *', t)).to eq(lo(1970, 12, 31, 1, 1, 44))
531
-
532
- t = local(1970, 12, 31, 1, 1, 30) # a bigger jump
533
- expect(pt('43,44 10 * * * *', t)).to eq(lo(1970, 12, 31, 0, 10, 44))
534
- end
535
-
536
- # New York EST: UTC-5
537
- # summer (dst) EDT: UTC-4
538
-
539
- # gh-127
540
- #
541
- it 'survives TZInfo::AmbiguousTime' do
542
-
543
- if ruby18? or jruby?
544
- expect(
545
- ptz(
546
- '30 1 31 10 * America/New_York',
547
- ltz('America/New_York', 2004, 10, 31, 14, 30, 0)
548
- ).strftime('%Y-%m-%d %H:%M:%S')
549
- ).to eq('2004-10-31 01:30:00')
550
- else
551
- expect(
552
- ptz(
553
- '30 1 31 10 * America/New_York',
554
- ltz('America/New_York', 2004, 10, 31, 14, 30, 0)
555
- )
556
- ).to eq(
557
- ltz('America/New_York', 0, 30, 1, 31, 10, 2004, nil, nil, false, nil)
558
- # EST time UTC-5
559
- )
560
- end
561
- end
562
-
563
- # gh-127
564
- #
565
- it 'survives TZInfo::PeriodNotFound' do
566
-
567
- expect(
568
- ptz(
569
- '0 2 9 3 * America/New_York',
570
- ltz('America/New_York', 2015, 3, 9, 12, 0, 0)
571
- )
572
- ).to eq(ltz('America/New_York', 2015, 3, 9, 2, 0, 0))
573
- end
574
-
575
- it 'computes correctly when * 0,10,20' do
576
-
577
- expect(
578
- pt('* 0,10,20 * * *', lo(2000, 1, 1))).to eq(
579
- lo(1999, 12, 31, 20, 59, 00))
580
- end
581
-
582
- it 'computes correctly when * */10' do
583
-
584
- expect(
585
- pt('* */10 * * *', lo(2000, 1, 1))).to eq(
586
- lo(1999, 12, 31, 20, 59, 00))
587
- end
588
- end
589
-
590
- describe '#matches?' do
591
-
592
- # it 'matches correctly in UTC (TZ not specified)' do
593
- #
594
- # match '* * * * *', utc(1970, 1, 1, 0, 1)
595
- # match '* * * * sun', utc(1970, 1, 4)
596
- # match '* * * * * *', utc(1970, 1, 1, 0, 0, 1)
597
- # match '* * 13 * fri', utc(1970, 2, 13)
598
- #
599
- # match '10 12 13 12 *', utc(1970, 12, 13, 12, 10)
600
- # match '* * 1 6 *', utc(1970, 6, 1)
601
- #
602
- # match '0 0 * * thu', utc(1970, 1, 8)
603
- #
604
- # match '0 0 1 1 *', utc(2012, 1, 1)
605
- # no_match '0 0 1 1 *', utc(2012, 1, 1, 1, 0)
606
- # end
607
-
608
- it 'matches correctly in local TZ (TZ not specified)' do
609
-
610
- match '* * * * *', local(1970, 1, 1, 0, 1)
611
- match '* * * * sun', local(1970, 1, 4)
612
- match '* * * * * *', local(1970, 1, 1, 0, 0, 1)
613
- match '* * 13 * fri', local(1970, 2, 13)
614
-
615
- match '10 12 13 12 *', local(1970, 12, 13, 12, 10)
616
- match '* * 1 6 *', local(1970, 6, 1)
617
-
618
- match '0 0 * * thu', local(1970, 1, 8)
619
-
620
- match '0 0 1 1 *', local(2012, 1, 1)
621
- no_match '0 0 1 1 *', local(2012, 1, 1, 1, 0)
622
- end
623
-
624
- it 'matches correctly in UTC (TZ specified)' do
625
-
626
- zone = 'Europe/Stockholm'
627
-
628
- match "* * * * * #{zone}", utc(1969, 12, 31, 23, 1)
629
- match "* * * * sun #{zone}", utc(1970, 1, 3, 23)
630
- match "* * * * * * #{zone}", utc(1969, 12, 31, 23, 0, 1)
631
- match "* * 13 * fri #{zone}", utc(1970, 2, 12, 23)
632
-
633
- match "10 12 13 12 * #{zone}", utc(1970, 12, 13, 11, 10)
634
- match "* * 1 6 * #{zone}", utc(1970, 5, 31, 23)
635
-
636
- match "0 0 * * thu #{zone}", utc(1970, 1, 7, 23)
637
- end
638
-
639
- it 'matches correctly when there is a sun#2 involved' do
640
-
641
- match '* * 13 * fri#2', utc(1970, 2, 13)
642
- no_match '* * 13 * fri#2', utc(1970, 2, 20)
643
- end
644
-
645
- it 'matches correctly when there is a L involved' do
646
-
647
- match '* * L * *', utc(1970, 1, 31)
648
- no_match '* * L * *', utc(1970, 1, 30)
649
- end
650
-
651
- it 'matches correctly when there is a sun#2,sun#3 involved' do
652
-
653
- no_match '* * * * sun#2,sun#3', local(1970, 1, 4)
654
- match '* * * * sun#2,sun#3', local(1970, 1, 11)
655
- match '* * * * sun#2,sun#3', local(1970, 1, 18)
656
- no_match '* * * * sun#2,sun#3', local(1970, 1, 25)
657
- end
658
-
659
- it 'matches correctly for seconds' do
660
-
661
- match '* * * * * *', local(1970, 1, 11)
662
- match '* * * * * *', local(1970, 1, 11, 0, 0, 13)
663
- end
664
-
665
- it 'matches correctly for seconds / interval' do
666
-
667
- match '*/2 * * * * *', local(1970, 1, 11)
668
- match '*/5 * * * * *', local(1970, 1, 11)
669
- match '*/5 * * * * *', local(1970, 1, 11, 0, 0, 0)
670
- no_match '*/5 * * * * *', local(1970, 1, 11, 0, 0, 1)
671
- match '*/5 * * * * *', local(1970, 1, 11, 0, 0, 5)
672
- match '*/2 * * * * *', local(1970, 1, 11, 0, 0, 2)
673
- match '*/2 * * * * *', local(1970, 1, 11, 0, 0, 2, 500)
674
- end
675
- end
676
-
677
- describe '#monthdays' do
678
-
679
- it 'returns the appropriate "sun#2"-like string' do
680
-
681
- class Rufus::Scheduler::CronLine
682
- public :monthdays
683
- end
684
-
685
- cl = Rufus::Scheduler::CronLine.new('* * * * *')
686
-
687
- expect(cl.monthdays(local(1970, 1, 1))).to eq(%w[ thu#1 thu#-5 ])
688
- expect(cl.monthdays(local(1970, 1, 7))).to eq(%w[ wed#1 wed#-4 ])
689
- expect(cl.monthdays(local(1970, 1, 14))).to eq(%w[ wed#2 wed#-3 ])
690
-
691
- expect(cl.monthdays(local(2011, 3, 11))).to eq(%w[ fri#2 fri#-3 ])
692
- end
693
- end
694
-
695
- describe '#frequency' do
696
-
697
- it 'returns the shortest delta between two occurrences' do
698
-
699
- expect(Rufus::Scheduler::CronLine.new(
700
- '* * * * *').frequency).to eq(60)
701
- expect(Rufus::Scheduler::CronLine.new(
702
- '* * * * * *').frequency).to eq(1)
703
-
704
- expect(Rufus::Scheduler::CronLine.new(
705
- '5 23 * * *').frequency).to eq(24 * 3600)
706
- expect(Rufus::Scheduler::CronLine.new(
707
- '5 * * * *').frequency).to eq(3600)
708
- expect(Rufus::Scheduler::CronLine.new(
709
- '10,20,30 * * * *').frequency).to eq(600)
710
-
711
- expect(Rufus::Scheduler::CronLine.new(
712
- '10,20,30 * * * * *').frequency).to eq(10)
713
- end
714
-
715
- it 'spots B-A vs C-B asymmetry in five-field forms' do
716
-
717
- expect(Rufus::Scheduler::CronLine.new(
718
- '10,17,30 * * * *').frequency).to eq(7 * 60)
719
- expect(Rufus::Scheduler::CronLine.new(
720
- '10,23,30 * * * *').frequency).to eq(7 * 60)
721
- expect(Rufus::Scheduler::CronLine.new(
722
- '23,10,30 * * * *').frequency).to eq(7 * 60)
723
- end
724
-
725
- it 'spots B-A vs C-B asymmetry in six-field forms' do
726
-
727
- expect(Rufus::Scheduler::CronLine.new(
728
- '10,17,30 * * * * *').frequency).to eq(7)
729
- expect(Rufus::Scheduler::CronLine.new(
730
- '10,23,30 * * * * *').frequency).to eq(7)
731
- expect(Rufus::Scheduler::CronLine.new(
732
- '23,10,30 * * * * *').frequency).to eq(7)
733
- end
734
-
735
- it 'handles crontab steps syntax in five-field forms' do
736
-
737
- expect(Rufus::Scheduler::CronLine.new(
738
- '*/10 * * * *').frequency).to eq(10 * 60)
739
- expect(Rufus::Scheduler::CronLine.new(
740
- '* */10 * * *').frequency).to eq(60) # "*" all minutes [0..59]
741
- expect(Rufus::Scheduler::CronLine.new(
742
- '0 */10 * * *').frequency).to eq(4 * 60 * 60) # 2000 to 0000
743
- end
744
-
745
- it 'handles crontab steps syntax in six-field forms' do
746
-
747
- expect(Rufus::Scheduler::CronLine.new(
748
- '*/10 * * * * *').frequency).to eq(10)
749
- expect(Rufus::Scheduler::CronLine.new(
750
- '* */10 * * * *').frequency).to eq(1) # "*" all seconds [0..59]
751
- expect(Rufus::Scheduler::CronLine.new(
752
- '0 */10 * * * *').frequency).to eq(10 * 60)
753
- end
754
- end
755
-
756
- describe '#brute_frequency' do
757
-
758
- it 'returns the shortest delta between two occurrences' do
759
-
760
- expect(Rufus::Scheduler::CronLine.new(
761
- '* * * * *').brute_frequency).to eq(60)
762
- expect(Rufus::Scheduler::CronLine.new(
763
- '* * * * * *').brute_frequency).to eq(1)
764
-
765
- expect(Rufus::Scheduler::CronLine.new(
766
- '5 23 * * *').brute_frequency).to eq(24 * 3600)
767
- expect(Rufus::Scheduler::CronLine.new(
768
- '5 * * * *').brute_frequency).to eq(3600)
769
- expect(Rufus::Scheduler::CronLine.new(
770
- '10,20,30 * * * *').brute_frequency).to eq(600)
771
-
772
- #Rufus::Scheduler::CronLine.new(
773
- # '10,20,30 * * * * *').brute_frequency.should == 10
774
- #
775
- # takes > 20s ...
776
- end
777
-
778
- # some combos only appear every other year...
779
- #
780
- it 'does not go into an infinite loop' do
781
-
782
- expect(Rufus::Scheduler::CronLine.new(
783
- '1 2 3 4 5').brute_frequency).to eq(31622400)
784
- end
785
-
786
- it 'spots B-A vs C-B asymmetry in five-field forms' do
787
-
788
- expect(Rufus::Scheduler::CronLine.new(
789
- '10,17,30 * * * *').brute_frequency).to eq(7 * 60)
790
- expect(Rufus::Scheduler::CronLine.new(
791
- '10,23,30 * * * *').brute_frequency).to eq(7 * 60)
792
- end
793
-
794
- it 'spots B-A vs C-B asymmetry in six-field forms' do
795
-
796
- expect(Rufus::Scheduler::CronLine.new(
797
- '10,17,30 * * * * *').brute_frequency).to eq(7)
798
- expect(Rufus::Scheduler::CronLine.new(
799
- '10,23,30 * * * * *').brute_frequency).to eq(7)
800
- end
801
-
802
- it 'handles crontab modulo syntax in five-field forms' do
803
-
804
- expect(Rufus::Scheduler::CronLine.new(
805
- '*/10 * * * *').brute_frequency).to eq(10 * 60)
806
- expect(Rufus::Scheduler::CronLine.new(
807
- '* */10 * * *').brute_frequency).to eq(60) # "*" all minutes [0..59]
808
- expect(Rufus::Scheduler::CronLine.new(
809
- '0 */10 * * *').brute_frequency).to eq(4 * 60 * 60) # 2000 to 0000
810
- end
811
-
812
- it 'handles crontab modulo syntax in six-field forms' do
813
-
814
- expect(Rufus::Scheduler::CronLine.new(
815
- '*/10 * * * * *').brute_frequency).to eq(10)
816
- expect(Rufus::Scheduler::CronLine.new(
817
- '* */10 * * * *').brute_frequency).to eq(1) # "*" all seconds [0..59]
818
- expect(Rufus::Scheduler::CronLine.new(
819
- '0 */10 * * * *').brute_frequency).to eq(10 * 60)
820
- end
821
- end
822
-
823
- context 'summer time' do
824
-
825
- # let's assume summer time jumps always occur on sundays
826
-
827
- # cf gh-114
828
- #
829
- it 'schedules correctly through a switch into summer time' do
830
-
831
- in_zone 'Europe/Berlin' do
832
-
833
- # find the summer jump
834
-
835
- j = Time.parse('2014-02-28 12:00')
836
- loop do
837
- jj = j + 24 * 3600
838
- break if jj.isdst
839
- j = jj
840
- end
841
-
842
- # test
843
-
844
- friday = j - 24 * 3600 # one day before
845
-
846
- # verify the playground...
847
- #
848
- expect(friday.isdst).to eq(false)
849
- expect((friday + 24 * 3600 * 3).isdst).to eq(true)
850
-
851
- cl0 = Rufus::Scheduler::CronLine.new('02 00 * * 1,2,3,4,5')
852
- cl1 = Rufus::Scheduler::CronLine.new('45 08 * * 1,2,3,4,5')
853
-
854
- n0 = cl0.next_time(friday)
855
- n1 = cl1.next_time(friday)
856
-
857
- expect(n0.strftime('%H:%M:%S %^a')).to eq('00:02:00 TUE')
858
- expect(n1.strftime('%H:%M:%S %^a')).to eq('08:45:00 MON')
859
-
860
- expect(n0.isdst).to eq(true)
861
- expect(n1.isdst).to eq(true)
862
-
863
- expect(
864
- (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('23:02:00 FRI')
865
- expect(
866
- (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('07:45:00 FRI')
867
- end
868
- end
869
-
870
- it 'schedules correctly through a switch out of summer time' do
871
-
872
- in_zone 'Europe/Berlin' do
873
-
874
- # find the winter jump
875
-
876
- j = Time.parse('2014-08-31 12:00')
877
- loop do
878
- jj = j + 24 * 3600
879
- break if jj.isdst == false
880
- j = jj
881
- end
882
-
883
- # test
884
-
885
- friday = j - 24 * 3600 # one day before
886
-
887
- # verify the playground...
888
- #
889
- expect(friday.isdst).to eq(true)
890
- expect((friday + 24 * 3600 * 3).isdst).to eq(false)
891
-
892
- cl0 = Rufus::Scheduler::CronLine.new('02 00 * * 1,2,3,4,5')
893
- cl1 = Rufus::Scheduler::CronLine.new('45 08 * * 1,2,3,4,5')
894
-
895
- n0 = cl0.next_time(friday)
896
- n1 = cl1.next_time(friday)
897
-
898
- expect(n0.strftime('%H:%M:%S %^a')).to eq('00:02:00 MON')
899
- expect(n1.strftime('%H:%M:%S %^a')).to eq('08:45:00 MON')
900
-
901
- expect(n0.isdst).to eq(false)
902
- expect(n1.isdst).to eq(false)
903
-
904
- expect(
905
- (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('01:02:00 FRI')
906
- expect(
907
- (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('09:45:00 FRI')
908
- end
909
- end
910
-
911
- it 'correctly increments through a DST transition' do
912
-
913
- expect(
914
- nt('* * * * * America/Los_Angeles', Time.utc(2015, 3, 8, 9, 59))
915
- ).to eq(Time.utc(2015, 3, 8, 10, 00))
916
- end
917
-
918
- it 'correctly increments every minute through a DST transition' do
919
-
920
- in_zone 'America/Los_Angeles' do
921
-
922
- line = cl('* * * * * America/Los_Angeles')
923
-
924
- t = Time.local(2015, 3, 8, 1, 57)
925
-
926
- points =
927
- 4.times.collect do
928
- t = line.next_time(t)
929
- t.to_compact_s
930
- end
931
-
932
- expect(points).to eq([
933
- '0158-8(0958)',
934
- '0159-8(0959)',
935
- '0300-7(1000)',
936
- '0301-7(1001)'
937
- ])
938
- end
939
- end
940
-
941
- it 'correctly decrements through a DST transition' do
942
-
943
- expect(
944
- pt('* * * * * America/Los_Angeles', Time.utc(2015, 3, 8, 10, 00))
945
- ).to eq(Time.utc(2015, 3, 8, 9, 59))
946
- end
947
-
948
- it 'correctly decrements every minute through a DST transition' do
949
-
950
- in_zone 'America/Los_Angeles' do
951
-
952
- line = cl('* * * * * America/Los_Angeles')
953
-
954
- t = Time.local(2015, 3, 8, 3, 2)
955
-
956
- points =
957
- 4.times.collect do
958
- t = line.previous_time(t)
959
- t.to_compact_s
960
- end
961
-
962
- expect(points).to eq([
963
- '0301-7(1001)',
964
- '0300-7(1000)',
965
- '0159-8(0959)',
966
- '0158-8(0958)'
967
- ])
968
- end
969
- end
970
-
971
- it 'correctly increments when entering DST' do
972
-
973
- in_zone 'America/Los_Angeles' do
974
-
975
- line = cl('*/10 * * * * America/Los_Angeles')
976
-
977
- t = Time.local(2015, 3, 8, 1, 40)
978
- t1 = t.dup
979
-
980
- points = []
981
- while t1 - t < 1 * 3600
982
- t1 = line.next_time(t1)
983
- points << t1.to_compact_s
984
- end
985
-
986
- expect(points).to eq(%w[
987
- 0150-8(0950)
988
- 0300-7(1000)
989
- 0310-7(1010)
990
- 0320-7(1020)
991
- 0330-7(1030)
992
- 0340-7(1040)
993
- ])
994
- end
995
- end
996
- end
997
-
998
- context 'fall time' do
999
-
1000
- it 'correctly increments through a DST transition' do
1001
-
1002
- expect(
1003
- nt('* * * * * America/Los_Angeles', Time.utc(2015, 11, 1, 9, 59))
1004
- ).to eq(Time.utc(2015, 11, 1, 10, 00))
1005
- end
1006
-
1007
- it 'correctly increments every minute through a DST transition' do
1008
-
1009
- in_zone 'America/Los_Angeles' do
1010
-
1011
- line = cl('* * * * * America/Los_Angeles')
1012
-
1013
- #t = Time.local(2015, 11, 1, 1, 57)
1014
- #
1015
- # --> 2015-11-01 01:57:00 -0800 (already PST)
1016
-
1017
- t = Time.local(0, 57, 1, 1, 11, 2015, nil, nil, true, nil)
1018
- #
1019
- # --> 2015-11-01 01:57:00 -0700 (still PDT)
1020
-
1021
- points =
1022
- 4.times.collect do
1023
- t = line.next_time(t)
1024
- t.to_compact_s
1025
- end
1026
-
1027
- expect(points).to eq([
1028
- '0158-7(0858)',
1029
- '0159-7(0859)',
1030
- '0100-8(0900)',
1031
- '0101-8(0901)'
1032
- ])
1033
- end
1034
- end
1035
-
1036
- it 'correctly decrements through a DST transition' do
1037
-
1038
- expect(
1039
- pt('* * * * * America/Los_Angeles', Time.utc(2015, 11, 1, 10, 00))
1040
- ).to eq(Time.utc(2015, 11, 1, 9, 59))
1041
- end
1042
-
1043
- it 'correctly decrements every minute through a DST transition' do
1044
-
1045
- in_zone 'America/Los_Angeles' do
1046
-
1047
- line = cl('* * * * * America/Los_Angeles')
1048
-
1049
- t = Time.local(0, 2, 1, 1, 11, 2015, nil, nil, true, nil)
1050
- #
1051
- # try to force PST
1052
-
1053
- # TODO: at some point, try to find out if the latest jRuby still
1054
- # exhibits that behaviour, report to them if necessary
1055
-
1056
- points =
1057
- (0..3).collect do
1058
- t = line.previous_time(t)
1059
- t.to_compact_s
1060
- end
1061
-
1062
- if t.zone == 'PST'
1063
- expect(points).to eq([
1064
- '0101-8(0901)',
1065
- '0100-8(0900)',
1066
- '0159-7(0859)',
1067
- '0158-7(0858)'
1068
- ])
1069
- else
1070
- expect(points).to eq([
1071
- '0101-7(0801)',
1072
- '0100-7(0800)',
1073
- '0059-7(0759)',
1074
- '0058-7(0758)'
1075
- ])
1076
- end
1077
- end
1078
- end
1079
-
1080
- it 'correctly increments when leaving DST' do
1081
-
1082
- in_zone 'America/Los_Angeles' do
1083
-
1084
- line = cl('*/10 * * * * America/Los_Angeles')
1085
-
1086
- t = Time.local(2015, 11, 1, 0, 40)
1087
- t1 = t.dup
1088
-
1089
- points = []
1090
- while t1 - t < 2 * 3600
1091
- t1 = line.next_time(t1)
1092
- points << t1.to_compact_s
1093
- end
1094
-
1095
- expect(points).to eq([
1096
- '0050-7(0750)', # | PDT
1097
- '0100-7(0800)', # |
1098
- '0110-7(0810)', # V
1099
- '0120-7(0820)',
1100
- '0130-7(0830)',
1101
- '0140-7(0840)',
1102
- '0150-7(0850)',
1103
- '0100-8(0900)', # + PST
1104
- '0110-8(0910)', # |
1105
- '0120-8(0920)', # V
1106
- '0130-8(0930)',
1107
- '0140-8(0940)'
1108
- ])
1109
- end
1110
- end
1111
- end
1112
- end
1113
-