spec/cronline_spec.rb in rufus-scheduler-3.0.9 vs spec/cronline_spec.rb in rufus-scheduler-3.1.0

- old
+ new

@@ -3,20 +3,37 @@ # Specifying rufus-scheduler # # Sat Mar 21 12:55:27 JST 2009 # -require 'tzinfo' require 'spec_helper' describe Rufus::Scheduler::CronLine do def cl(cronline_string) Rufus::Scheduler::CronLine.new(cronline_string) end + def nt(cronline, now) + Rufus::Scheduler::CronLine.new(cronline).next_time(now) + end + def ntz(cronline, now) + tz = cronline.split.last + tu = nt(cronline, now).utc + in_zone(tz) { tu.getlocal } + end + + def pt(cronline, now) + Rufus::Scheduler::CronLine.new(cronline).previous_time(now) + end + def ptz(cronline, now) + tz = cronline.split.last + tu = pt(cronline, now).utc + in_zone(tz) { tu.getlocal } + end + def match(line, time) expect(cl(line).matches?(time)).to eq(true) end def no_match(line, time) expect(cl(line).matches?(time)).to eq(false) @@ -47,16 +64,24 @@ to_a '7 10-12 * * * *', [ [7], [10, 11, 12], nil, nil, nil, nil, nil, nil ] to_a '1-5 * * * * *', [ [1,2,3,4,5], nil, nil, nil, nil, nil, nil, nil ] to_a '0 0 1 1 *', [ [0], [0], [0], [1], [1], nil, nil, nil ] - to_a '0 23-24 * * *', [ [0], [0], [23, 0], nil, nil, nil, nil, nil ] + if ruby18? + to_a '0 23-24 * * *', [ [0], [0], [0, 23], nil, nil, nil, nil, nil ] + else + to_a '0 23-24 * * *', [ [0], [0], [23, 0], nil, nil, nil, nil, nil ] + end # # as reported by Aimee Rose in # https://github.com/jmettraux/rufus-scheduler/issues/56 - to_a '0 23-2 * * *', [ [0], [0], [23, 0, 1, 2], nil, nil, nil, nil, nil ] + if ruby18? + to_a '0 23-2 * * *', [ [0], [0], [0, 1, 2, 23], nil, nil, nil, nil, nil ] + else + to_a '0 23-2 * * *', [ [0], [0], [23, 0, 1, 2], nil, nil, nil, nil, nil ] + end end it 'rejects invalid weekday expressions' do expect { cl '0 17 * * MON_FRI' }.to raise_error @@ -90,12 +115,15 @@ it 'interprets cron strings with / (slashes) correctly' do to_a( '0 */2 * * *', - [ [0], [0], (0..11).collect { |e| e * 2 }, nil, nil, nil, nil, nil ]) + [ [0], [0], (0..23).select { |e| e.even? }, nil, nil, nil, nil, nil ]) to_a( + '0 0-23/2 * * *', + [ [0], [0], (0..23).select { |e| e.even? }, nil, nil, nil, nil, nil ]) + to_a( '0 7-23/2 * * *', [ [0], [0], (7..23).select { |e| e.odd? }, nil, nil, nil, nil, nil ]) to_a( '*/10 * * * *', [ [0], [0, 10, 20, 30, 40, 50], nil, nil, nil, nil, nil, nil ]) @@ -187,60 +215,38 @@ end end describe '#next_time' do - def nt(cronline, now) - Rufus::Scheduler::CronLine.new(cronline).next_time(now) - end - def ntz(cronline, now) - tz = cronline.split.last - tu = nt(cronline, now).utc - in_zone(tz) { tu.getlocal } - end - it 'computes the next occurence correctly' do - now = Time.at(0).getutc # Thu Jan 01 00:00:00 UTC 1970 + in_zone 'Europe/Berlin' do - expect(nt('* * * * *', now)).to eq(now + 60) - expect(nt('* * * * sun', now)).to eq(now + 259200) - expect(nt('* * * * * *', now)).to eq(now + 1) - expect(nt('* * 13 * fri', now)).to eq(now + 3715200) + now = Time.at(0) - 3600 - expect(nt('10 12 13 12 *', now)).to eq(now + 29938200) - # this one is slow (1 year == 3 seconds) - # - # historical note: - # (comment made in 2006 or 2007, the underlying libs got better and - # that slowness is gone) + expect(nt('* * * * *', now)).to eq(now + 60) + expect(nt('* * * * sun', now)).to eq(now + 259200) + expect(nt('* * * * * *', now)).to eq(now + 1) + expect(nt('* * 13 * fri', now)).to eq(now + 3715200) - expect(nt('0 0 * * thu', now)).to eq(now + 604800) - expect(nt('00 0 * * thu', now)).to eq(now + 604800) + expect(nt('10 12 13 12 *', now)).to eq(now + 29938200) + # this one is slow (1 year == 3 seconds) + # + # historical note: + # (comment made in 2006 or 2007, the underlying libs got better and + # that slowness is gone) - expect(nt('0 0 * * *', now)).to eq(now + 24 * 3600) - expect(nt('0 24 * * *', now)).to eq(now + 24 * 3600) + expect(nt('0 0 * * thu', now)).to eq(now + 604800) + expect(nt('00 0 * * thu', now)).to eq(now + 604800) - now = local(2008, 12, 31, 23, 59, 59, 0) + expect(nt('0 0 * * *', now)).to eq(now + 24 * 3600) + expect(nt('0 24 * * *', now)).to eq(now + 24 * 3600) - expect(nt('* * * * *', now)).to eq(now + 1) - end + now = local(2008, 12, 31, 23, 59, 59, 0) - it 'computes the next occurence correctly in UTC (TZ not specified)' do - - now = utc(1970, 1, 1) - - expect(nt('* * * * *', now)).to eq(utc(1970, 1, 1, 0, 1)) - expect(nt('* * * * sun', now)).to eq(utc(1970, 1, 4)) - expect(nt('* * * * * *', now)).to eq(utc(1970, 1, 1, 0, 0, 1)) - expect(nt('* * 13 * fri', now)).to eq(utc(1970, 2, 13)) - - expect(nt('10 12 13 12 *', now)).to eq(utc(1970, 12, 13, 12, 10)) - # this one is slow (1 year == 3 seconds) - expect(nt('* * 1 6 *', now)).to eq(utc(1970, 6, 1)) - - expect(nt('0 0 * * thu', now)).to eq(utc(1970, 1, 8)) + expect(nt('* * * * *', now)).to eq(now + 1) + end end it 'computes the next occurence correctly in local TZ (TZ not specified)' do now = local(1970, 1, 1) @@ -258,13 +264,11 @@ end it 'computes the next occurence correctly in UTC (TZ specified)' do zone = 'Europe/Stockholm' - tz = TZInfo::Timezone.get(zone) - now = tz.local_to_utc(local(1970, 1, 1)) - # Midnight in zone, UTC + now = in_zone(zone) { Time.local(1970, 1, 1) } expect(nt("* * * * * #{zone}", now)).to eq(utc(1969, 12, 31, 23, 1)) expect(nt("* * * * sun #{zone}", now)).to eq(utc(1970, 1, 3, 23)) expect(nt("* * * * * * #{zone}", now)).to eq(utc(1969, 12, 31, 23, 0, 1)) expect(nt("* * 13 * fri #{zone}", now)).to eq(utc(1970, 2, 12, 23)) @@ -273,24 +277,10 @@ expect(nt("* * 1 6 * #{zone}", now)).to eq(utc(1970, 5, 31, 23)) expect(nt("0 0 * * thu #{zone}", now)).to eq(utc(1970, 1, 7, 23)) end - #it 'computes the next occurence correctly in local TZ (TZ specified)' do - # zone = 'Europe/Stockholm' - # tz = TZInfo::Timezone.get(zone) - # now = tz.local_to_utc(utc(1970, 1, 1)).localtime - # # Midnight in zone, local time - # nt("* * * * * #{zone}", now).should == local(1969, 12, 31, 18, 1) - # nt("* * * * sun #{zone}", now).should == local(1970, 1, 3, 18) - # nt("* * * * * * #{zone}", now).should == local(1969, 12, 31, 18, 0, 1) - # nt("* * 13 * fri #{zone}", now).should == local(1970, 2, 12, 18) - # nt("10 12 13 12 * #{zone}", now).should == local(1970, 12, 13, 6, 10) - # nt("* * 1 6 * #{zone}", now).should == local(1970, 5, 31, 19) - # nt("0 0 * * thu #{zone}", now).should == local(1970, 1, 7, 18) - #end - it 'computes the next time correctly when there is a sun#2 involved' do expect(nt('* * * * sun#1', local(1970, 1, 1))).to eq(local(1970, 1, 4)) expect(nt('* * * * sun#2', local(1970, 1, 1))).to eq(local(1970, 1, 11)) @@ -373,19 +363,10 @@ end end describe '#previous_time' do - def pt(cronline, now) - Rufus::Scheduler::CronLine.new(cronline).previous_time(now) - end - def ptz(cronline, now) - tz = cronline.split.last - tu = pt(cronline, now).utc - in_zone(tz) { tu.getlocal } - end - it 'returns the previous time the cron should have triggered' do expect( pt('* * * * sun', lo(1970, 1, 1))).to eq(lo(1969, 12, 28, 23, 59, 00)) expect( @@ -436,26 +417,26 @@ end end describe '#matches?' do - it 'matches correctly in UTC (TZ not specified)' do +# it 'matches correctly in UTC (TZ not specified)' do +# +# match '* * * * *', utc(1970, 1, 1, 0, 1) +# match '* * * * sun', utc(1970, 1, 4) +# match '* * * * * *', utc(1970, 1, 1, 0, 0, 1) +# match '* * 13 * fri', utc(1970, 2, 13) +# +# match '10 12 13 12 *', utc(1970, 12, 13, 12, 10) +# match '* * 1 6 *', utc(1970, 6, 1) +# +# match '0 0 * * thu', utc(1970, 1, 8) +# +# match '0 0 1 1 *', utc(2012, 1, 1) +# no_match '0 0 1 1 *', utc(2012, 1, 1, 1, 0) +# end - match '* * * * *', utc(1970, 1, 1, 0, 1) - match '* * * * sun', utc(1970, 1, 4) - match '* * * * * *', utc(1970, 1, 1, 0, 0, 1) - match '* * 13 * fri', utc(1970, 2, 13) - - match '10 12 13 12 *', utc(1970, 12, 13, 12, 10) - match '* * 1 6 *', utc(1970, 6, 1) - - match '0 0 * * thu', utc(1970, 1, 8) - - match '0 0 1 1 *', utc(2012, 1, 1) - no_match '0 0 1 1 *', utc(2012, 1, 1, 1, 0) - end - it 'matches correctly in local TZ (TZ not specified)' do match '* * * * *', local(1970, 1, 1, 0, 1) match '* * * * sun', local(1970, 1, 4) match '* * * * * *', local(1970, 1, 1, 0, 0, 1) @@ -544,61 +525,65 @@ describe '#frequency' do it 'returns the shortest delta between two occurrences' do expect(Rufus::Scheduler::CronLine.new( - '* * * * *').frequency).to eq(60) + '* * * * *').frequency).to eq(60) expect(Rufus::Scheduler::CronLine.new( - '* * * * * *').frequency).to eq(1) + '* * * * * *').frequency).to eq(1) expect(Rufus::Scheduler::CronLine.new( - '5 23 * * *').frequency).to eq(24 * 3600) + '5 23 * * *').frequency).to eq(24 * 3600) expect(Rufus::Scheduler::CronLine.new( - '5 * * * *').frequency).to eq(3600) + '5 * * * *').frequency).to eq(3600) expect(Rufus::Scheduler::CronLine.new( - '10,20,30 * * * *').frequency).to eq(600) + '10,20,30 * * * *').frequency).to eq(600) expect(Rufus::Scheduler::CronLine.new( - '10,20,30 * * * * *').frequency).to eq(10) + '10,20,30 * * * * *').frequency).to eq(10) end end describe '#brute_frequency' do it 'returns the shortest delta between two occurrences' do expect(Rufus::Scheduler::CronLine.new( - '* * * * *').brute_frequency).to eq(60) + '* * * * *').brute_frequency).to eq(60) expect(Rufus::Scheduler::CronLine.new( - '* * * * * *').brute_frequency).to eq(1) + '* * * * * *').brute_frequency).to eq(1) expect(Rufus::Scheduler::CronLine.new( - '5 23 * * *').brute_frequency).to eq(24 * 3600) + '5 23 * * *').brute_frequency).to eq(24 * 3600) expect(Rufus::Scheduler::CronLine.new( - '5 * * * *').brute_frequency).to eq(3600) + '5 * * * *').brute_frequency).to eq(3600) expect(Rufus::Scheduler::CronLine.new( - '10,20,30 * * * *').brute_frequency).to eq(600) + '10,20,30 * * * *').brute_frequency).to eq(600) #Rufus::Scheduler::CronLine.new( # '10,20,30 * * * * *').brute_frequency.should == 10 # # takes > 20s ... end + + # some combos only appear every other year... + # + it 'does not go into an infinite loop' do + + expect(Rufus::Scheduler::CronLine.new( + '1 2 3 4 5').brute_frequency).to eq(31622400) + end end context 'summer time' do # let's assume summer time jumps always occur on sundays # cf gh-114 # it 'schedules correctly through a switch into summer time' do - #j = `zdump -v Europe/Berlin | grep "Sun Mar" | grep 2014`.split("\n")[0] - #j = j.match(/^.+ (Sun Mar .+ UTC) /)[1] - # only works on system that have a zdump... - in_zone 'Europe/Berlin' do # find the summer jump j = Time.parse('2014-02-28 12:00') @@ -621,18 +606,18 @@ cl1 = Rufus::Scheduler::CronLine.new('45 08 * * 1,2,3,4,5') n0 = cl0.next_time(friday) n1 = cl1.next_time(friday) - expect(n0.strftime('%H:%M:%S %^a')).to eq('00:02:00 MON') + expect(n0.strftime('%H:%M:%S %^a')).to eq('00:02:00 TUE') expect(n1.strftime('%H:%M:%S %^a')).to eq('08:45:00 MON') expect(n0.isdst).to eq(true) expect(n1.isdst).to eq(true) expect( - (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('23:02:00 THU') + (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('23:02:00 FRI') expect( (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('07:45:00 FRI') end end @@ -672,9 +657,73 @@ expect( (n0 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('01:02:00 FRI') expect( (n1 - 24 * 3600 * 3).strftime('%H:%M:%S %^a')).to eq('09:45:00 FRI') + end + end + + it 'correctly increments through a DST transition' do + + expect( + nt('* * * * * America/Los_Angeles', Time.utc(2015, 3, 8, 9, 59)) + ).to eq(Time.utc(2015, 3, 8, 10, 00)) + end + + it 'correctly increments every minute through a DST transition' do + + in_zone 'America/Los_Angeles' do + + line = cl('* * * * * America/Los_Angeles') + + t = Time.local(2015, 3, 8, 1, 57) + + points = + [ 0, 1, 2, 3 ].collect do + t = line.next_time(t) + t.strftime('%H:%M:%Sl') + ' ' + t.dup.utc.strftime('%H:%M:%Su') + end + + expect(points).to eq( + [ + '01:58:00l 09:58:00u', + '01:59:00l 09:59:00u', + '03:00:00l 10:00:00u', + '03:01:00l 10:01:00u' + ] + ) + end + end + + it 'correctly decrements through a DST transition' do + + expect( + pt('* * * * * America/Los_Angeles', Time.utc(2015, 3, 8, 10, 00)) + ).to eq(Time.utc(2015, 3, 8, 9, 59)) + end + + it 'correctly decrements every minute through a DST transition' do + + in_zone 'America/Los_Angeles' do + + line = cl('* * * * * America/Los_Angeles') + + t = Time.local(2015, 3, 8, 3, 2) + + points = + [ 0, 1, 2, 3 ].collect do + t = line.previous_time(t) + t.strftime('%H:%M:%Sl') + ' ' + t.dup.utc.strftime('%H:%M:%Su') + end + + expect(points).to eq( + [ + '03:01:00l 10:01:00u', + '03:00:00l 10:00:00u', + '01:59:00l 09:59:00u', + '01:58:00l 09:58:00u' + ] + ) end end end end