...

Source file src/github.com/Azure/go-autorest/autorest/sender_test.go

Documentation: github.com/Azure/go-autorest/autorest

     1  package autorest
     2  
     3  // Copyright 2017 Microsoft Corporation
     4  //
     5  //  Licensed under the Apache License, Version 2.0 (the "License");
     6  //  you may not use this file except in compliance with the License.
     7  //  You may obtain a copy of the License at
     8  //
     9  //      http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  //  Unless required by applicable law or agreed to in writing, software
    12  //  distributed under the License is distributed on an "AS IS" BASIS,
    13  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  //  See the License for the specific language governing permissions and
    15  //  limitations under the License.
    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  	// Output:
    59  	// autorest: Sending GET https://microsoft.com/a/b/c/
    60  	// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
    61  	// autorest: Sending GET https://microsoft.com/a/b/c/
    62  	// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
    63  	// autorest: Sending GET https://microsoft.com/a/b/c/
    64  	// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
    65  	// autorest: Sending GET https://microsoft.com/a/b/c/
    66  	// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
    67  	// autorest: Sending GET https://microsoft.com/a/b/c/
    68  	// autorest: GET https://microsoft.com/a/b/c/ received 202 Accepted
    69  }
    70  
    71  func ExampleDoRetryForAttempts() {
    72  	client := mocks.NewSender()
    73  	client.SetAndRepeatError(fmt.Errorf("Faux Error"), 10)
    74  
    75  	// Retry with backoff -- ensure returned Bodies are closed
    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  	// Output: Retry stopped after 5 attempts
    86  }
    87  
    88  func ExampleDoErrorIfStatusCode() {
    89  	client := mocks.NewSender()
    90  	client.AppendAndRepeatResponse(mocks.NewResponseWithStatus("204 NoContent", http.StatusNoContent), 10)
    91  
    92  	// Chain decorators to retry the request, up to five times, if the status code is 204
    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  	// Output: Retry stopped after 5 attempts with code 204 NoContent
   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  	// cannot use the mock sender as it's not safe for concurrent use
  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  			// cannot use testing.T.Fatal inside a goroutine, send error down channel
  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