scouting: Change background_task implementation

Instead of manually implementing a ticker, this patch switches over to
using `time.Ticker`. The functionality should be identical.

This patch also adds a small test to make sure that the bare
functionality is working.

Signed-off-by: Philipp Schrader <philipp.schrader@gmail.com>
Change-Id: I54acfc5280b3541f3021dbe35d79e7db0adcc5f6
diff --git a/scouting/background_task/background_task.go b/scouting/background_task/background_task.go
index 4fdb034..6980042 100644
--- a/scouting/background_task/background_task.go
+++ b/scouting/background_task/background_task.go
@@ -7,52 +7,46 @@
 // A helper to run a function in the background at a specified interval.
 // Can be used for a lot of different things.
 type backgroundTask struct {
-	doneChan     chan<- bool
-	checkStopped chan<- bool
-	interval     time.Duration
+	ticker        *time.Ticker
+	stopRequested chan bool
+	done          chan bool
 }
 
 func New(interval time.Duration) backgroundTask {
 	return backgroundTask{
-		doneChan:     make(chan bool, 1),
-		checkStopped: make(chan bool, 1),
-		interval:     interval,
+		ticker:        time.NewTicker(interval),
+		stopRequested: make(chan bool, 1),
+		done:          make(chan bool, 1),
 	}
 }
 
 func (task *backgroundTask) Start(taskFunc func()) {
 	go func() {
-		// Setting start time to a time prior so the function gets
-		// called instantly when Start() called
-		startTime := time.Now().Add(-task.interval - time.Minute)
+		// Signal the Stop() function below when the goroutine has
+		// finished executing.
+		defer func() { task.done <- true }()
+
+		// time.Ticker doesn't perform an immediate invocation.
+		// Instead, it waits for the specified duration before
+		// triggering the first tick. We pretend that there's a tick
+		// here by invoking the callback manually.
+		taskFunc()
+
 		for {
-			curTime := time.Now()
-			diff := curTime.Sub(startTime)
-
-			if diff > task.interval {
+			select {
+			case <-task.stopRequested:
+				return
+			case <-task.ticker.C:
 				taskFunc()
-				startTime = curTime
 			}
-
-			if len(task.doneChan) != 0 {
-				break
-			}
-
-			time.Sleep(time.Second)
 		}
-
-		task.checkStopped <- true
 	}()
 }
 
 func (task *backgroundTask) Stop() {
-	task.doneChan <- true
-
-	for {
-		if len(task.checkStopped) != 0 {
-			close(task.doneChan)
-			close(task.checkStopped)
-			break
-		}
-	}
+	task.stopRequested <- true
+	task.ticker.Stop()
+	<-task.done
+	close(task.stopRequested)
+	close(task.done)
 }