Tests for retry_utils

One can argue about how necessary they are,
but at least I remembered how to do golang.
This commit is contained in:
Dmitrii Dolgov 2018-02-07 17:04:43 +01:00
parent 60c742a3e8
commit dd79fcd036
2 changed files with 96 additions and 3 deletions

View File

@ -5,14 +5,39 @@ import (
"time" "time"
) )
// Retry calls ConditionFunc until it returns boolean true, a timeout expires or an error occurs. type RetryTicker interface {
Stop()
Tick()
}
type Ticker struct {
ticker *time.Ticker
}
func (t *Ticker) Stop() { t.ticker.Stop() }
func (t *Ticker) Tick() { <-t.ticker.C }
// Retry calls ConditionFunc until either:
// * it returns boolean true
// * a timeout expires
// * an error occurs
func Retry(interval time.Duration, timeout time.Duration, f func() (bool, error)) error { func Retry(interval time.Duration, timeout time.Duration, f func() (bool, error)) error {
//TODO: make the retry exponential //TODO: make the retry exponential
if timeout < interval { if timeout < interval {
return fmt.Errorf("timout(%s) should be greater than interval(%v)", timeout, interval) return fmt.Errorf("timout(%s) should be greater than interval(%v)", timeout, interval)
} }
tick := &Ticker{time.NewTicker(interval)}
return RetryWorker(interval, timeout, f, tick)
}
func RetryWorker(
interval time.Duration,
timeout time.Duration,
f func() (bool, error),
tick RetryTicker) error {
maxRetries := int(timeout / interval) maxRetries := int(timeout / interval)
tick := time.NewTicker(interval)
defer tick.Stop() defer tick.Stop()
for i := 0; ; i++ { for i := 0; ; i++ {
@ -26,7 +51,7 @@ func Retry(interval time.Duration, timeout time.Duration, f func() (bool, error)
if i+1 == maxRetries { if i+1 == maxRetries {
break break
} }
<-tick.C tick.Tick()
} }
return fmt.Errorf("still failing after %d retries", maxRetries) return fmt.Errorf("still failing after %d retries", maxRetries)
} }

View File

@ -0,0 +1,68 @@
package retryutil
import (
"errors"
"testing"
)
type mockTicker struct {
test *testing.T
counter int
}
func (t *mockTicker) Stop() {}
func (t *mockTicker) Tick() {
t.counter += 1
}
func TestRetryWorkerSuccess(t *testing.T) {
tick := &mockTicker{t, 0}
result := RetryWorker(10, 20, func() (bool, error) {
return true, nil
}, tick)
if result != nil {
t.Errorf("Wrong result, expected: %#v, got: %#v", nil, result)
}
if tick.counter != 0 {
t.Errorf("Ticker was started once, but it shouldn't be")
}
}
func TestRetryWorkerOneFalse(t *testing.T) {
var counter = 0
tick := &mockTicker{t, 0}
result := RetryWorker(1, 3, func() (bool, error) {
counter += 1
if counter <= 1 {
return false, nil
} else {
return true, nil
}
}, tick)
if result != nil {
t.Errorf("Wrong result, expected: %#v, got: %#v", nil, result)
}
if tick.counter != 1 {
t.Errorf("Ticker was started %#v, but supposed to be just once", tick.counter)
}
}
func TestRetryWorkerError(t *testing.T) {
fail := errors.New("Error")
tick := &mockTicker{t, 0}
result := RetryWorker(1, 3, func() (bool, error) {
return false, fail
}, tick)
if result != fail {
t.Errorf("Wrong result, expected: %#v, got: %#v", fail, result)
}
}