@@ -25,17 +25,46 @@ import (
25
25
"io/ioutil"
26
26
"net/http"
27
27
"testing"
28
+ "time"
28
29
29
30
"github.com/Azure/azure-sdk-for-go/services/network/mgmt/2019-06-01/network"
30
31
"github.com/Azure/go-autorest/autorest/to"
31
32
"github.com/golang/mock/gomock"
32
33
"github.com/stretchr/testify/assert"
33
34
35
+ "k8s.io/client-go/util/flowcontrol"
34
36
azclients "k8s.io/legacy-cloud-providers/azure/clients"
35
37
"k8s.io/legacy-cloud-providers/azure/clients/armclient"
36
38
"k8s.io/legacy-cloud-providers/azure/clients/armclient/mockarmclient"
39
+ "k8s.io/legacy-cloud-providers/azure/retry"
37
40
)
38
41
42
+ // 2065-01-24 05:20:00 +0000 UTC
43
+ func getFutureTime () time.Time {
44
+ return time .Unix (3000000000 , 0 )
45
+ }
46
+
47
+ func TestNew (t * testing.T ) {
48
+ config := & azclients.ClientConfig {
49
+ SubscriptionID : "sub" ,
50
+ ResourceManagerEndpoint : "endpoint" ,
51
+ Location : "eastus" ,
52
+ RateLimitConfig : & azclients.RateLimitConfig {
53
+ CloudProviderRateLimit : true ,
54
+ CloudProviderRateLimitQPS : 0.5 ,
55
+ CloudProviderRateLimitBucket : 1 ,
56
+ CloudProviderRateLimitQPSWrite : 0.5 ,
57
+ CloudProviderRateLimitBucketWrite : 1 ,
58
+ },
59
+ Backoff : & retry.Backoff {Steps : 1 },
60
+ }
61
+
62
+ routeClient := New (config )
63
+ assert .Equal (t , "sub" , routeClient .subscriptionID )
64
+ assert .NotEmpty (t , routeClient .rateLimiterReader )
65
+ assert .NotEmpty (t , routeClient .rateLimiterWriter )
66
+ }
67
+
39
68
func TestCreateOrUpdate (t * testing.T ) {
40
69
ctrl := gomock .NewController (t )
41
70
defer ctrl .Finish ()
@@ -49,11 +78,91 @@ func TestCreateOrUpdate(t *testing.T) {
49
78
armClient .EXPECT ().PutResourceWithDecorators (gomock .Any (), to .String (r .ID ), r , gomock .Any ()).Return (response , nil ).Times (1 )
50
79
armClient .EXPECT ().CloseResponse (gomock .Any (), gomock .Any ()).Times (1 )
51
80
52
- rtClient := getTestRouteClient (armClient )
53
- rerr := rtClient .CreateOrUpdate (context .TODO (), "rg" , "rt" , "r1" , r , "" )
81
+ routeClient := getTestRouteClient (armClient )
82
+ rerr := routeClient .CreateOrUpdate (context .TODO (), "rg" , "rt" , "r1" , r , "* " )
54
83
assert .Nil (t , rerr )
55
84
}
56
85
86
+ func TestCreateOrUpdateWithNeverRateLimiter (t * testing.T ) {
87
+ ctrl := gomock .NewController (t )
88
+ defer ctrl .Finish ()
89
+
90
+ rcCreateOrUpdatetErr := & retry.Error {
91
+ RawError : fmt .Errorf ("azure cloud provider rate limited(%s) for operation %q" , "write" , "RouteCreateOrUpdate" ),
92
+ Retriable : true ,
93
+ }
94
+
95
+ r := getTestRoute ("r1" )
96
+ armClient := mockarmclient .NewMockInterface (ctrl )
97
+
98
+ routeClient := getTestRouteClientWithNeverRateLimiter (armClient )
99
+ rerr := routeClient .CreateOrUpdate (context .TODO (), "rg" , "rt" , "r1" , r , "" )
100
+ assert .Equal (t , rcCreateOrUpdatetErr , rerr )
101
+ }
102
+
103
+ func TestCreateOrUpdateRetryAfterReader (t * testing.T ) {
104
+ ctrl := gomock .NewController (t )
105
+ defer ctrl .Finish ()
106
+
107
+ rcCreateOrUpdateErr := & retry.Error {
108
+ RawError : fmt .Errorf ("azure cloud provider throttled for operation %s with reason %q" , "RouteCreateOrUpdate" , "client throttled" ),
109
+ Retriable : true ,
110
+ RetryAfter : getFutureTime (),
111
+ }
112
+
113
+ r := getTestRoute ("r1" )
114
+ armClient := mockarmclient .NewMockInterface (ctrl )
115
+
116
+ routeClient := getTestRouteClientWithRetryAfterReader (armClient )
117
+ rerr := routeClient .CreateOrUpdate (context .TODO (), "rg" , "rt" , "r1" , r , "" )
118
+ assert .NotNil (t , rerr )
119
+ assert .Equal (t , rcCreateOrUpdateErr , rerr )
120
+ }
121
+
122
+ func TestCreateOrUpdateThrottle (t * testing.T ) {
123
+ ctrl := gomock .NewController (t )
124
+ defer ctrl .Finish ()
125
+
126
+ response := & http.Response {
127
+ StatusCode : http .StatusTooManyRequests ,
128
+ Body : ioutil .NopCloser (bytes .NewReader ([]byte ("{}" ))),
129
+ }
130
+ throttleErr := & retry.Error {
131
+ HTTPStatusCode : http .StatusTooManyRequests ,
132
+ RawError : fmt .Errorf ("error" ),
133
+ Retriable : true ,
134
+ RetryAfter : time .Unix (100 , 0 ),
135
+ }
136
+
137
+ r := getTestRoute ("r1" )
138
+ armClient := mockarmclient .NewMockInterface (ctrl )
139
+ armClient .EXPECT ().PutResourceWithDecorators (gomock .Any (), to .String (r .ID ), r , gomock .Any ()).Return (response , throttleErr ).Times (1 )
140
+ armClient .EXPECT ().CloseResponse (gomock .Any (), gomock .Any ()).Times (1 )
141
+
142
+ routeClient := getTestRouteClient (armClient )
143
+ rerr := routeClient .CreateOrUpdate (context .TODO (), "rg" , "rt" , "r1" , r , "" )
144
+ assert .Equal (t , throttleErr , rerr )
145
+ }
146
+
147
+ func TestCreateOrUpdateWithCreateOrUpdateResponderError (t * testing.T ) {
148
+ ctrl := gomock .NewController (t )
149
+ defer ctrl .Finish ()
150
+
151
+ r := getTestRoute ("r1" )
152
+ armClient := mockarmclient .NewMockInterface (ctrl )
153
+ response := & http.Response {
154
+ StatusCode : http .StatusNotFound ,
155
+ Body : ioutil .NopCloser (bytes .NewReader ([]byte ("" ))),
156
+ }
157
+
158
+ armClient .EXPECT ().PutResourceWithDecorators (gomock .Any (), to .String (r .ID ), r , gomock .Any ()).Return (response , nil ).Times (1 )
159
+ armClient .EXPECT ().CloseResponse (gomock .Any (), gomock .Any ()).Times (1 )
160
+
161
+ routeClient := getTestRouteClient (armClient )
162
+ rerr := routeClient .CreateOrUpdate (context .TODO (), "rg" , "rt" , "r1" , r , "" )
163
+ assert .NotNil (t , rerr )
164
+ }
165
+
57
166
func TestDelete (t * testing.T ) {
58
167
ctrl := gomock .NewController (t )
59
168
defer ctrl .Finish ()
@@ -62,11 +171,64 @@ func TestDelete(t *testing.T) {
62
171
armClient := mockarmclient .NewMockInterface (ctrl )
63
172
armClient .EXPECT ().DeleteResource (gomock .Any (), to .String (r .ID ), "" ).Return (nil ).Times (1 )
64
173
65
- rtClient := getTestRouteClient (armClient )
66
- rerr := rtClient .Delete (context .TODO (), "rg" , "rt" , "r1" )
174
+ routeClient := getTestRouteClient (armClient )
175
+ rerr := routeClient .Delete (context .TODO (), "rg" , "rt" , "r1" )
67
176
assert .Nil (t , rerr )
68
177
}
69
178
179
+ func TestDeleteWithNeverRateLimiter (t * testing.T ) {
180
+ ctrl := gomock .NewController (t )
181
+ defer ctrl .Finish ()
182
+
183
+ rcDeleteErr := & retry.Error {
184
+ RawError : fmt .Errorf ("azure cloud provider rate limited(%s) for operation %q" , "write" , "RouteDelete" ),
185
+ Retriable : true ,
186
+ }
187
+
188
+ armClient := mockarmclient .NewMockInterface (ctrl )
189
+
190
+ routeClient := getTestRouteClientWithNeverRateLimiter (armClient )
191
+ rerr := routeClient .Delete (context .TODO (), "rg" , "rt" , "r1" )
192
+ assert .Equal (t , rcDeleteErr , rerr )
193
+ }
194
+
195
+ func TestDeleteRetryAfterReader (t * testing.T ) {
196
+ ctrl := gomock .NewController (t )
197
+ defer ctrl .Finish ()
198
+
199
+ rcDeleteErr := & retry.Error {
200
+ RawError : fmt .Errorf ("azure cloud provider throttled for operation %s with reason %q" , "RouteDelete" , "client throttled" ),
201
+ Retriable : true ,
202
+ RetryAfter : getFutureTime (),
203
+ }
204
+
205
+ armClient := mockarmclient .NewMockInterface (ctrl )
206
+
207
+ routeClient := getTestRouteClientWithRetryAfterReader (armClient )
208
+ rerr := routeClient .Delete (context .TODO (), "rg" , "rt" , "r1" )
209
+ assert .Equal (t , rcDeleteErr , rerr )
210
+ }
211
+
212
+ func TestDeleteThrottle (t * testing.T ) {
213
+ ctrl := gomock .NewController (t )
214
+ defer ctrl .Finish ()
215
+
216
+ throttleErr := & retry.Error {
217
+ HTTPStatusCode : http .StatusTooManyRequests ,
218
+ RawError : fmt .Errorf ("error" ),
219
+ Retriable : true ,
220
+ RetryAfter : time .Unix (100 , 0 ),
221
+ }
222
+
223
+ r := getTestRoute ("r1" )
224
+ armClient := mockarmclient .NewMockInterface (ctrl )
225
+ armClient .EXPECT ().DeleteResource (gomock .Any (), to .String (r .ID ), "" ).Return (throttleErr ).Times (1 )
226
+
227
+ routeClient := getTestRouteClient (armClient )
228
+ rerr := routeClient .Delete (context .TODO (), "rg" , "rt" , "r1" )
229
+ assert .Equal (t , throttleErr , rerr )
230
+ }
231
+
70
232
func getTestRoute (name string ) network.Route {
71
233
return network.Route {
72
234
ID : to .StringPtr (fmt .Sprintf ("/subscriptions/subscriptionID/resourceGroups/rg/providers/Microsoft.Network/routeTables/rt/routes/%s" , name )),
@@ -83,3 +245,27 @@ func getTestRouteClient(armClient armclient.Interface) *Client {
83
245
rateLimiterWriter : rateLimiterWriter ,
84
246
}
85
247
}
248
+
249
+ func getTestRouteClientWithNeverRateLimiter (armClient armclient.Interface ) * Client {
250
+ rateLimiterReader := flowcontrol .NewFakeNeverRateLimiter ()
251
+ rateLimiterWriter := flowcontrol .NewFakeNeverRateLimiter ()
252
+ return & Client {
253
+ armClient : armClient ,
254
+ subscriptionID : "subscriptionID" ,
255
+ rateLimiterReader : rateLimiterReader ,
256
+ rateLimiterWriter : rateLimiterWriter ,
257
+ }
258
+ }
259
+
260
+ func getTestRouteClientWithRetryAfterReader (armClient armclient.Interface ) * Client {
261
+ rateLimiterReader := flowcontrol .NewFakeAlwaysRateLimiter ()
262
+ rateLimiterWriter := flowcontrol .NewFakeAlwaysRateLimiter ()
263
+ return & Client {
264
+ armClient : armClient ,
265
+ subscriptionID : "subscriptionID" ,
266
+ rateLimiterReader : rateLimiterReader ,
267
+ rateLimiterWriter : rateLimiterWriter ,
268
+ RetryAfterReader : getFutureTime (),
269
+ RetryAfterWriter : getFutureTime (),
270
+ }
271
+ }
0 commit comments