256 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			256 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			Go
		
	
	
	
| 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() })
 | |
| 	cron.Schedule("", "", Every(time.Minute), FuncJob(func() {}))
 | |
| 	cron.Schedule("", "", Every(time.Second), FuncJob(func() { wg.Done() }))
 | |
| 	cron.Schedule("", "", Every(time.Hour), FuncJob(func() {}))
 | |
| 
 | |
| 	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"})
 | |
| 	cron.Schedule("", "", Every(5*time.Second+5*time.Nanosecond), testJob{wg, "job4"})
 | |
| 	cron.Schedule("", "", Every(5*time.Minute), testJob{wg, "job5"})
 | |
| 
 | |
| 	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
 | |
| }
 |