11package retry
22
33import (
4+ "context"
45 "errors"
56 "testing"
7+ "time"
68)
79
10+ // timeMarginOfError represents the acceptable amount of time that may pass for
11+ // a time-based (sleep) unit before considering invalid.
12+ const timeMarginOfError = time .Millisecond
13+
814func TestRetry (t * testing.T ) {
915 action := func (attempt uint ) error {
1016 return nil
@@ -47,8 +53,63 @@ func TestRetryRetriesUntilNoErrorReturned(t *testing.T) {
4753 }
4854}
4955
56+ func TestRetryWithContextAlreadyCancelled (t * testing.T ) {
57+ action := func (ctx context.Context , attempt uint ) error {
58+ return errors .New ("erroring" )
59+ }
60+
61+ ctx , cancel := context .WithCancel (context .Background ())
62+ cancel ()
63+
64+ err := RetryWithContext (ctx , action )
65+
66+ if ctx .Err () != err {
67+ t .Error ("expected a context error" )
68+ }
69+ }
70+
71+ func TestRetryWithContextSleepIsInterrupted (t * testing.T ) {
72+ const sleepDuration = 100 * timeMarginOfError
73+ noSleepDeadline := time .Now ().Add (sleepDuration )
74+
75+ strategy := func (attempt uint , sleep func (time.Duration )) bool {
76+ sleep (sleepDuration )
77+ return true
78+ }
79+
80+ var numCalls int
81+ expectedErr := errors .New ("erroring" )
82+
83+ action := func (ctx context.Context , attempt uint ) error {
84+ numCalls ++
85+ return expectedErr
86+ }
87+
88+ stopAfter := 10 * timeMarginOfError
89+ deadline := time .Now ().Add (stopAfter )
90+ ctx , _ := context .WithDeadline (context .Background (), deadline )
91+
92+ err := RetryWithContext (ctx , action , strategy )
93+
94+ if time .Now ().Before (deadline ) {
95+ t .Errorf ("expected to stop after %s" , stopAfter )
96+ }
97+
98+ if time .Now ().After (noSleepDeadline ) {
99+ t .Errorf ("expected to stop before %s" , sleepDuration )
100+ }
101+
102+ if 1 != numCalls {
103+ t .Errorf ("expected the action to be tried once, not %d times" , numCalls )
104+ }
105+
106+ if expectedErr != err {
107+ t .Error ("expected to receive the error returned by the action" )
108+ }
109+ }
110+
50111func TestShouldAttempt (t * testing.T ) {
51- shouldAttempt := shouldAttempt (1 )
112+ shouldAttempt := shouldAttempt (1 , time . Sleep )
52113
53114 if ! shouldAttempt {
54115 t .Error ("expected to return true" )
@@ -58,63 +119,63 @@ func TestShouldAttempt(t *testing.T) {
58119func TestShouldAttemptWithStrategy (t * testing.T ) {
59120 const attemptNumberShouldReturnFalse = 7
60121
61- strategy := func (attempt uint ) bool {
122+ strategy := func (attempt uint , sleep func (time. Duration ) ) bool {
62123 return (attemptNumberShouldReturnFalse != attempt )
63124 }
64125
65- should := shouldAttempt (1 , strategy )
126+ should := shouldAttempt (1 , time . Sleep , strategy )
66127
67128 if ! should {
68129 t .Error ("expected to return true" )
69130 }
70131
71- should = shouldAttempt (1 + attemptNumberShouldReturnFalse , strategy )
132+ should = shouldAttempt (1 + attemptNumberShouldReturnFalse , time . Sleep , strategy )
72133
73134 if ! should {
74135 t .Error ("expected to return true" )
75136 }
76137
77- should = shouldAttempt (attemptNumberShouldReturnFalse , strategy )
138+ should = shouldAttempt (attemptNumberShouldReturnFalse , time . Sleep , strategy )
78139
79140 if should {
80141 t .Error ("expected to return false" )
81142 }
82143}
83144
84145func TestShouldAttemptWithMultipleStrategies (t * testing.T ) {
85- trueStrategy := func (attempt uint ) bool {
146+ trueStrategy := func (attempt uint , sleep func (time. Duration ) ) bool {
86147 return true
87148 }
88149
89- falseStrategy := func (attempt uint ) bool {
150+ falseStrategy := func (attempt uint , sleep func (time. Duration ) ) bool {
90151 return false
91152 }
92153
93- should := shouldAttempt (1 , trueStrategy )
154+ should := shouldAttempt (1 , time . Sleep , trueStrategy )
94155
95156 if ! should {
96157 t .Error ("expected to return true" )
97158 }
98159
99- should = shouldAttempt (1 , falseStrategy )
160+ should = shouldAttempt (1 , time . Sleep , falseStrategy )
100161
101162 if should {
102163 t .Error ("expected to return false" )
103164 }
104165
105- should = shouldAttempt (1 , trueStrategy , trueStrategy , trueStrategy )
166+ should = shouldAttempt (1 , time . Sleep , trueStrategy , trueStrategy , trueStrategy )
106167
107168 if ! should {
108169 t .Error ("expected to return true" )
109170 }
110171
111- should = shouldAttempt (1 , falseStrategy , falseStrategy , falseStrategy )
172+ should = shouldAttempt (1 , time . Sleep , falseStrategy , falseStrategy , falseStrategy )
112173
113174 if should {
114175 t .Error ("expected to return false" )
115176 }
116177
117- should = shouldAttempt (1 , trueStrategy , trueStrategy , falseStrategy )
178+ should = shouldAttempt (1 , time . Sleep , trueStrategy , trueStrategy , falseStrategy )
118179
119180 if should {
120181 t .Error ("expected to return false" )
0 commit comments