| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 | package cronimport (	"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}
 |