Repository: go-co-op/gocron
Pull request #381 (2022-08-23 19:58:38)

add CustomTimer allowing overriding of the time.AfterFunc
### What does this do?


### Which issue(s) does this PR fix/relate to?
<!--- Put `Resolves #XXX` here to auto-close the issue that your PR fixes (if such) --->
Related to #377 

### List any changes that modify/break current functionality


### Have you included tests for your changes?


### Did you document any new/modified functionality?

- [ ] Updated `example_test.go`
- [ ] Updated `README.md`

### Notes



Patch:
diff --git a/scheduler.go b/scheduler.go
index 75fddf9..6c249c7 100644
--- a/scheduler.go
+++ b/scheduler.go
@@ -27,7 +27,8 @@ type Scheduler struct {
 	running       bool // represents if the scheduler is running at the moment or not
 
 	time     TimeWrapper // wrapper around time.Time
-	executor *executor   // executes jobs passed via chan
+	timer    func(d time.Duration, f func()) *time.Timer
+	executor *executor // executes jobs passed via chan
 
 	tags sync.Map // for storing tags when unique tags is set
 
@@ -55,6 +56,7 @@ func NewScheduler(loc *time.Location) *Scheduler {
 		time:       &trueTime{},
 		executor:   &executor,
 		tagsUnique: false,
+		timer:      afterFunc,
 	}
 }
 
@@ -569,7 +571,7 @@ func (s *Scheduler) runContinuous(job *Job) {
 		s.run(job)
 	}
 
-	job.setTimer(time.AfterFunc(next.duration, func() {
+	job.setTimer(s.timer(next.duration, func() {
 		if !next.dateTime.IsZero() {
 			for {
 				n := s.now().UnixNano() - next.dateTime.UnixNano()
@@ -1303,6 +1305,13 @@ func (s *Scheduler) CustomTime(customTimeWrapper TimeWrapper) {
 	s.time = customTimeWrapper
 }
 
+// CustomTimer takes in a function that mirrors the time.AfterFunc
+// This is used to mock the time.AfterFunc function used by the scheduler
+// for testing long intervals in a short amount of time.
+func (s *Scheduler) CustomTimer(customTimer func(d time.Duration, f func()) *time.Timer) {
+	s.timer = customTimer
+}
+
 func (s *Scheduler) StopBlockingChan() {
 	s.startBlockingStopChanMutex.Lock()
 	if s.startBlockingStopChan != nil {
diff --git a/timeHelper.go b/timeHelper.go
index f3ce956..487a7a2 100644
--- a/timeHelper.go
+++ b/timeHelper.go
@@ -25,3 +25,9 @@ func (t *trueTime) Unix(sec int64, nsec int64) time.Time {
 func (t *trueTime) Sleep(d time.Duration) {
 	time.Sleep(d)
 }
+
+// afterFunc proxies the time.AfterFunc function.
+// This allows it to be mocked for testing.
+func afterFunc(d time.Duration, f func()) *time.Timer {
+	return time.AfterFunc(d, f)
+}


Test patch:
diff --git a/example_test.go b/example_test.go
index 349089e..9f0574b 100644
--- a/example_test.go
+++ b/example_test.go
@@ -270,6 +270,19 @@ func ExampleScheduler_CustomTime() {
 	// s.CustomTime(mct)
 }
 
+func ExampleScheduler_CustomTimer() {
+	s := gocron.NewScheduler(time.UTC)
+	s.CustomTimer(func(d time.Duration, f func()) *time.Timer {
+		// force jobs with 1 minute interval to run every second
+		if d == time.Minute {
+			d = time.Second
+		}
+		return time.AfterFunc(d, f)
+	})
+	// this job will run every 1 second
+	_, _ = s.Every("1m").Do(task)
+}
+
 func ExampleScheduler_Day() {
 	s := gocron.NewScheduler(time.UTC)