1 package azure
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import (
18 "context"
19 "encoding/json"
20 "errors"
21 "fmt"
22 "net/http"
23 "reflect"
24 "testing"
25 "time"
26
27 "github.com/Azure/go-autorest/autorest"
28 "github.com/Azure/go-autorest/autorest/mocks"
29 )
30
31 func TestCreateFromInvalidRequestVerb(t *testing.T) {
32 resp := mocks.NewResponseWithBodyAndStatus(nil, http.StatusOK, "some status")
33 resp.Request = mocks.NewRequestWithParams(http.MethodGet, mocks.TestURL, nil)
34 _, err := createPollingTracker(resp)
35 if err == nil {
36 t.Fatal("unexpected nil error")
37 }
38 }
39
40
41 func TestCreateDeleteTracker201Success(t *testing.T) {
42 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusCreated, nil)
43 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
44 pt, err := createPollingTracker(resp)
45 if err != nil {
46 t.Fatalf("failed to create tracker: %v", err)
47 }
48 if pt.pollingMethod() != PollingLocation {
49 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
50 }
51 if pt.finalGetURL() != mocks.TestLocationURL {
52 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
53 }
54 }
55
56 func TestCreateDeleteTracker201FailNoLocation(t *testing.T) {
57 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusCreated, nil)
58 _, err := createPollingTracker(resp)
59 if err == nil {
60 t.Fatal("unexpected nil error")
61 }
62 }
63
64 func TestCreateDeleteTracker201FailBadLocation(t *testing.T) {
65 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusCreated, nil)
66 mocks.SetLocationHeader(resp, mocks.TestBadURL)
67 _, err := createPollingTracker(resp)
68 if err == nil {
69 t.Fatal("unexpected nil error")
70 }
71 }
72
73 func TestCreateDeleteTracker202SuccessAsyncOp(t *testing.T) {
74 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, nil)
75 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
76 pt, err := createPollingTracker(resp)
77 if err != nil {
78 t.Fatalf("failed to create tracker: %v", err)
79 }
80 if pt.pollingMethod() != PollingAsyncOperation {
81 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
82 }
83 if pt.finalGetURL() != "" {
84 t.Fatal("expected empty GET URL")
85 }
86 }
87
88 func TestCreateDeleteTracker202SuccessLocation(t *testing.T) {
89 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, nil)
90 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
91 pt, err := createPollingTracker(resp)
92 if err != nil {
93 t.Fatalf("failed to create tracker: %v", err)
94 }
95 if pt.pollingMethod() != PollingLocation {
96 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
97 }
98 if pt.finalGetURL() != mocks.TestLocationURL {
99 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
100 }
101 }
102
103 func TestCreateDeleteTracker202SuccessBoth(t *testing.T) {
104 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, nil)
105 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
106 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
107 pt, err := createPollingTracker(resp)
108 if err != nil {
109 t.Fatalf("failed to create tracker: %v", err)
110 }
111 if pt.pollingMethod() != PollingAsyncOperation {
112 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
113 }
114 if pt.finalGetURL() != mocks.TestLocationURL {
115 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
116 }
117 }
118
119 func TestCreateDeleteTracker202SuccessBadLocation(t *testing.T) {
120 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, nil)
121 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
122 mocks.SetLocationHeader(resp, mocks.TestBadURL)
123 pt, err := createPollingTracker(resp)
124 if err != nil {
125 t.Fatalf("failed to create tracker: %v", err)
126 }
127 if pt.pollingMethod() != PollingAsyncOperation {
128 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
129 }
130 if pt.finalGetURL() != "" {
131 t.Fatal("expected empty GET URL")
132 }
133 }
134
135 func TestCreateDeleteTracker202FailBadAsyncOp(t *testing.T) {
136 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, nil)
137 setAsyncOpHeader(resp, mocks.TestBadURL)
138 _, err := createPollingTracker(resp)
139 if err == nil {
140 t.Fatal("unexpected nil error")
141 }
142 }
143
144 func TestCreateDeleteTracker202FailBadLocation(t *testing.T) {
145 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, nil)
146 mocks.SetLocationHeader(resp, mocks.TestBadURL)
147 _, err := createPollingTracker(resp)
148 if err == nil {
149 t.Fatal("unexpected nil error")
150 }
151 }
152
153
154
155 func TestCreatePatchTracker201Success(t *testing.T) {
156 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusCreated, nil)
157 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
158 pt, err := createPollingTracker(resp)
159 if err != nil {
160 t.Fatalf("failed to create tracker: %v", err)
161 }
162 if pt.pollingMethod() != PollingAsyncOperation {
163 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
164 }
165 if pt.finalGetURL() != mocks.TestURL {
166 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
167 }
168 }
169
170 func TestCreatePatchTracker201SuccessNoHeaders(t *testing.T) {
171 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusCreated, nil)
172 pt, err := createPollingTracker(resp)
173 if err != nil {
174 t.Fatalf("failed to create tracker: %v", err)
175 }
176 if pt.pollingMethod() != PollingRequestURI {
177 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
178 }
179 if pt.finalGetURL() != mocks.TestURL {
180 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
181 }
182 }
183
184 func TestCreatePatchTracker201FailBadAsyncOp(t *testing.T) {
185 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusCreated, nil)
186 setAsyncOpHeader(resp, mocks.TestBadURL)
187 _, err := createPollingTracker(resp)
188 if err == nil {
189 t.Fatal("unexpected nil error")
190 }
191 }
192
193 func TestCreatePatchTracker202SuccessAsyncOp(t *testing.T) {
194 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusAccepted, nil)
195 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
196 pt, err := createPollingTracker(resp)
197 if err != nil {
198 t.Fatalf("failed to create tracker: %v", err)
199 }
200 if pt.pollingMethod() != PollingAsyncOperation {
201 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
202 }
203 if pt.finalGetURL() != mocks.TestURL {
204 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
205 }
206 }
207
208 func TestCreatePatchTracker202SuccessLocation(t *testing.T) {
209 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusAccepted, nil)
210 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
211 pt, err := createPollingTracker(resp)
212 if err != nil {
213 t.Fatalf("failed to create tracker: %v", err)
214 }
215 if pt.pollingMethod() != PollingLocation {
216 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
217 }
218 if pt.finalGetURL() != mocks.TestURL {
219 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
220 }
221 }
222
223 func TestCreatePatchTracker202SuccessBoth(t *testing.T) {
224 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusAccepted, nil)
225 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
226 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
227 pt, err := createPollingTracker(resp)
228 if err != nil {
229 t.Fatalf("failed to create tracker: %v", err)
230 }
231 if pt.pollingMethod() != PollingAsyncOperation {
232 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
233 }
234 if pt.finalGetURL() != mocks.TestURL {
235 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
236 }
237 }
238
239 func TestCreatePatchTracker202FailBadAsyncOp(t *testing.T) {
240 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusAccepted, nil)
241 setAsyncOpHeader(resp, mocks.TestBadURL)
242 _, err := createPollingTracker(resp)
243 if err == nil {
244 t.Fatal("unexpected nil error")
245 }
246 }
247
248 func TestCreatePatchTracker202FailBadLocation(t *testing.T) {
249 resp := newAsyncResp(newAsyncReq(http.MethodPatch, nil), http.StatusAccepted, nil)
250 mocks.SetLocationHeader(resp, mocks.TestBadURL)
251 _, err := createPollingTracker(resp)
252 if err == nil {
253 t.Fatal("unexpected nil error")
254 }
255 }
256
257
258
259 func TestCreatePostTracker201Success(t *testing.T) {
260 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusCreated, nil)
261 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
262 pt, err := createPollingTracker(resp)
263 if err != nil {
264 t.Fatalf("failed to create tracker: %v", err)
265 }
266 if pt.pollingMethod() != PollingLocation {
267 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
268 }
269 if pt.finalGetURL() != mocks.TestLocationURL {
270 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
271 }
272 }
273
274 func TestCreatePostTracker201FailNoHeader(t *testing.T) {
275 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusCreated, nil)
276 _, err := createPollingTracker(resp)
277 if err == nil {
278 t.Fatal("unexpected nil err")
279 }
280 }
281
282 func TestCreatePostTracker201FailBadHeader(t *testing.T) {
283 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusCreated, nil)
284 mocks.SetLocationHeader(resp, mocks.TestBadURL)
285 _, err := createPollingTracker(resp)
286 if err == nil {
287 t.Fatal("unexpected nil err")
288 }
289 }
290
291 func TestCreatePostTracker202SuccessAsyncOp(t *testing.T) {
292 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusAccepted, nil)
293 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
294 pt, err := createPollingTracker(resp)
295 if err != nil {
296 t.Fatalf("failed to create tracker: %v", err)
297 }
298 if pt.pollingMethod() != PollingAsyncOperation {
299 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
300 }
301 if pt.finalGetURL() != "" {
302 t.Fatal("expected empty final GET URL")
303 }
304 }
305
306 func TestCreatePostTracker202SuccessLocation(t *testing.T) {
307 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusAccepted, nil)
308 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
309 pt, err := createPollingTracker(resp)
310 if err != nil {
311 t.Fatalf("failed to create tracker: %v", err)
312 }
313 if pt.pollingMethod() != PollingLocation {
314 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
315 }
316 if pt.finalGetURL() != mocks.TestLocationURL {
317 t.Fatalf("wrong final GET URI: %s", pt.finalGetURL())
318 }
319 }
320
321 func TestCreatePostTracker202SuccessBoth(t *testing.T) {
322 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusAccepted, nil)
323 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
324 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
325 pt, err := createPollingTracker(resp)
326 if err != nil {
327 t.Fatalf("failed to create tracker: %v", err)
328 }
329 if pt.pollingMethod() != PollingAsyncOperation {
330 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
331 }
332 if pt.finalGetURL() != mocks.TestLocationURL {
333 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
334 }
335 }
336
337 func TestCreatePostTracker202SuccessBadLocation(t *testing.T) {
338 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusAccepted, nil)
339 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
340 mocks.SetLocationHeader(resp, mocks.TestBadURL)
341 pt, err := createPollingTracker(resp)
342 if err != nil {
343 t.Fatalf("failed to create tracker: %v", err)
344 }
345 if pt.pollingMethod() != PollingAsyncOperation {
346 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
347 }
348 if pt.finalGetURL() != "" {
349 t.Fatal("expected empty final GET URL")
350 }
351 }
352
353 func TestCreatePostTracker202FailBadAsyncOp(t *testing.T) {
354 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusAccepted, nil)
355 setAsyncOpHeader(resp, mocks.TestBadURL)
356 _, err := createPollingTracker(resp)
357 if err == nil {
358 t.Fatal("unexpected nil error")
359 }
360 }
361
362 func TestCreatePostTracker202FailBadLocation(t *testing.T) {
363 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusAccepted, nil)
364 _, err := createPollingTracker(resp)
365 mocks.SetLocationHeader(resp, mocks.TestBadURL)
366 if err == nil {
367 t.Fatal("unexpected nil error")
368 }
369 }
370
371
372
373 func TestCreatePutTracker201SuccessAsyncOp(t *testing.T) {
374 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusCreated, nil)
375 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
376 pt, err := createPollingTracker(resp)
377 if err != nil {
378 t.Fatalf("failed to create tracker: %v", err)
379 }
380 if pt.pollingMethod() != PollingAsyncOperation {
381 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
382 }
383 if pt.finalGetURL() != mocks.TestURL {
384 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
385 }
386 }
387
388 func TestCreatePutTracker201SuccessNoHeaders(t *testing.T) {
389 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusCreated, nil)
390 pt, err := createPollingTracker(resp)
391 if err != nil {
392 t.Fatalf("failed to create tracker: %v", err)
393 }
394 if pt.pollingMethod() != PollingRequestURI {
395 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
396 }
397 if pt.finalGetURL() != mocks.TestURL {
398 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
399 }
400 }
401
402 func TestCreatePutTracker201FailBadAsyncOp(t *testing.T) {
403 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusCreated, nil)
404 setAsyncOpHeader(resp, mocks.TestBadURL)
405 _, err := createPollingTracker(resp)
406 if err == nil {
407 t.Fatal("unexpected nil error")
408 }
409 }
410
411 func TestCreatePutTracker202SuccessAsyncOp(t *testing.T) {
412 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
413 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
414 pt, err := createPollingTracker(resp)
415 if err != nil {
416 t.Fatalf("failed to create tracker: %v", err)
417 }
418 if pt.pollingMethod() != PollingAsyncOperation {
419 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
420 }
421 if pt.finalGetURL() != mocks.TestURL {
422 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
423 }
424 }
425
426 func TestCreatePutTracker202SuccessLocation(t *testing.T) {
427 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
428 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
429 pt, err := createPollingTracker(resp)
430 if err != nil {
431 t.Fatalf("failed to create tracker: %v", err)
432 }
433 if pt.pollingMethod() != PollingLocation {
434 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
435 }
436 if pt.finalGetURL() != resp.Request.URL.String() {
437 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
438 }
439 }
440
441 func TestCreatePutTracker202SuccessBoth(t *testing.T) {
442 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
443 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
444 mocks.SetLocationHeader(resp, mocks.TestLocationURL)
445 pt, err := createPollingTracker(resp)
446 if err != nil {
447 t.Fatalf("failed to create tracker: %v", err)
448 }
449 if pt.pollingMethod() != PollingAsyncOperation {
450 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
451 }
452 if pt.finalGetURL() != resp.Request.URL.String() {
453 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
454 }
455 }
456
457 func TestCreatePutTracker202SuccessBadLocation(t *testing.T) {
458 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
459 setAsyncOpHeader(resp, mocks.TestAzureAsyncURL)
460 mocks.SetLocationHeader(resp, mocks.TestBadURL)
461 pt, err := createPollingTracker(resp)
462 if err != nil {
463 t.Fatalf("failed to create tracker: %v", err)
464 }
465 if pt.pollingMethod() != PollingAsyncOperation {
466 t.Fatalf("wrong polling method: %s", pt.pollingMethod())
467 }
468 if pt.finalGetURL() != mocks.TestURL {
469 t.Fatalf("wrong final GET URL: %s", pt.finalGetURL())
470 }
471 }
472
473 func TestCreatePutTracker202FailBadAsyncOp(t *testing.T) {
474 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
475 setAsyncOpHeader(resp, mocks.TestBadURL)
476 _, err := createPollingTracker(resp)
477 if err == nil {
478 t.Fatal("unexpected nil error")
479 }
480 }
481
482 func TestPollPutTrackerSuccessNoHeaders(t *testing.T) {
483 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
484 pt, err := createPollingTracker(resp)
485 if err != nil {
486 t.Fatalf("failed to create tracker: %v", err)
487 }
488 sender := mocks.NewSender()
489 sender.AppendResponse(newProvisioningStatusResponse("InProgress"))
490 err = pt.pollForStatus(context.Background(), sender)
491 if err != nil {
492 t.Fatalf("failed to poll for status: %v", err)
493 }
494 err = pt.checkForErrors()
495 if err != nil {
496 t.Fatalf("unexpected error: %v", err)
497 }
498 }
499
500 func TestPollPutTrackerFailNoHeadersEmptyBody(t *testing.T) {
501 resp := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusAccepted, nil)
502 pt, err := createPollingTracker(resp)
503 if err != nil {
504 t.Fatalf("failed to create tracker: %v", err)
505 }
506 sender := mocks.NewSender()
507 sender.AppendResponse(mocks.NewResponseWithBodyAndStatus(&mocks.Body{}, http.StatusOK, "status ok"))
508 err = pt.pollForStatus(context.Background(), sender)
509 if err != nil {
510 t.Fatalf("failed to poll for status: %v", err)
511 }
512 err = pt.checkForErrors()
513 if err == nil {
514 t.Fatalf("unexpected nil error")
515 }
516 }
517
518
519
520 func TestAsyncPollingReturnsWrappedError(t *testing.T) {
521 resp := newSimpleAsyncResp()
522 pt, err := createPollingTracker(resp)
523 if err != nil {
524 t.Fatalf("failed to create tracker: %v", err)
525 }
526 sender := mocks.NewSender()
527 sender.AppendResponse(newOperationResourceErrorResponse("Failed"))
528 err = pt.pollForStatus(context.Background(), sender)
529 if err == nil {
530 t.Fatal("unexpected nil polling error")
531 }
532 err = pt.pollingError()
533 if err == nil {
534 t.Fatal("unexpected nil polling error")
535 }
536 if se, ok := err.(*ServiceError); !ok {
537 t.Fatal("incorrect error type")
538 } else if se.Code == "" {
539 t.Fatal("empty service error code")
540 } else if se.Message == "" {
541 t.Fatal("empty service error message")
542 }
543 }
544
545 func TestLocationPollingReturnsWrappedError(t *testing.T) {
546 resp := newSimpleLocationResp()
547 pt, err := createPollingTracker(resp)
548 if err != nil {
549 t.Fatalf("failed to create tracker: %v", err)
550 }
551 sender := mocks.NewSender()
552 sender.AppendResponse(newProvisioningStatusErrorResponse("Failed"))
553 err = pt.pollForStatus(context.Background(), sender)
554 if err == nil {
555 t.Fatal("unexpected nil polling error")
556 }
557 err = pt.pollingError()
558 if err == nil {
559 t.Fatal("unexpected nil polling error")
560 }
561 if se, ok := err.(*ServiceError); !ok {
562 t.Fatal("incorrect error type")
563 } else if se.Code == "" {
564 t.Fatal("empty service error code")
565 } else if se.Message == "" {
566 t.Fatal("empty service error message")
567 }
568 }
569
570 func TestLocationPollingReturnsUnwrappedError(t *testing.T) {
571 resp := newSimpleLocationResp()
572 pt, err := createPollingTracker(resp)
573 if err != nil {
574 t.Fatalf("failed to create tracker: %v", err)
575 }
576 sender := mocks.NewSender()
577 sender.AppendResponse(newProvisioningStatusUnwrappedErrorResponse("Failed"))
578 err = pt.pollForStatus(context.Background(), sender)
579 if err == nil {
580 t.Fatal("unexpected nil polling error")
581 }
582 err = pt.pollingError()
583 if err == nil {
584 t.Fatal("unexpected nil polling error")
585 }
586 if se, ok := err.(*ServiceError); !ok {
587 t.Fatal("incorrect error type")
588 } else if se.Code == "" {
589 t.Fatal("empty service error code")
590 } else if se.Message == "" {
591 t.Fatal("empty service error message")
592 }
593 }
594
595 func TestFuture_PollsUntilProvisioningStatusSucceeds(t *testing.T) {
596 r2 := newOperationResourceResponse("busy")
597 r3 := newOperationResourceResponse(operationSucceeded)
598
599 sender := mocks.NewSender()
600 ctx := context.Background()
601 sender.AppendAndRepeatResponse(r2, 2)
602 sender.AppendResponse(r3)
603
604 future, err := NewFutureFromResponse(newSimpleAsyncResp())
605 if err != nil {
606 t.Fatalf("failed to create future: %v", err)
607 }
608
609 for done, err := future.DoneWithContext(ctx, sender); !done; done, err = future.DoneWithContext(ctx, sender) {
610 if future.PollingMethod() != PollingAsyncOperation {
611 t.Fatalf("wrong future polling method: %s", future.PollingMethod())
612 }
613 if err != nil {
614 t.Fatalf("polling Done failed: %v", err)
615 }
616 delay, ok := future.GetPollingDelay()
617 if !ok {
618 t.Fatalf("expected Retry-After value")
619 }
620 time.Sleep(delay)
621 }
622
623 if sender.Attempts() < sender.NumResponses() {
624 t.Fatalf("stopped polling before receiving a terminated OperationResource")
625 }
626
627 autorest.Respond(future.Response(),
628 autorest.ByClosing())
629 }
630
631 func TestFuture_MarshallingSuccess(t *testing.T) {
632 future, err := NewFutureFromResponse(newSimpleAsyncResp())
633 if err != nil {
634 t.Fatalf("failed to create future: %v", err)
635 }
636
637 data, err := json.Marshal(future)
638 if err != nil {
639 t.Fatalf("failed to marshal: %v", err)
640 }
641
642 var future2 Future
643 err = json.Unmarshal(data, &future2)
644 if err != nil {
645 t.Fatalf("failed to unmarshal: %v", err)
646 }
647
648 if reflect.DeepEqual(future.pt, future2.pt) {
649 t.Fatalf("marshalling unexpected match")
650 }
651
652
653 future.pt.(*pollingTrackerPut).resp = nil
654 future.pt.(*pollingTrackerPut).rawBody = nil
655 if !reflect.DeepEqual(future.pt, future2.pt) {
656 t.Fatalf("marshalling futures don't match")
657 }
658 }
659
660 func TestFuture_MarshallingWithError(t *testing.T) {
661 r2 := newOperationResourceResponse("busy")
662 r3 := newOperationResourceErrorResponse(operationFailed)
663
664 sender := mocks.NewSender()
665 sender.AppendAndRepeatResponse(r2, 2)
666 sender.AppendResponse(r3)
667 client := autorest.Client{
668 PollingDelay: 1 * time.Second,
669 PollingDuration: autorest.DefaultPollingDuration,
670 RetryAttempts: autorest.DefaultRetryAttempts,
671 RetryDuration: 1 * time.Second,
672 Sender: sender,
673 }
674
675 future, err := NewFutureFromResponse(newSimpleAsyncResp())
676 if err != nil {
677 t.Fatalf("failed to create future: %v", err)
678 }
679
680 err = future.WaitForCompletionRef(context.Background(), client)
681 if err == nil {
682 t.Fatal("expected non-nil error")
683 }
684
685 data, err := json.Marshal(future)
686 if err != nil {
687 t.Fatalf("failed to marshal: %v", err)
688 }
689
690 var future2 Future
691 err = json.Unmarshal(data, &future2)
692 if err != nil {
693 t.Fatalf("failed to unmarshal: %v", err)
694 }
695
696 if reflect.DeepEqual(future.pt, future2.pt) {
697 t.Fatalf("marshalling unexpected match")
698 }
699
700
701 future.pt.(*pollingTrackerPut).resp = nil
702 future.pt.(*pollingTrackerPut).rawBody = nil
703 if !reflect.DeepEqual(future.pt, future2.pt) {
704 t.Fatalf("marshalling futures don't match")
705 }
706 }
707
708 func TestFuture_CreateFromFailedOperation(t *testing.T) {
709 _, err := NewFutureFromResponse(newAsyncResponseWithError(http.MethodPut))
710 if err == nil {
711 t.Fatal("expected non-nil error")
712 }
713 }
714
715 func TestFuture_WaitForCompletionRef(t *testing.T) {
716 r2 := newOperationResourceResponse("busy")
717 r3 := newOperationResourceResponse(operationSucceeded)
718
719 sender := mocks.NewSender()
720 sender.AppendAndRepeatResponse(r2, 2)
721 sender.AppendResponse(r3)
722 client := autorest.Client{
723 PollingDelay: 1 * time.Second,
724 PollingDuration: autorest.DefaultPollingDuration,
725 RetryAttempts: autorest.DefaultRetryAttempts,
726 RetryDuration: 1 * time.Second,
727 Sender: sender,
728 }
729
730 future, err := NewFutureFromResponse(newSimpleAsyncResp())
731 if err != nil {
732 t.Fatalf("failed to create future: %v", err)
733 }
734
735 err = future.WaitForCompletionRef(context.Background(), client)
736 if err != nil {
737 t.Fatalf("WaitForCompletion returned non-nil error")
738 }
739
740 if sender.Attempts() < sender.NumResponses() {
741 t.Fatalf("stopped polling before receiving a terminated OperationResource")
742 }
743
744 autorest.Respond(future.Response(),
745 autorest.ByClosing())
746 }
747
748 func TestFuture_WaitForCompletionRefWithRetryAfter(t *testing.T) {
749 r2 := newOperationResourceResponse("busy")
750 r3 := newOperationResourceResponse(operationSucceeded)
751
752 sender := mocks.NewSender()
753 sender.AppendAndRepeatResponse(r2, 2)
754 sender.AppendResponse(r3)
755 client := autorest.Client{
756 PollingDelay: 1 * time.Second,
757 PollingDuration: autorest.DefaultPollingDuration,
758 RetryAttempts: autorest.DefaultRetryAttempts,
759 RetryDuration: 1 * time.Second,
760 Sender: sender,
761 }
762
763 future, err := NewFutureFromResponse(newSimpleAsyncRespWithRetryAfter())
764 if err != nil {
765 t.Fatalf("failed to create future: %v", err)
766 }
767
768 err = future.WaitForCompletionRef(context.Background(), client)
769 if err != nil {
770 t.Fatalf("WaitForCompletion returned non-nil error")
771 }
772
773 if sender.Attempts() < sender.NumResponses() {
774 t.Fatalf("stopped polling before receiving a terminated OperationResource")
775 }
776
777 autorest.Respond(future.Response(),
778 autorest.ByClosing())
779 }
780
781 func TestFuture_WaitForCompletionTimedOut(t *testing.T) {
782 r2 := newProvisioningStatusResponse("busy")
783
784 sender := mocks.NewSender()
785 sender.AppendAndRepeatResponseWithDelay(r2, 1*time.Second, 5)
786
787 future, err := NewFutureFromResponse(newSimpleAsyncResp())
788 if err != nil {
789 t.Fatalf("failed to create future: %v", err)
790 }
791
792 client := autorest.Client{
793 PollingDelay: autorest.DefaultPollingDelay,
794 PollingDuration: 2 * time.Second,
795 RetryAttempts: autorest.DefaultRetryAttempts,
796 RetryDuration: 1 * time.Second,
797 Sender: sender,
798 }
799
800 err = future.WaitForCompletionRef(context.Background(), client)
801 if err == nil {
802 t.Fatalf("WaitForCompletion returned nil error, should have timed out")
803 }
804 }
805
806 func TestFuture_WaitForCompletionRetriesExceeded(t *testing.T) {
807 r1 := newProvisioningStatusResponse("InProgress")
808
809 sender := mocks.NewSender()
810 sender.AppendResponse(r1)
811 sender.AppendAndRepeatError(errors.New("transient network failure"), autorest.DefaultRetryAttempts+1)
812
813 future, err := NewFutureFromResponse(newSimpleAsyncResp())
814 if err != nil {
815 t.Fatalf("failed to create future: %v", err)
816 }
817
818 client := autorest.Client{
819 PollingDelay: autorest.DefaultPollingDelay,
820 PollingDuration: autorest.DefaultPollingDuration,
821 RetryAttempts: autorest.DefaultRetryAttempts,
822 RetryDuration: 100 * time.Millisecond,
823 Sender: sender,
824 }
825
826 err = future.WaitForCompletionRef(context.Background(), client)
827 if err == nil {
828 t.Fatalf("WaitForCompletion returned nil error, should have errored out")
829 }
830 }
831
832 func TestFuture_WaitForCompletionCancelled(t *testing.T) {
833 r1 := newProvisioningStatusResponse("InProgress")
834
835 sender := mocks.NewSender()
836 sender.AppendAndRepeatResponseWithDelay(r1, 1*time.Second, 5)
837
838 future, err := NewFutureFromResponse(newSimpleAsyncResp())
839 if err != nil {
840 t.Fatalf("failed to create future: %v", err)
841 }
842
843 client := autorest.Client{
844 PollingDelay: autorest.DefaultPollingDelay,
845 PollingDuration: autorest.DefaultPollingDuration,
846 RetryAttempts: autorest.DefaultRetryAttempts,
847 RetryDuration: autorest.DefaultRetryDuration,
848 Sender: sender,
849 }
850
851 ctx, cancel := context.WithCancel(context.Background())
852 go func() {
853 time.Sleep(2 * time.Second)
854 cancel()
855 }()
856
857 err = future.WaitForCompletionRef(ctx, client)
858 if err == nil {
859 t.Fatalf("WaitForCompletion returned nil error, should have been cancelled")
860 }
861 }
862
863 func TestFuture_GetResultFromNonAsyncOperation(t *testing.T) {
864 resp := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusOK, mocks.NewBody(someResource))
865 future, err := NewFutureFromResponse(resp)
866 if err != nil {
867 t.Fatalf("failed to create tracker: %v", err)
868 }
869 if pm := future.PollingMethod(); pm != PollingUnknown {
870 t.Fatalf("wrong polling method: %s", pm)
871 }
872 done, err := future.DoneWithContext(context.Background(), nil)
873 if err != nil {
874 t.Fatalf("failed to check status: %v", err)
875 }
876 if !done {
877 t.Fatal("operation should be done")
878 }
879 res, err := future.GetResult(nil)
880 if err != nil {
881 t.Fatalf("failed to get result: %v", err)
882 }
883 if res != resp {
884 t.Fatal("result and response don't match")
885 }
886 }
887
888 func TestFuture_GetResultNonTerminal(t *testing.T) {
889 resp := newAsyncResp(newAsyncReq(http.MethodDelete, nil), http.StatusAccepted, mocks.NewBody(fmt.Sprintf(operationResourceFormat, operationInProgress)))
890 mocks.SetResponseHeader(resp, headerAsyncOperation, mocks.TestAzureAsyncURL)
891 future, err := NewFutureFromResponse(resp)
892 if err != nil {
893 t.Fatalf("failed to create future: %v", err)
894 }
895 res, err := future.GetResult(nil)
896 if err == nil {
897 t.Fatal("expected non-nil error")
898 }
899 if res != nil {
900 t.Fatal("expected nil result")
901 }
902 }
903
904 const (
905 operationResourceIllegal = `
906 This is not JSON and should fail...badly.
907 `
908
909
910 pollingStateFormat = `
911 {
912 "unused" : {
913 "somefield" : 42
914 },
915 "properties" : {
916 "provisioningState": "%s"
917 }
918 }
919 `
920
921
922 errorResponse = `
923 {
924 "error" : {
925 "code" : "InvalidParameter",
926 "message" : "tom-service-DISCOVERY-server-base-v1.core.local' is not a valid captured VHD blob name prefix."
927 }
928 }
929 `
930
931
932 unwrappedErrorResponse = `
933 {
934 "code" : "InvalidParameter",
935 "message" : "tom-service-DISCOVERY-server-base-v1.core.local' is not a valid captured VHD blob name prefix."
936 }
937 `
938
939
940 pollingStateEmpty = `
941 {
942 "unused" : {
943 "somefield" : 42
944 },
945 "properties" : {
946 }
947 }
948 `
949
950
951 operationResourceFormat = `
952 {
953 "id": "/subscriptions/id/locations/westus/operationsStatus/sameguid",
954 "name": "sameguid",
955 "status" : "%s",
956 "startTime" : "2006-01-02T15:04:05Z",
957 "endTime" : "2006-01-02T16:04:05Z",
958 "percentComplete" : 50.00,
959 "properties" : {
960 "foo": "bar"
961 }
962 }
963 `
964
965
966 operationResourceErrorFormat = `
967 {
968 "id": "/subscriptions/id/locations/westus/operationsStatus/sameguid",
969 "name": "sameguid",
970 "status" : "%s",
971 "startTime" : "2006-01-02T15:04:05Z",
972 "endTime" : "2006-01-02T16:04:05Z",
973 "percentComplete" : 50.00,
974 "properties" : {},
975 "error" : {
976 "code" : "BadArgument",
977 "message" : "The provided database 'foo' has an invalid username."
978 }
979 }
980 `
981
982
983 someResource = `
984 {
985 "id": "/subscriptions/guid/resourceGroups/rg/providers/something/else/thing",
986 "name": "thing",
987 "type": "Imaginary.type",
988 "location": "Central US",
989 "properties": {}
990 }
991 `
992 )
993
994
995 func newAsyncReq(reqMethod string, body *mocks.Body) *http.Request {
996 return mocks.NewRequestWithParams(reqMethod, mocks.TestURL, body)
997 }
998
999
1000
1001 func newAsyncResp(req *http.Request, statusCode int, body *mocks.Body) *http.Response {
1002 status := "Unknown"
1003 switch statusCode {
1004 case http.StatusOK, http.StatusNoContent:
1005 status = "Completed"
1006 case http.StatusCreated:
1007 status = "Creating"
1008 case http.StatusAccepted:
1009 status = "In progress"
1010 case http.StatusBadRequest:
1011 status = "Bad request"
1012 }
1013 r := mocks.NewResponseWithBodyAndStatus(body, statusCode, status)
1014 r.Request = req
1015 return r
1016 }
1017
1018
1019 func newSimpleAsyncResp() *http.Response {
1020 r := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusCreated, mocks.NewBody(fmt.Sprintf(operationResourceFormat, operationInProgress)))
1021 mocks.SetResponseHeader(r, headerAsyncOperation, mocks.TestAzureAsyncURL)
1022 return r
1023 }
1024
1025 func newSimpleAsyncRespWithRetryAfter() *http.Response {
1026 r := newAsyncResp(newAsyncReq(http.MethodPut, nil), http.StatusCreated, mocks.NewBody(fmt.Sprintf(operationResourceFormat, operationInProgress)))
1027 mocks.SetResponseHeader(r, headerAsyncOperation, mocks.TestAzureAsyncURL)
1028 mocks.SetResponseHeader(r, autorest.HeaderRetryAfter, "1")
1029 return r
1030 }
1031
1032
1033 func newSimpleLocationResp() *http.Response {
1034 r := newAsyncResp(newAsyncReq(http.MethodPost, nil), http.StatusCreated, mocks.NewBody(fmt.Sprintf(pollingStateFormat, operationInProgress)))
1035 mocks.SetResponseHeader(r, autorest.HeaderLocation, mocks.TestLocationURL)
1036 return r
1037 }
1038
1039
1040 func newAsyncResponseWithError(reqMethod string) *http.Response {
1041 return newAsyncResp(newAsyncReq(reqMethod, nil), http.StatusBadRequest, mocks.NewBody(errorResponse))
1042 }
1043
1044
1045 func newOperationResourceResponse(status string) *http.Response {
1046 r := mocks.NewResponseWithBodyAndStatus(mocks.NewBody(fmt.Sprintf(operationResourceFormat, status)), http.StatusOK, status)
1047 mocks.SetRetryHeader(r, retryDelay)
1048 return r
1049 }
1050
1051
1052 func newOperationResourceErrorResponse(status string) *http.Response {
1053 return mocks.NewResponseWithBodyAndStatus(mocks.NewBody(fmt.Sprintf(operationResourceErrorFormat, status)), http.StatusBadRequest, status)
1054 }
1055
1056
1057 func newProvisioningStatusResponse(status string) *http.Response {
1058 r := mocks.NewResponseWithBodyAndStatus(mocks.NewBody(fmt.Sprintf(pollingStateFormat, status)), http.StatusOK, status)
1059 mocks.SetRetryHeader(r, retryDelay)
1060 return r
1061 }
1062
1063
1064 func newProvisioningStatusErrorResponse(status string) *http.Response {
1065 return mocks.NewResponseWithBodyAndStatus(mocks.NewBody(errorResponse), http.StatusBadRequest, status)
1066 }
1067
1068
1069 func newProvisioningStatusUnwrappedErrorResponse(status string) *http.Response {
1070 return mocks.NewResponseWithBodyAndStatus(mocks.NewBody(unwrappedErrorResponse), http.StatusBadRequest, status)
1071 }
1072
1073
1074 func setAsyncOpHeader(resp *http.Response, location string) {
1075 mocks.SetResponseHeader(resp, http.CanonicalHeaderKey(headerAsyncOperation), location)
1076 }
1077
View as plain text