Skip to content

Commit 3a95b11

Browse files
authored
Merge pull request kubernetes#91439 from weijiehu/azureretry
Improves unittest CC for azure_error and azure_retry
2 parents f097cee + a306943 commit 3a95b11

File tree

3 files changed

+166
-0
lines changed

3 files changed

+166
-0
lines changed

staging/src/k8s.io/legacy-cloud-providers/azure/retry/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ go_test(
2525
],
2626
embed = [":go_default_library"],
2727
deps = [
28+
"//vendor/github.com/Azure/go-autorest/autorest:go_default_library",
2829
"//vendor/github.com/Azure/go-autorest/autorest/mocks:go_default_library",
2930
"//vendor/github.com/stretchr/testify/assert:go_default_library",
3031
],

staging/src/k8s.io/legacy-cloud-providers/azure/retry/azure_error_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,40 @@ import (
2929
"github.com/stretchr/testify/assert"
3030
)
3131

32+
func TestNewError(t *testing.T) {
33+
rawErr := fmt.Errorf("HTTP status code (404)")
34+
newerr := NewError(true, rawErr)
35+
assert.Equal(t, true, newerr.Retriable)
36+
assert.Equal(t, rawErr, newerr.RawError)
37+
}
38+
39+
func TestGetRetriableError(t *testing.T) {
40+
rawErr := fmt.Errorf("HTTP status code (404)")
41+
newerr := GetRetriableError(rawErr)
42+
assert.Equal(t, true, newerr.Retriable)
43+
assert.Equal(t, rawErr, newerr.RawError)
44+
}
45+
46+
func TestGetRateLimitError(t *testing.T) {
47+
opType := "write"
48+
opName := "opNameTest"
49+
rawErr := fmt.Errorf("azure cloud provider rate limited(%s) for operation %q", opType, opName)
50+
newerr := GetRateLimitError(true, opName)
51+
assert.Equal(t, true, newerr.Retriable)
52+
assert.Equal(t, rawErr, newerr.RawError)
53+
}
54+
55+
func TestGetThrottlingError(t *testing.T) {
56+
operation := "operationtest"
57+
reason := "reasontest"
58+
rawErr := fmt.Errorf("azure cloud provider throttled for operation %s with reason %q", operation, reason)
59+
onehourlater := time.Now().Add(time.Hour * 1)
60+
newerr := GetThrottlingError(operation, reason, onehourlater)
61+
assert.Equal(t, true, newerr.Retriable)
62+
assert.Equal(t, rawErr, newerr.RawError)
63+
assert.Equal(t, onehourlater, newerr.RetryAfter)
64+
}
65+
3266
func TestGetError(t *testing.T) {
3367
now = func() time.Time {
3468
return time.Time{}
@@ -104,6 +138,19 @@ func TestGetError(t *testing.T) {
104138
}
105139
}
106140

141+
func TestGetErrorNil(t *testing.T) {
142+
rerr := GetError(nil, nil)
143+
assert.Nil(t, rerr)
144+
145+
// null body
146+
resp := &http.Response{
147+
StatusCode: http.StatusBadRequest,
148+
Body: nil,
149+
}
150+
rerr = GetError(resp, nil)
151+
assert.Equal(t, fmt.Errorf("empty HTTP response"), rerr.RawError)
152+
}
153+
107154
func TestGetStatusNotFoundAndForbiddenIgnoredError(t *testing.T) {
108155
now = func() time.Time {
109156
return time.Time{}
@@ -256,6 +303,11 @@ func TestIsSuccessResponse(t *testing.T) {
256303
}
257304
}
258305

306+
func TestIsSuccessResponseNil(t *testing.T) {
307+
res := isSuccessHTTPResponse(nil)
308+
assert.Equal(t, false, res)
309+
}
310+
259311
func TestIsThrottled(t *testing.T) {
260312
tests := []struct {
261313
err *Error
@@ -290,3 +342,13 @@ func TestIsThrottled(t *testing.T) {
290342
assert.Equal(t, test.expected, real)
291343
}
292344
}
345+
346+
func TestIsErrorRetriable(t *testing.T) {
347+
// flase case
348+
result := IsErrorRetriable(nil)
349+
assert.Equal(t, false, result)
350+
351+
// true case
352+
result = IsErrorRetriable(fmt.Errorf("Retriable: true"))
353+
assert.Equal(t, true, result)
354+
}

staging/src/k8s.io/legacy-cloud-providers/azure/retry/azure_retry_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,85 @@ import (
2626
"testing"
2727
"time"
2828

29+
"github.com/Azure/go-autorest/autorest"
2930
"github.com/Azure/go-autorest/autorest/mocks"
3031
"github.com/stretchr/testify/assert"
3132
)
3233

34+
func TestNewBackoff(t *testing.T) {
35+
expected := &Backoff{Duration: time.Second, Factor: 2, Steps: 0, Cap: 3 * time.Second, Jitter: 0.5}
36+
result := NewBackoff(time.Second, 2, 0.5, 0, 3*time.Second)
37+
assert.Equal(t, expected, result)
38+
}
39+
40+
func TestWithNonRetriableErrors(t *testing.T) {
41+
bo := &Backoff{Duration: time.Second, Factor: 2, Steps: 0, Cap: 3 * time.Second, Jitter: 0.5}
42+
errs := []string{"error1", "error2"}
43+
expected := bo
44+
expected.NonRetriableErrors = errs
45+
result := bo.WithNonRetriableErrors(errs)
46+
assert.Equal(t, expected, result)
47+
}
48+
49+
func TestWithRetriableHTTPStatusCodes(t *testing.T) {
50+
bo := &Backoff{Duration: time.Second, Factor: 2, Steps: 0, Cap: 3 * time.Second, Jitter: 0.5}
51+
httpStatusCodes := []int{http.StatusOK, http.StatusTooManyRequests}
52+
expected := bo
53+
expected.RetriableHTTPStatusCodes = httpStatusCodes
54+
result := bo.WithRetriableHTTPStatusCodes(httpStatusCodes)
55+
assert.Equal(t, expected, result)
56+
}
57+
58+
func TestIsNonRetriableError(t *testing.T) {
59+
// false case
60+
bo := &Backoff{Factor: 1.0, Steps: 3}
61+
ret := bo.isNonRetriableError(nil)
62+
assert.Equal(t, false, ret)
63+
64+
// true case
65+
errs := []string{"error1", "error2"}
66+
bo2 := bo
67+
bo2.NonRetriableErrors = errs
68+
rerr := &Error{
69+
Retriable: false,
70+
HTTPStatusCode: 429,
71+
RawError: fmt.Errorf("error1"),
72+
}
73+
74+
ret = bo2.isNonRetriableError(rerr)
75+
assert.Equal(t, true, ret)
76+
}
77+
78+
func TestJitterWithNegativeMaxFactor(t *testing.T) {
79+
// jitter := duration + time.Duration(rand.Float64()*maxFactor*float64(duration))
80+
// If maxFactor is 0.0 or less than 0.0, a suggested default value will be chosen.
81+
// rand.Float64() returns, as a float64, a pseudo-random number in [0.0,1.0).
82+
duration := time.Duration(time.Second)
83+
maxFactor := float64(-3.0)
84+
res := jitter(duration, maxFactor)
85+
defaultMaxFactor := float64(1.0)
86+
expected := jitter(duration, defaultMaxFactor)
87+
assert.Equal(t, expected-res >= time.Duration(0.0*float64(duration)), true)
88+
assert.Equal(t, expected-res < time.Duration(1.0*float64(duration)), true)
89+
}
90+
91+
func TestDoExponentialBackoffRetry(t *testing.T) {
92+
client := mocks.NewSender()
93+
bo := &Backoff{Duration: time.Second, Factor: 2, Steps: 0, Cap: 3 * time.Second, Jitter: 0.5}
94+
sender := autorest.DecorateSender(
95+
client,
96+
DoExponentialBackoffRetry(bo),
97+
)
98+
99+
req := &http.Request{
100+
Method: "GET",
101+
}
102+
103+
result, err := sender.Do(req)
104+
assert.Nil(t, result)
105+
assert.Nil(t, err)
106+
}
107+
33108
func TestStep(t *testing.T) {
34109
tests := []struct {
35110
initial *Backoff
@@ -97,6 +172,34 @@ func TestDoBackoffRetry(t *testing.T) {
97172
assert.Equal(t, expectedErr.Error(), err)
98173
assert.Equal(t, 3, client.Attempts())
99174

175+
// retries with 0 steps
176+
respSteps0, errSteps0 := doBackoffRetry(client, fakeRequest, &Backoff{Factor: 1.0, Steps: 0})
177+
assert.Nil(t, respSteps0)
178+
assert.Nil(t, errSteps0)
179+
180+
// backoff with NonRetriableErrors and RetriableHTTPStatusCodes
181+
r = mocks.NewResponseWithStatus("404 StatusNotFound", http.StatusNotFound)
182+
client = mocks.NewSender()
183+
client.AppendAndRepeatResponseWithDelay(r, time.Second, 1)
184+
client.AppendError(fmt.Errorf("HTTP status code (404)"))
185+
bo := &Backoff{Factor: 1.0, Steps: 3}
186+
bo.NonRetriableErrors = []string{"404 StatusNotFound"}
187+
bo.RetriableHTTPStatusCodes = []int{http.StatusNotFound}
188+
expectedResp := &http.Response{
189+
Status: "200 OK",
190+
StatusCode: 200,
191+
Proto: "HTTP/1.0",
192+
ProtoMajor: 1,
193+
ProtoMinor: 0,
194+
Body: mocks.NewBody(""),
195+
Request: fakeRequest,
196+
}
197+
198+
resp, err = doBackoffRetry(client, fakeRequest, bo)
199+
assert.Nil(t, err)
200+
assert.Equal(t, 3, client.Attempts())
201+
assert.Equal(t, expectedResp, resp)
202+
100203
// returns immediately on succeed
101204
r = mocks.NewResponseWithStatus("200 OK", http.StatusOK)
102205
client = mocks.NewSender()

0 commit comments

Comments
 (0)