Skip to content

Commit 0024802

Browse files
authored
Cover backoff wrappers and constructor panics (#42)
Adds test coverage for public API that had none, pulled from the non-nix parts of #38 and rewritten to match the per-source-file test layout. The `Constant`, `Exponential`, and `Fibonacci` convenience wrappers were at 0% coverage, and the `NewConstant`/`NewExponential`/`NewFibonacci` non-positive-base panic paths were untested. Each `backoff_*_test.go` now exercises its wrapper (retry a few times, then succeed) and its constructor panics (table-driven over zero and negative bases). Package coverage goes from 89.5% to 95.2%; the six functions above are now 100%. Deliberately left out of #38: the nix tooling, the Go 1.26.5 bump (staying on 1.25), the jitter zero-panic fix (already landed in #39), the `lockedSource` tests (rand.go is gone), and `IsRetryable` (no external need today, and an `errors.Is`-friendly sentinel would beat a bool helper if one ever arises). Signed-off-by: Seth Vargo <seth@sethvargo.com>
1 parent 61116c4 commit 0024802

3 files changed

Lines changed: 135 additions & 0 deletions

File tree

backoff_constant_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package retry_test
22

33
import (
4+
"context"
5+
"errors"
46
"fmt"
57
"reflect"
68
"slices"
@@ -108,3 +110,46 @@ func ExampleNewConstant() {
108110
// 1s
109111
// 1s
110112
}
113+
114+
func TestConstant(t *testing.T) {
115+
t.Parallel()
116+
117+
calls := 0
118+
if err := retry.Constant(context.Background(), 1*time.Nanosecond, func(_ context.Context) error {
119+
calls++
120+
if calls < 3 {
121+
return retry.RetryableError(errors.New("retry"))
122+
}
123+
return nil
124+
}); err != nil {
125+
t.Fatal(err)
126+
}
127+
if calls != 3 {
128+
t.Errorf("expected %d to be %d", calls, 3)
129+
}
130+
}
131+
132+
func TestNewConstant_panics(t *testing.T) {
133+
t.Parallel()
134+
135+
cases := []struct {
136+
name string
137+
base time.Duration
138+
}{
139+
{name: "zero", base: 0},
140+
{name: "negative", base: -1 * time.Second},
141+
}
142+
143+
for _, tc := range cases {
144+
t.Run(tc.name, func(t *testing.T) {
145+
t.Parallel()
146+
147+
defer func() {
148+
if recover() == nil {
149+
t.Errorf("expected panic")
150+
}
151+
}()
152+
retry.NewConstant(tc.base)
153+
})
154+
}
155+
}

backoff_exponential_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package retry_test
22

33
import (
4+
"context"
5+
"errors"
46
"fmt"
57
"math"
68
"reflect"
@@ -158,3 +160,46 @@ func TestExponentialBackoff_ConcurrentOverflow(t *testing.T) {
158160
t.Errorf("expected \n\n%v\n\n to be \n\n%v\n\n", results, want)
159161
}
160162
}
163+
164+
func TestExponential(t *testing.T) {
165+
t.Parallel()
166+
167+
calls := 0
168+
if err := retry.Exponential(context.Background(), 1*time.Nanosecond, func(_ context.Context) error {
169+
calls++
170+
if calls < 3 {
171+
return retry.RetryableError(errors.New("retry"))
172+
}
173+
return nil
174+
}); err != nil {
175+
t.Fatal(err)
176+
}
177+
if calls != 3 {
178+
t.Errorf("expected %d to be %d", calls, 3)
179+
}
180+
}
181+
182+
func TestNewExponential_panics(t *testing.T) {
183+
t.Parallel()
184+
185+
cases := []struct {
186+
name string
187+
base time.Duration
188+
}{
189+
{name: "zero", base: 0},
190+
{name: "negative", base: -1 * time.Second},
191+
}
192+
193+
for _, tc := range cases {
194+
t.Run(tc.name, func(t *testing.T) {
195+
t.Parallel()
196+
197+
defer func() {
198+
if recover() == nil {
199+
t.Errorf("expected panic")
200+
}
201+
}()
202+
retry.NewExponential(tc.base)
203+
})
204+
}
205+
}

backoff_fibonacci_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package retry_test
22

33
import (
4+
"context"
5+
"errors"
46
"fmt"
57
"math"
68
"reflect"
@@ -126,3 +128,46 @@ func ExampleNewFibonacci() {
126128
// 5s
127129
// 8s
128130
}
131+
132+
func TestFibonacci(t *testing.T) {
133+
t.Parallel()
134+
135+
calls := 0
136+
if err := retry.Fibonacci(context.Background(), 1*time.Nanosecond, func(_ context.Context) error {
137+
calls++
138+
if calls < 3 {
139+
return retry.RetryableError(errors.New("retry"))
140+
}
141+
return nil
142+
}); err != nil {
143+
t.Fatal(err)
144+
}
145+
if calls != 3 {
146+
t.Errorf("expected %d to be %d", calls, 3)
147+
}
148+
}
149+
150+
func TestNewFibonacci_panics(t *testing.T) {
151+
t.Parallel()
152+
153+
cases := []struct {
154+
name string
155+
base time.Duration
156+
}{
157+
{name: "zero", base: 0},
158+
{name: "negative", base: -1 * time.Second},
159+
}
160+
161+
for _, tc := range cases {
162+
t.Run(tc.name, func(t *testing.T) {
163+
t.Parallel()
164+
165+
defer func() {
166+
if recover() == nil {
167+
t.Errorf("expected panic")
168+
}
169+
}()
170+
retry.NewFibonacci(tc.base)
171+
})
172+
}
173+
}

0 commit comments

Comments
 (0)