Skip to content

Commit

Permalink
Create/use a Job interface. Add a test.
Browse files Browse the repository at this point in the history
  • Loading branch information
robfig committed Jul 20, 2012
1 parent f6244e2 commit bd4b092
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 9 deletions.
20 changes: 17 additions & 3 deletions cron.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@ type Cron struct {
add chan *Entry
}

// Simple interface for submitted cron jobs.
type Job interface {
Run()
}

// A cron entry consists of a schedule and the func to execute on that schedule.
type Entry struct {
*Schedule
Next time.Time
Func func()
Job Job
}

type byTime []*Entry
Expand Down Expand Up @@ -48,7 +53,16 @@ func New() *Cron {
}
}

func (c *Cron) Add(spec string, cmd func()) {
// Provide a default implementation for those that want to run a simple func.
type jobAdapter func()

func (r jobAdapter) Run() { r() }

func (c *Cron) AddFunc(spec string, cmd func()) {
c.AddJob(spec, jobAdapter(cmd))
}

func (c *Cron) AddJob(spec string, cmd Job) {
entry := &Entry{Parse(spec), time.Time{}, cmd}
select {
case c.add <- entry:
Expand Down Expand Up @@ -92,7 +106,7 @@ func (c *Cron) Run() {
if e.Next != effective {
break
}
go e.Func()
go e.Job.Run()
e.Next = e.Schedule.Next(effective)
}

Expand Down
46 changes: 40 additions & 6 deletions cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestNoEntries(t *testing.T) {
// Add a job, start cron, expect it runs.
func TestAddBeforeRunning(t *testing.T) {
cron := New()
cron.Add("* * * * * ?", func() {
cron.AddFunc("* * * * * ?", func() {
cron.Stop()
})
done := startAndSignal(cron)
Expand All @@ -40,7 +40,7 @@ func TestAddWhileRunning(t *testing.T) {
cron := New()
done := startAndSignal(cron)
go func() {
cron.Add("* * * * * ?", func() {
cron.AddFunc("* * * * * ?", func() {
cron.Stop()
})
}()
Expand All @@ -57,11 +57,11 @@ func TestAddWhileRunning(t *testing.T) {
// that the immediate entry runs immediately.
func TestMultipleEntries(t *testing.T) {
cron := New()
cron.Add("0 0 0 1 1 ?", func() {})
cron.Add("* * * * * ?", func() {
cron.AddFunc("0 0 0 1 1 ?", func() {})
cron.AddFunc("* * * * * ?", func() {
cron.Stop()
})
cron.Add("0 0 0 31 12 ?", func() {})
cron.AddFunc("0 0 0 31 12 ?", func() {})
done := startAndSignal(cron)

select {
Expand All @@ -77,7 +77,7 @@ func TestLocalTimezone(t *testing.T) {
now := time.Now().Local()
spec := fmt.Sprintf("%d %d %d %d %d ?",
now.Second()+1, now.Minute(), now.Hour(), now.Day(), now.Month())
cron.Add(spec, func() { cron.Stop() })
cron.AddFunc(spec, func() { cron.Stop() })
done := startAndSignal(cron)

select {
Expand All @@ -87,6 +87,40 @@ func TestLocalTimezone(t *testing.T) {
}
}

type testRunnable struct {
cron *Cron
name string
}

func (t testRunnable) Run() {
t.cron.Stop()
}

// Simple test using Runnables.
func TestRunnable(t *testing.T) {
cron := New()
cron.AddJob("0 0 0 30 Feb ?", testRunnable{cron, "job0"})
cron.AddJob("0 0 0 1 1 ?", testRunnable{cron, "job1"})
cron.AddJob("* * * * * ?", testRunnable{cron, "job2"})
cron.AddJob("1 0 0 1 1 ?", testRunnable{cron, "job3"})

done := startAndSignal(cron)
select {
case <-time.After(2 * time.Second):
t.FailNow()
case <-done:
}

// Ensure the entries are in the right order.
answers := []string{"job2", "job1", "job3", "job0"}
for i, answer := range answers {
actual := cron.Entries[i].Job.(testRunnable).name
if actual != answer {
t.Errorf("Jobs not in the right order. (expected) %s != %s (actual)", answer, actual)
}
}
}

// Return a channel that signals when the cron's Start() method returns.
func startAndSignal(cron *Cron) <-chan struct{} {
ch := make(chan struct{})
Expand Down

0 comments on commit bd4b092

Please sign in to comment.