1
16
17 package cache
18
19 import (
20 "fmt"
21 "testing"
22 "time"
23
24 apierrors "k8s.io/apimachinery/pkg/api/errors"
25 testingclock "k8s.io/utils/clock/testing"
26 )
27
28 type retryScenarioStep struct {
29 clockStep time.Duration
30 err error
31 wantRetry bool
32 }
33
34 func TestRetryWithDeadline(t *testing.T) {
35 internalError := apierrors.NewInternalError(fmt.Errorf("etcdserver: no leader"))
36 otherError := fmt.Errorf("some other error")
37
38 testCases := []struct {
39 name string
40 duration time.Duration
41 reset time.Duration
42 isRetryable func(error) bool
43 scenario []retryScenarioStep
44 }{
45 {
46 name: "Never retry when duration is zero",
47 duration: time.Duration(0),
48 reset: time.Second * 30,
49 isRetryable: func(err error) bool { return false },
50 scenario: []retryScenarioStep{
51 {
52 clockStep: time.Second * 1,
53 err: nil,
54 wantRetry: false,
55 },
56 {
57 clockStep: time.Second * 0,
58 err: internalError,
59 wantRetry: false,
60 },
61 {
62 clockStep: time.Second * 1,
63 err: otherError,
64 wantRetry: false,
65 },
66 },
67 },
68 {
69 name: "Retry when internal error happens only within duration",
70 duration: time.Second * 1,
71 reset: time.Second * 30,
72 isRetryable: apierrors.IsInternalError,
73 scenario: []retryScenarioStep{
74 {
75 clockStep: time.Second * 1,
76 err: internalError,
77 wantRetry: true,
78 },
79 {
80 clockStep: time.Second * 1,
81 err: internalError,
82 wantRetry: true,
83 },
84 {
85 clockStep: time.Second * 1,
86 err: internalError,
87 wantRetry: false,
88 },
89 },
90 },
91 {
92 name: "Don't retry when other error happens",
93 duration: time.Second * 1,
94 reset: time.Second * 30,
95 isRetryable: apierrors.IsInternalError,
96 scenario: []retryScenarioStep{
97 {
98 clockStep: time.Second * 1,
99 err: otherError,
100 wantRetry: false,
101 },
102 },
103 },
104 {
105 name: "Ignore other errors for retries",
106 duration: time.Second * 1,
107 reset: time.Second * 30,
108 isRetryable: apierrors.IsInternalError,
109 scenario: []retryScenarioStep{
110 {
111 clockStep: time.Second * 1,
112 err: internalError,
113 wantRetry: true,
114 },
115 {
116 clockStep: time.Second * 0,
117 err: otherError,
118 wantRetry: true,
119 },
120 {
121 clockStep: time.Second * 1,
122 err: internalError,
123 wantRetry: true,
124 },
125 },
126 },
127 }
128
129 for _, tc := range testCases {
130 fakeClock := testingclock.NewFakeClock(time.Now())
131 retry := NewRetryWithDeadline(tc.duration, tc.reset, tc.isRetryable, fakeClock)
132
133 for i, step := range tc.scenario {
134 fakeClock.Step(step.clockStep)
135 retry.After(step.err)
136 result := retry.ShouldRetry()
137 if result != step.wantRetry {
138 t.Errorf("%v unexpected retry, step %d, result %v want %v", tc, i, result, step.wantRetry)
139 break
140 }
141 }
142 }
143 }
144
View as plain text