2014-06-13 21:01:52 +04:00
package cron
import (
"fmt"
"sync"
"testing"
"time"
)
// Many tests schedule a job for every second, and then wait at most a second
// for it to run. This amount is just slightly larger than 1 second to
// compensate for a few milliseconds of runtime.
const ONE_SECOND = 1 * time . Second + 10 * time . Millisecond
// Start and stop cron with no entries.
func TestNoEntries ( t * testing . T ) {
cron := New ( )
cron . Start ( )
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- stop ( cron ) :
}
}
// Start, stop, then add an entry. Verify entry doesn't run.
func TestStopCausesJobsToNotRun ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 1 )
cron := New ( )
cron . Start ( )
cron . Stop ( )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
select {
case <- time . After ( ONE_SECOND ) :
// No job ran!
case <- wait ( wg ) :
t . FailNow ( )
}
}
// Add a job, start cron, expect it runs.
func TestAddBeforeRunning ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 1 )
cron := New ( )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
cron . Start ( )
defer cron . Stop ( )
// Give cron 2 seconds to run our job (which is always activated).
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
// Start cron, add a job, expect it runs.
func TestAddWhileRunning ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 1 )
cron := New ( )
cron . Start ( )
defer cron . Stop ( )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
// Test timing with Entries.
func TestSnapshotEntries ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 1 )
cron := New ( )
cron . AddFunc ( "" , "@every 2s" , func ( ) { wg . Done ( ) } )
cron . Start ( )
defer cron . Stop ( )
// Cron should fire in 2 seconds. After 1 second, call Entries.
select {
case <- time . After ( ONE_SECOND ) :
cron . Entries ( )
}
// Even though Entries was called, the cron should fire at the 2 second mark.
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
// Test that the entries are correctly sorted.
// Add a bunch of long-in-the-future entries, and an immediate entry, and ensure
// that the immediate entry runs immediately.
// Also: Test that multiple jobs run in the same instant.
func TestMultipleEntries ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 2 )
cron := New ( )
cron . AddFunc ( "" , "0 0 0 1 1 ?" , func ( ) { } )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
cron . AddFunc ( "" , "0 0 0 31 12 ?" , func ( ) { } )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
cron . Start ( )
defer cron . Stop ( )
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
// Test running the same job twice.
func TestRunningJobTwice ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 2 )
cron := New ( )
cron . AddFunc ( "" , "0 0 0 1 1 ?" , func ( ) { } )
cron . AddFunc ( "" , "0 0 0 31 12 ?" , func ( ) { } )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
cron . Start ( )
defer cron . Stop ( )
select {
case <- time . After ( 2 * ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
func TestRunningMultipleSchedules ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 2 )
cron := New ( )
cron . AddFunc ( "" , "0 0 0 1 1 ?" , func ( ) { } )
cron . AddFunc ( "" , "0 0 0 31 12 ?" , func ( ) { } )
cron . AddFunc ( "" , "* * * * * ?" , func ( ) { wg . Done ( ) } )
2014-06-17 07:19:25 +04:00
cron . Schedule ( "" , "" , Every ( time . Minute ) , FuncJob ( func ( ) { } ) )
cron . Schedule ( "" , "" , Every ( time . Second ) , FuncJob ( func ( ) { wg . Done ( ) } ) )
cron . Schedule ( "" , "" , Every ( time . Hour ) , FuncJob ( func ( ) { } ) )
2014-06-13 21:01:52 +04:00
cron . Start ( )
defer cron . Stop ( )
select {
case <- time . After ( 2 * ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
// Test that the cron is run in the local time zone (as opposed to UTC).
func TestLocalTimezone ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 1 )
now := time . Now ( ) . Local ( )
spec := fmt . Sprintf ( "%d %d %d %d %d ?" ,
now . Second ( ) + 1 , now . Minute ( ) , now . Hour ( ) , now . Day ( ) , now . Month ( ) )
cron := New ( )
cron . AddFunc ( "" , spec , func ( ) { wg . Done ( ) } )
cron . Start ( )
defer cron . Stop ( )
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
}
type testJob struct {
wg * sync . WaitGroup
name string
}
func ( t testJob ) Run ( ) {
t . wg . Done ( )
}
// Simple test using Runnables.
func TestJob ( t * testing . T ) {
wg := & sync . WaitGroup { }
wg . Add ( 1 )
cron := New ( )
cron . AddJob ( "" , "0 0 0 30 Feb ?" , testJob { wg , "job0" } )
cron . AddJob ( "" , "0 0 0 1 1 ?" , testJob { wg , "job1" } )
cron . AddJob ( "" , "* * * * * ?" , testJob { wg , "job2" } )
cron . AddJob ( "" , "1 0 0 1 1 ?" , testJob { wg , "job3" } )
2014-06-17 07:19:25 +04:00
cron . Schedule ( "" , "" , Every ( 5 * time . Second + 5 * time . Nanosecond ) , testJob { wg , "job4" } )
cron . Schedule ( "" , "" , Every ( 5 * time . Minute ) , testJob { wg , "job5" } )
2014-06-13 21:01:52 +04:00
cron . Start ( )
defer cron . Stop ( )
select {
case <- time . After ( ONE_SECOND ) :
t . FailNow ( )
case <- wait ( wg ) :
}
// Ensure the entries are in the right order.
expecteds := [ ] string { "job2" , "job4" , "job5" , "job1" , "job3" , "job0" }
var actuals [ ] string
for _ , entry := range cron . Entries ( ) {
actuals = append ( actuals , entry . Job . ( testJob ) . name )
}
for i , expected := range expecteds {
if actuals [ i ] != expected {
t . Errorf ( "Jobs not in the right order. (expected) %s != %s (actual)" , expecteds , actuals )
t . FailNow ( )
}
}
}
func wait ( wg * sync . WaitGroup ) chan bool {
ch := make ( chan bool )
go func ( ) {
wg . Wait ( )
ch <- true
} ( )
return ch
}
func stop ( cron * Cron ) chan bool {
ch := make ( chan bool )
go func ( ) {
cron . Stop ( )
ch <- true
} ( )
return ch
}