rufus-scheduler 3.1.9 → 3.1.10

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-