Merge pull request #224 from zalando-incubator/feature/retry_util_tests
Tests for retry_utils
This commit is contained in:
		
						commit
						75435ef934
					
				|  | @ -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, tick, f) | ||||
| } | ||||
| 
 | ||||
| func RetryWorker( | ||||
| 	interval time.Duration, | ||||
| 	timeout time.Duration, | ||||
| 	tick RetryTicker, | ||||
| 	f func() (bool, error)) 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, tick, func() (bool, error) { | ||||
| 		return true, nil | ||||
| 	}) | ||||
| 
 | ||||
| 	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, tick, func() (bool, error) { | ||||
| 		counter += 1 | ||||
| 
 | ||||
| 		if counter <= 1 { | ||||
| 			return false, nil | ||||
| 		} else { | ||||
| 			return true, nil | ||||
| 		} | ||||
| 	}) | ||||
| 
 | ||||
| 	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, tick, func() (bool, error) { | ||||
| 		return false, fail | ||||
| 	}) | ||||
| 
 | ||||
| 	if result != fail { | ||||
| 		t.Errorf("Wrong result, expected: %#v, got: %#v", fail, result) | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in New Issue