1 package autorest
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import (
18 "bytes"
19 "context"
20 "fmt"
21 "log"
22 "net/http"
23 "net/http/httptest"
24 "os"
25 "reflect"
26 "sync"
27 "testing"
28 "time"
29
30 "github.com/Azure/go-autorest/autorest/mocks"
31 )
32
33 func ExampleSendWithSender() {
34 r := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
35 mocks.SetAcceptedHeaders(r)
36
37 client := mocks.NewSender()
38 client.AppendAndRepeatResponse(r, 10)
39
40 logger := log.New(os.Stdout, "autorest: ", 0)
41 na := NullAuthorizer{}
42
43 req, _ := Prepare(&http.Request{},
44 AsGet(),
45 WithBaseURL("https://microsoft.com/a/b/c/"),
46 na.WithAuthorization())
47
48 r, _ = SendWithSender(client, req,
49 WithLogging(logger),
50 DoErrorIfStatusCode(http.StatusAccepted),
51 DoCloseIfError(),
52 DoRetryForAttempts(5, time.Duration(0)))
53
54 Respond(r,
55 ByDiscardingBody(),
56 ByClosing())
57
58
59
60
61
62
63
64
65
66
67
68
69 }
70
71 func ExampleDoRetryForAttempts() {
72 client := mocks.NewSender()
73 client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10)
74
75
76 r, _ := SendWithSender(client, mocks.NewRequest(),
77 DoCloseIfError(),
78 DoRetryForAttempts(5, time.Duration(0)))
79
80 Respond(r,
81 ByDiscardingBody(),
82 ByClosing())
83
84 fmt.Printf("Retry stopped after %d attempts", client.Attempts())
85
86 }
87
88 func ExampleDoErrorIfStatusCode() {
89 client := mocks.NewSender()
90 client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 NoContent", http.StatusNoContent), 10)
91
92
93 r, _ := SendWithSender(client, mocks.NewRequest(),
94 DoErrorIfStatusCode(http.StatusNoContent),
95 DoCloseIfError(),
96 DoRetryForAttempts(5, time.Duration(0)))
97
98 Respond(r,
99 ByDiscardingBody(),
100 ByClosing())
101
102 fmt.Printf("Retry stopped after %d attempts with code %s", client.Attempts(), r.Status)
103
104 }
105
106 func TestSendWithSenderRunsDecoratorsInOrder(t *testing.T) {
107 client := mocks.NewSender()
108 s := ""
109
110 r, err := SendWithSender(client, mocks.NewRequest(),
111 withMessage(&s, "a"),
112 withMessage(&s, "b"),
113 withMessage(&s, "c"))
114 if err != nil {
115 t.Fatalf("autorest: SendWithSender returned an error (%v)", err)
116 }
117
118 Respond(r,
119 ByDiscardingBody(),
120 ByClosing())
121
122 if s != "abc" {
123 t.Fatalf("autorest: SendWithSender invoke decorators out of order; expected 'abc', received '%s'", s)
124 }
125 }
126
127 func TestCreateSender(t *testing.T) {
128 f := false
129
130 s := CreateSender(
131 (func() SendDecorator {
132 return func(s Sender) Sender {
133 return SenderFunc(func(r *http.Request) (*http.Response, error) {
134 f = true
135 return nil, nil
136 })
137 }
138 })())
139 s.Do(&http.Request{})
140
141 if !f {
142 t.Fatal("autorest: CreateSender failed to apply supplied decorator")
143 }
144 }
145
146 func TestSend(t *testing.T) {
147 f := false
148
149 Send(&http.Request{},
150 (func() SendDecorator {
151 return func(s Sender) Sender {
152 return SenderFunc(func(r *http.Request) (*http.Response, error) {
153 f = true
154 return nil, nil
155 })
156 }
157 })())
158
159 if !f {
160 t.Fatal("autorest: Send failed to apply supplied decorator")
161 }
162 }
163
164 func TestAfterDelayWaits(t *testing.T) {
165 client := mocks.NewSender()
166
167 d := 2 * time.Second
168
169 tt := time.Now()
170 r, _ := SendWithSender(client, mocks.NewRequest(),
171 AfterDelay(d))
172 s := time.Since(tt)
173 if s < d {
174 t.Fatal("autorest: AfterDelay failed to wait for at least the specified duration")
175 }
176
177 Respond(r,
178 ByDiscardingBody(),
179 ByClosing())
180 }
181
182 func TestAfterDelay_Cancels(t *testing.T) {
183 client := mocks.NewSender()
184 ctx, cancel := context.WithCancel(context.Background())
185 delay := 5 * time.Second
186
187 var wg sync.WaitGroup
188 wg.Add(1)
189 start := time.Now()
190 end := time.Now()
191 var err error
192 go func() {
193 req := mocks.NewRequest()
194 req = req.WithContext(ctx)
195 _, err = SendWithSender(client, req,
196 AfterDelay(delay))
197 end = time.Now()
198 wg.Done()
199 }()
200 cancel()
201 wg.Wait()
202 time.Sleep(5 * time.Millisecond)
203 if end.Sub(start) >= delay {
204 t.Fatal("autorest: AfterDelay elapsed")
205 }
206 if err == nil {
207 t.Fatal("autorest: AfterDelay didn't cancel")
208 }
209 }
210
211 func TestAfterDelayDoesNotWaitTooLong(t *testing.T) {
212 client := mocks.NewSender()
213
214 d := 5 * time.Millisecond
215 start := time.Now()
216 r, _ := SendWithSender(client, mocks.NewRequest(),
217 AfterDelay(d))
218
219 if time.Since(start) > (5 * d) {
220 t.Fatal("autorest: AfterDelay waited too long (exceeded 5 times specified duration)")
221 }
222
223 Respond(r,
224 ByDiscardingBody(),
225 ByClosing())
226 }
227
228 func TestAsIs(t *testing.T) {
229 client := mocks.NewSender()
230
231 r1 := mocks.NewResponse()
232 client.AppendResponse(r1)
233
234 r2, err := SendWithSender(client, mocks.NewRequest(),
235 AsIs())
236 if err != nil {
237 t.Fatalf("autorest: AsIs returned an unexpected error (%v)", err)
238 } else if !reflect.DeepEqual(r1, r2) {
239 t.Fatalf("autorest: AsIs modified the response -- received %v, expected %v", r2, r1)
240 }
241
242 Respond(r1,
243 ByDiscardingBody(),
244 ByClosing())
245 Respond(r2,
246 ByDiscardingBody(),
247 ByClosing())
248 }
249
250 func TestDoCloseIfError(t *testing.T) {
251 client := mocks.NewSender()
252 client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest))
253
254 r, _ := SendWithSender(client, mocks.NewRequest(),
255 DoErrorIfStatusCode(http.StatusBadRequest),
256 DoCloseIfError())
257
258 if r.Body.(*mocks.Body).IsOpen() {
259 t.Fatal("autorest: Expected DoCloseIfError to close response body -- it was left open")
260 }
261
262 Respond(r,
263 ByDiscardingBody(),
264 ByClosing())
265 }
266
267 func TestDoCloseIfErrorAcceptsNilResponse(t *testing.T) {
268 client := mocks.NewSender()
269
270 SendWithSender(client, mocks.NewRequest(),
271 (func() SendDecorator {
272 return func(s Sender) Sender {
273 return SenderFunc(func(r *http.Request) (*http.Response, error) {
274 resp, err := s.Do(r)
275 if err != nil {
276 resp.Body.Close()
277 }
278 return nil, fmt.Errorf("Faux Error")
279 })
280 }
281 })(),
282 DoCloseIfError())
283 }
284
285 func TestDoCloseIfErrorAcceptsNilBody(t *testing.T) {
286 client := mocks.NewSender()
287
288 SendWithSender(client, mocks.NewRequest(),
289 (func() SendDecorator {
290 return func(s Sender) Sender {
291 return SenderFunc(func(r *http.Request) (*http.Response, error) {
292 resp, err := s.Do(r)
293 if err != nil {
294 resp.Body.Close()
295 }
296 resp.Body = nil
297 return resp, fmt.Errorf("Faux Error")
298 })
299 }
300 })(),
301 DoCloseIfError())
302 }
303
304 func TestDoErrorIfStatusCode(t *testing.T) {
305 client := mocks.NewSender()
306 client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest))
307
308 r, err := SendWithSender(client, mocks.NewRequest(),
309 DoErrorIfStatusCode(http.StatusBadRequest),
310 DoCloseIfError())
311 if err == nil {
312 t.Fatal("autorest: DoErrorIfStatusCode failed to emit an error for passed code")
313 }
314
315 Respond(r,
316 ByDiscardingBody(),
317 ByClosing())
318 }
319
320 func TestDoErrorIfStatusCodeIgnoresStatusCodes(t *testing.T) {
321 client := mocks.NewSender()
322 client.AppendResponse(newAcceptedResponse())
323
324 r, err := SendWithSender(client, mocks.NewRequest(),
325 DoErrorIfStatusCode(http.StatusBadRequest),
326 DoCloseIfError())
327 if err != nil {
328 t.Fatal("autorest: DoErrorIfStatusCode failed to ignore a status code")
329 }
330
331 Respond(r,
332 ByDiscardingBody(),
333 ByClosing())
334 }
335
336 func TestDoErrorUnlessStatusCode(t *testing.T) {
337 client := mocks.NewSender()
338 client.AppendResponse(mocks.NewResponseWithStatus("400 BadRequest", http.StatusBadRequest))
339
340 r, err := SendWithSender(client, mocks.NewRequest(),
341 DoErrorUnlessStatusCode(http.StatusAccepted),
342 DoCloseIfError())
343 if err == nil {
344 t.Fatal("autorest: DoErrorUnlessStatusCode failed to emit an error for an unknown status code")
345 }
346
347 Respond(r,
348 ByDiscardingBody(),
349 ByClosing())
350 }
351
352 func TestDoErrorUnlessStatusCodeIgnoresStatusCodes(t *testing.T) {
353 client := mocks.NewSender()
354 client.AppendResponse(newAcceptedResponse())
355
356 r, err := SendWithSender(client, mocks.NewRequest(),
357 DoErrorUnlessStatusCode(http.StatusAccepted),
358 DoCloseIfError())
359 if err != nil {
360 t.Fatal("autorest: DoErrorUnlessStatusCode emitted an error for a knonwn status code")
361 }
362
363 Respond(r,
364 ByDiscardingBody(),
365 ByClosing())
366 }
367
368 func TestDoRetryForAttemptsStopsAfterSuccess(t *testing.T) {
369 client := mocks.NewSender()
370
371 r, err := SendWithSender(client, mocks.NewRequest(),
372 DoRetryForAttempts(5, time.Duration(0)))
373 if client.Attempts() != 1 {
374 t.Fatalf("autorest: DoRetryForAttempts failed to stop after success -- expected attempts %v, actual %v",
375 1, client.Attempts())
376 }
377 if err != nil {
378 t.Fatalf("autorest: DoRetryForAttempts returned an unexpected error (%v)", err)
379 }
380
381 Respond(r,
382 ByDiscardingBody(),
383 ByClosing())
384 }
385
386 func TestDoRetryForAttemptsStopsAfterAttempts(t *testing.T) {
387 client := mocks.NewSender()
388 client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10)
389
390 r, err := SendWithSender(client, mocks.NewRequest(),
391 DoRetryForAttempts(5, time.Duration(0)),
392 DoCloseIfError())
393 if err == nil {
394 t.Fatal("autorest: Mock client failed to emit errors")
395 }
396
397 Respond(r,
398 ByDiscardingBody(),
399 ByClosing())
400
401 if client.Attempts() != 5 {
402 t.Fatal("autorest: DoRetryForAttempts failed to stop after specified number of attempts")
403 }
404 }
405
406 func TestDoRetryForAttemptsReturnsResponse(t *testing.T) {
407 client := mocks.NewSender()
408 client.SetError(fmt.Errorf("Faux Error"))
409
410 r, err := SendWithSender(client, mocks.NewRequest(),
411 DoRetryForAttempts(1, time.Duration(0)))
412 if err == nil {
413 t.Fatal("autorest: Mock client failed to emit errors")
414 }
415
416 if r == nil {
417 t.Fatal("autorest: DoRetryForAttempts failed to return the underlying response")
418 }
419
420 Respond(r,
421 ByDiscardingBody(),
422 ByClosing())
423 }
424
425 func TestDoRetryForDurationStopsAfterSuccess(t *testing.T) {
426 client := mocks.NewSender()
427
428 r, err := SendWithSender(client, mocks.NewRequest(),
429 DoRetryForDuration(10*time.Millisecond, time.Duration(0)))
430 if client.Attempts() != 1 {
431 t.Fatalf("autorest: DoRetryForDuration failed to stop after success -- expected attempts %v, actual %v",
432 1, client.Attempts())
433 }
434 if err != nil {
435 t.Fatalf("autorest: DoRetryForDuration returned an unexpected error (%v)", err)
436 }
437
438 Respond(r,
439 ByDiscardingBody(),
440 ByClosing())
441 }
442
443 func TestDoRetryForDurationStopsAfterDuration(t *testing.T) {
444 client := mocks.NewSender()
445 client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1)
446
447 d := 5 * time.Millisecond
448 start := time.Now()
449 r, err := SendWithSender(client, mocks.NewRequest(),
450 DoRetryForDuration(d, time.Duration(0)),
451 DoCloseIfError())
452 if err == nil {
453 t.Fatal("autorest: Mock client failed to emit errors")
454 }
455
456 if time.Since(start) < d {
457 t.Fatal("autorest: DoRetryForDuration failed stopped too soon")
458 }
459
460 Respond(r,
461 ByDiscardingBody(),
462 ByClosing())
463 }
464
465 func TestDoRetryForDurationStopsWithinReason(t *testing.T) {
466 client := mocks.NewSender()
467 client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1)
468
469 d := 5 * time.Second
470 start := time.Now()
471 r, err := SendWithSender(client, mocks.NewRequest(),
472 DoRetryForDuration(d, time.Duration(0)),
473 DoCloseIfError())
474 if err == nil {
475 t.Fatal("autorest: Mock client failed to emit errors")
476 }
477
478 if time.Since(start) > (5 * d) {
479 t.Fatal("autorest: DoRetryForDuration failed stopped soon enough (exceeded 5 times specified duration)")
480 }
481
482 Respond(r,
483 ByDiscardingBody(),
484 ByClosing())
485 }
486
487 func TestDoRetryForDurationReturnsResponse(t *testing.T) {
488 client := mocks.NewSender()
489 client.SetAndRepeatError(fmt.Errorf("Faux Error"), -1)
490
491 r, err := SendWithSender(client, mocks.NewRequest(),
492 DoRetryForDuration(10*time.Millisecond, time.Duration(0)),
493 DoCloseIfError())
494 if err == nil {
495 t.Fatal("autorest: Mock client failed to emit errors")
496 }
497
498 if r == nil {
499 t.Fatal("autorest: DoRetryForDuration failed to return the underlying response")
500 }
501
502 Respond(r,
503 ByDiscardingBody(),
504 ByClosing())
505 }
506
507 func TestDelayForBackoff(t *testing.T) {
508 d := 2 * time.Second
509 start := time.Now()
510 DelayForBackoff(d, 0, nil)
511 if time.Since(start) < d {
512 t.Fatal("autorest: DelayForBackoff did not delay as long as expected")
513 }
514 }
515
516 func TestDelayForBackoffWithCap(t *testing.T) {
517 d := 2 * time.Second
518 start := time.Now()
519 DelayForBackoffWithCap(d, 1*time.Second, 0, nil)
520 if time.Since(start) >= d {
521 t.Fatal("autorest: DelayForBackoffWithCap delayed for too long")
522 }
523 }
524
525 func TestDelayForBackoff_Cancels(t *testing.T) {
526 cancel := make(chan struct{})
527 delay := 5 * time.Second
528
529 var wg sync.WaitGroup
530 wg.Add(1)
531 start := time.Now()
532 go func() {
533 wg.Done()
534 DelayForBackoff(delay, 0, cancel)
535 }()
536 wg.Wait()
537 close(cancel)
538 time.Sleep(5 * time.Millisecond)
539 if time.Since(start) >= delay {
540 t.Fatal("autorest: DelayForBackoff failed to cancel")
541 }
542 }
543
544 func TestDelayForBackoffWithinReason(t *testing.T) {
545 d := 5 * time.Second
546 maxCoefficient := 2
547 start := time.Now()
548 DelayForBackoff(d, 0, nil)
549 if time.Since(start) > (time.Duration(maxCoefficient) * d) {
550
551 t.Fatalf("autorest: DelayForBackoff delayed too long (exceeded %d times the specified duration)", maxCoefficient)
552 }
553 }
554
555 func TestDoPollForStatusCodes_IgnoresUnspecifiedStatusCodes(t *testing.T) {
556 client := mocks.NewSender()
557
558 r, _ := SendWithSender(client, mocks.NewRequest(),
559 DoPollForStatusCodes(time.Duration(0), time.Duration(0)))
560
561 if client.Attempts() != 1 {
562 t.Fatalf("autorest: Sender#DoPollForStatusCodes polled for unspecified status code")
563 }
564
565 Respond(r,
566 ByDiscardingBody(),
567 ByClosing())
568 }
569
570 func TestDoPollForStatusCodes_PollsForSpecifiedStatusCodes(t *testing.T) {
571 client := mocks.NewSender()
572 client.AppendResponse(newAcceptedResponse())
573
574 r, _ := SendWithSender(client, mocks.NewRequest(),
575 DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
576
577 if client.Attempts() != 2 {
578 t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to poll for specified status code")
579 }
580
581 Respond(r,
582 ByDiscardingBody(),
583 ByClosing())
584 }
585
586 func TestDoPollForStatusCodes_CanBeCanceled(t *testing.T) {
587 cancel := make(chan struct{})
588 delay := 5 * time.Second
589
590 r := mocks.NewResponse()
591 mocks.SetAcceptedHeaders(r)
592 client := mocks.NewSender()
593 client.AppendAndRepeatResponse(r, 100)
594
595 var wg sync.WaitGroup
596 wg.Add(1)
597 start := time.Now()
598 go func() {
599 wg.Done()
600 r, _ := SendWithSender(client, mocks.NewRequest(),
601 DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
602 Respond(r,
603 ByDiscardingBody(),
604 ByClosing())
605 }()
606 wg.Wait()
607 close(cancel)
608 time.Sleep(5 * time.Millisecond)
609 if time.Since(start) >= delay {
610 t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to cancel")
611 }
612 }
613
614 func TestDoPollForStatusCodes_ClosesAllNonreturnedResponseBodiesWhenPolling(t *testing.T) {
615 resp := newAcceptedResponse()
616
617 client := mocks.NewSender()
618 client.AppendAndRepeatResponse(resp, 2)
619
620 r, _ := SendWithSender(client, mocks.NewRequest(),
621 DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
622
623 if resp.Body.(*mocks.Body).IsOpen() || resp.Body.(*mocks.Body).CloseAttempts() < 2 {
624 t.Fatalf("autorest: Sender#DoPollForStatusCodes did not close unreturned response bodies")
625 }
626
627 Respond(r,
628 ByDiscardingBody(),
629 ByClosing())
630 }
631
632 func TestDoPollForStatusCodes_LeavesLastResponseBodyOpen(t *testing.T) {
633 client := mocks.NewSender()
634 client.AppendResponse(newAcceptedResponse())
635
636 r, _ := SendWithSender(client, mocks.NewRequest(),
637 DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
638
639 if !r.Body.(*mocks.Body).IsOpen() {
640 t.Fatalf("autorest: Sender#DoPollForStatusCodes did not leave open the body of the last response")
641 }
642
643 Respond(r,
644 ByDiscardingBody(),
645 ByClosing())
646 }
647
648 func TestDoPollForStatusCodes_StopsPollingAfterAnError(t *testing.T) {
649 client := mocks.NewSender()
650 client.AppendAndRepeatResponse(newAcceptedResponse(), 5)
651 client.SetError(fmt.Errorf("Faux Error"))
652 client.SetEmitErrorAfter(1)
653
654 r, _ := SendWithSender(client, mocks.NewRequest(),
655 DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
656
657 if client.Attempts() > 2 {
658 t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to stop polling after receiving an error")
659 }
660
661 Respond(r,
662 ByDiscardingBody(),
663 ByClosing())
664 }
665
666 func TestDoPollForStatusCodes_ReturnsPollingError(t *testing.T) {
667 client := mocks.NewSender()
668 client.AppendAndRepeatResponse(newAcceptedResponse(), 5)
669 client.SetError(fmt.Errorf("Faux Error"))
670 client.SetEmitErrorAfter(1)
671
672 r, err := SendWithSender(client, mocks.NewRequest(),
673 DoPollForStatusCodes(time.Millisecond, time.Millisecond, http.StatusAccepted))
674
675 if err == nil {
676 t.Fatalf("autorest: Sender#DoPollForStatusCodes failed to return error from polling")
677 }
678
679 Respond(r,
680 ByDiscardingBody(),
681 ByClosing())
682 }
683
684 func TestWithLogging_Logs(t *testing.T) {
685 buf := &bytes.Buffer{}
686 logger := log.New(buf, "autorest: ", 0)
687 client := mocks.NewSender()
688
689 r, _ := SendWithSender(client, &http.Request{},
690 WithLogging(logger))
691
692 if buf.String() == "" {
693 t.Fatal("autorest: Sender#WithLogging failed to log the request")
694 }
695
696 Respond(r,
697 ByDiscardingBody(),
698 ByClosing())
699 }
700
701 func TestWithLogging_HandlesMissingResponse(t *testing.T) {
702 buf := &bytes.Buffer{}
703 logger := log.New(buf, "autorest: ", 0)
704 client := mocks.NewSender()
705 client.AppendResponse(nil)
706 client.SetError(fmt.Errorf("Faux Error"))
707
708 r, err := SendWithSender(client, &http.Request{},
709 WithLogging(logger))
710
711 if r != nil || err == nil {
712 t.Fatal("autorest: Sender#WithLogging returned a valid response -- expecting nil")
713 }
714 if buf.String() == "" {
715 t.Fatal("autorest: Sender#WithLogging failed to log the request for a nil response")
716 }
717
718 Respond(r,
719 ByDiscardingBody(),
720 ByClosing())
721 }
722
723 func TestDoRetryForStatusCodesWithSuccess(t *testing.T) {
724 client := mocks.NewSender()
725 client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("408 Request Timeout", http.StatusRequestTimeout), 2)
726 client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
727
728 r, _ := SendWithSender(client, mocks.NewRequest(),
729 DoRetryForStatusCodes(5, time.Duration(2*time.Second), http.StatusRequestTimeout),
730 )
731
732 Respond(r,
733 ByDiscardingBody(),
734 ByClosing())
735
736 if client.Attempts() != 3 {
737 t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ",
738 r.Status, client.Attempts()-1)
739 }
740 }
741
742 func TestDoRetryForStatusCodesWithNoSuccess(t *testing.T) {
743 client := mocks.NewSender()
744 client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("504 Gateway Timeout", http.StatusGatewayTimeout), 5)
745
746 r, _ := SendWithSender(client, mocks.NewRequest(),
747 DoRetryForStatusCodes(2, time.Duration(2*time.Second), http.StatusGatewayTimeout),
748 )
749 Respond(r,
750 ByDiscardingBody(),
751 ByClosing())
752
753 if client.Attempts() != 3 {
754 t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: failed stop after %v retry attempts; Want: Stop after 2 retry attempts",
755 client.Attempts()-1)
756 }
757 }
758
759 func TestDoRetryForStatusCodes_CodeNotInRetryList(t *testing.T) {
760 client := mocks.NewSender()
761 client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 No Content", http.StatusNoContent), 1)
762
763 r, _ := SendWithSender(client, mocks.NewRequest(),
764 DoRetryForStatusCodes(6, time.Duration(2*time.Second), http.StatusGatewayTimeout),
765 )
766
767 Respond(r,
768 ByDiscardingBody(),
769 ByClosing())
770
771 if client.Attempts() != 1 || r.Status != "204 No Content" {
772 t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: Retry attempts %v for StatusCode %v; Want: 0 attempts for StatusCode 204",
773 client.Attempts(), r.Status)
774 }
775 }
776
777 func TestDoRetryForStatusCodes_RequestBodyReadError(t *testing.T) {
778 client := mocks.NewSender()
779 client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 No Content", http.StatusNoContent), 2)
780
781 r, err := SendWithSender(client, mocks.NewRequestWithCloseBody(),
782 DoRetryForStatusCodes(6, time.Duration(2*time.Second), http.StatusGatewayTimeout),
783 )
784
785 Respond(r,
786 ByDiscardingBody(),
787 ByClosing())
788
789 if err == nil || client.Attempts() != 0 {
790 t.Fatalf("autorest: Sender#DoRetryForStatusCodes -- Got: Not failed for request body read error; Want: Failed for body read error - %v", err)
791 }
792 }
793
794 func newAcceptedResponse() *http.Response {
795 resp := mocks.NewResponseWithStatus("202 Accepted", http.StatusAccepted)
796 mocks.SetAcceptedHeaders(resp)
797 return resp
798 }
799
800 func TestDelayWithRetryAfterWithSuccess(t *testing.T) {
801 Count429AsRetry = false
802 defer func() { Count429AsRetry = true }()
803 after, retries := 2, 2
804 totalSecs := after * retries
805
806 client := mocks.NewSender()
807 resp := mocks.NewResponseWithStatus("429 Too many requests", http.StatusTooManyRequests)
808 mocks.SetResponseHeader(resp, "Retry-After", fmt.Sprintf("%v", after))
809 client.AppendAndRepeatResponse(resp, retries)
810 client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
811
812 d := time.Second * time.Duration(totalSecs)
813 start := time.Now()
814 r, _ := SendWithSender(client, mocks.NewRequest(),
815 DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusTooManyRequests),
816 )
817
818 if time.Since(start) < d {
819 t.Fatal("autorest: DelayWithRetryAfter failed stopped too soon")
820 }
821
822 Respond(r,
823 ByDiscardingBody(),
824 ByClosing())
825
826 if r.StatusCode != http.StatusOK {
827 t.Fatalf("autorest: Sender#DelayWithRetryAfterWithSuccess -- got status code %d, wanted 200", r.StatusCode)
828 }
829 if client.Attempts() != 3 {
830 t.Fatalf("autorest: Sender#DelayWithRetryAfterWithSuccess -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ",
831 r.Status, client.Attempts()-1)
832 }
833 }
834
835 func TestDelayWithRetryAfterWithFail(t *testing.T) {
836 after, retries := 2, 2
837 totalSecs := after * retries
838
839 client := mocks.NewSender()
840 resp := mocks.NewResponseWithStatus("429 Too many requests", http.StatusTooManyRequests)
841 mocks.SetResponseHeader(resp, "Retry-After", fmt.Sprintf("%v", after))
842 client.AppendAndRepeatResponse(resp, retries)
843 client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
844
845 d := time.Second * time.Duration(totalSecs)
846 start := time.Now()
847 r, _ := SendWithSender(client, mocks.NewRequest(),
848 DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusTooManyRequests),
849 )
850
851 if time.Since(start) < d {
852 t.Fatal("autorest: DelayWithRetryAfter failed stopped too soon")
853 }
854
855 Respond(r,
856 ByDiscardingBody(),
857 ByClosing())
858
859 if r.StatusCode != http.StatusTooManyRequests {
860 t.Fatalf("autorest: Sender#DelayWithRetryAfterWithFail -- got status code %d, wanted 429", r.StatusCode)
861 }
862 if client.Attempts() != 2 {
863 t.Fatalf("autorest: Sender#DelayWithRetryAfterWithFail -- Got: StatusCode %v in %v attempts; Want: StatusCode 429 OK in 1 attempt -- ",
864 r.Status, client.Attempts()-1)
865 }
866 }
867
868 func TestDelayWithRetryAfterWithSuccessDateTime(t *testing.T) {
869 resumeAt := time.Now().Add(2 * time.Second).Round(time.Second)
870
871 client := mocks.NewSender()
872 resp := mocks.NewResponseWithStatus("503 Service temporarily unavailable", http.StatusServiceUnavailable)
873 mocks.SetResponseHeader(resp, "Retry-After", resumeAt.Format(time.RFC1123))
874 client.AppendResponse(resp)
875 client.AppendResponse(mocks.NewResponseWithStatus("200 OK", http.StatusOK))
876
877 r, _ := SendWithSender(client, mocks.NewRequest(),
878 DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusServiceUnavailable),
879 )
880
881 if time.Now().Before(resumeAt) {
882 t.Fatal("autorest: DelayWithRetryAfter failed stopped too soon")
883 }
884
885 Respond(r,
886 ByDiscardingBody(),
887 ByClosing())
888
889 if client.Attempts() != 2 {
890 t.Fatalf("autorest: Sender#DelayWithRetryAfter -- Got: StatusCode %v in %v attempts; Want: StatusCode 200 OK in 2 attempts -- ",
891 r.Status, client.Attempts()-1)
892 }
893 }
894
895 type temporaryError struct {
896 message string
897 }
898
899 func (te temporaryError) Error() string {
900 return te.message
901 }
902
903 func (te temporaryError) Timeout() bool {
904 return true
905 }
906
907 func (te temporaryError) Temporary() bool {
908 return true
909 }
910
911 func TestDoRetryForStatusCodes_NilResponseTemporaryError(t *testing.T) {
912 client := mocks.NewSender()
913 client.AppendResponse(nil)
914 client.SetError(temporaryError{message: "faux error"})
915
916 r, err := SendWithSender(client, mocks.NewRequest(),
917 DoRetryForStatusCodes(3, time.Duration(1*time.Second), StatusCodesForRetry...),
918 )
919
920 Respond(r,
921 ByDiscardingBody(),
922 ByClosing())
923
924 if err != nil || client.Attempts() != 2 {
925 t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponseTemporaryError -- Got: non-nil error or wrong number of attempts - %v", err)
926 }
927 }
928
929 func TestDoRetryForStatusCodes_NilResponseTemporaryError2(t *testing.T) {
930 client := mocks.NewSender()
931 client.AppendResponse(nil)
932 client.SetError(fmt.Errorf("faux error"))
933
934 r, err := SendWithSender(client, mocks.NewRequest(),
935 DoRetryForStatusCodes(3, time.Duration(1*time.Second), StatusCodesForRetry...),
936 )
937
938 Respond(r,
939 ByDiscardingBody(),
940 ByClosing())
941
942 if err != nil || client.Attempts() != 2 {
943 t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponseTemporaryError2 -- Got: nil error or wrong number of attempts - %v", err)
944 }
945 }
946
947 type fatalError struct {
948 message string
949 }
950
951 func (fe fatalError) Error() string {
952 return fe.message
953 }
954
955 func (fe fatalError) Timeout() bool {
956 return false
957 }
958
959 func (fe fatalError) Temporary() bool {
960 return false
961 }
962
963 func TestDoRetryForStatusCodes_NilResponseFatalError(t *testing.T) {
964 const retryAttempts = 3
965 client := mocks.NewSender()
966 client.AppendAndRepeatResponse(nil, retryAttempts+1)
967 client.SetAndRepeatError(fatalError{"fatal error"}, retryAttempts+1)
968
969 r, err := SendWithSender(client, mocks.NewRequest(),
970 DoRetryForStatusCodes(retryAttempts, time.Duration(1*time.Second), StatusCodesForRetry...),
971 )
972
973 Respond(r,
974 ByDiscardingBody(),
975 ByClosing())
976
977 if err == nil || client.Attempts() < retryAttempts+1 {
978 t.Fatalf("autorest: Sender#TestDoRetryForStatusCodes_NilResponseFatalError -- Got: nil error or wrong number of attempts - %v", err)
979 }
980 }
981
982 func TestDoRetryForStatusCodes_Cancel429(t *testing.T) {
983 Count429AsRetry = false
984 defer func() { Count429AsRetry = true }()
985 retries := 6
986 client := mocks.NewSender()
987 resp := mocks.NewResponseWithStatus("429 Too many requests", http.StatusTooManyRequests)
988 client.AppendAndRepeatResponse(resp, retries)
989
990 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(retries/2)*time.Second)
991 defer cancel()
992 req := mocks.NewRequest().WithContext(ctx)
993 r, err := SendWithSender(client, req,
994 DoRetryForStatusCodes(1, time.Duration(time.Second), http.StatusTooManyRequests),
995 )
996
997 if err == nil {
998 t.Fatal("unexpected nil-error")
999 }
1000 if r == nil {
1001 t.Fatal("unexpected nil response")
1002 }
1003 if r.StatusCode != http.StatusTooManyRequests {
1004 t.Fatalf("expected status code 429, got: %d", r.StatusCode)
1005 }
1006 if client.Attempts() >= retries {
1007 t.Fatalf("too many attempts: %d", client.Attempts())
1008 }
1009 }
1010
1011 func TestDoRetryForStatusCodes_Race(t *testing.T) {
1012
1013 s := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
1014 defer s.Close()
1015
1016 sender := DecorateSender(s.Client(),
1017 DoRetryForStatusCodes(0, 0, http.StatusRequestTimeout))
1018
1019 runs := 2
1020 errCh := make(chan error, runs)
1021
1022 for i := 0; i < runs; i++ {
1023 go func() {
1024 req, _ := http.NewRequest(http.MethodGet, s.URL, nil)
1025
1026 _, err := sender.Do(req)
1027 errCh <- err
1028 }()
1029 }
1030 for i := 0; i < runs; i++ {
1031 err := <-errCh
1032 if err != nil {
1033 t.Fatal(err)
1034 }
1035 }
1036 close(errCh)
1037 }
1038
1039 func TestGetSendDecorators(t *testing.T) {
1040 sd := GetSendDecorators(context.Background())
1041 if l := len(sd); l != 0 {
1042 t.Fatalf("expected zero length but got %d", l)
1043 }
1044 sd = GetSendDecorators(context.Background(), DoCloseIfError(), DoErrorIfStatusCode())
1045 if l := len(sd); l != 2 {
1046 t.Fatalf("expected length of two but got %d", l)
1047 }
1048 }
1049
1050 func TestWithSendDecorators(t *testing.T) {
1051 ctx := WithSendDecorators(context.Background(), []SendDecorator{DoRetryForAttempts(5, 5*time.Second)})
1052 sd := GetSendDecorators(ctx)
1053 if l := len(sd); l != 1 {
1054 t.Fatalf("expected length of one but got %d", l)
1055 }
1056 sd = GetSendDecorators(ctx, DoCloseIfError(), DoErrorIfStatusCode())
1057 if l := len(sd); l != 1 {
1058 t.Fatalf("expected length of one but got %d", l)
1059 }
1060 }
1061
View as plain text