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"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
//TODO: make the retry exponential
|
||||
if 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)
|
||||
tick := time.NewTicker(interval)
|
||||
defer tick.Stop()
|
||||
|
||||
for i := 0; ; i++ {
|
||||
|
|
@ -26,7 +51,7 @@ func Retry(interval time.Duration, timeout time.Duration, f func() (bool, error)
|
|||
if i+1 == maxRetries {
|
||||
break
|
||||
}
|
||||
<-tick.C
|
||||
tick.Tick()
|
||||
}
|
||||
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