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:
parent
60c742a3e8
commit
dd79fcd036
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue