...

Source file src/github.com/go-resty/resty/v2/client_test.go

Documentation: github.com/go-resty/resty/v2

     1  // Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
     2  // resty source code and usage is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package resty
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/tls"
    10  	"errors"
    11  	"fmt"
    12  	"io/ioutil"
    13  	"net"
    14  	"net/http"
    15  	"net/url"
    16  	"path/filepath"
    17  	"reflect"
    18  	"strconv"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  )
    23  
    24  func TestClientBasicAuth(t *testing.T) {
    25  	ts := createAuthServer(t)
    26  	defer ts.Close()
    27  
    28  	c := dc()
    29  	c.SetBasicAuth("myuser", "basicauth").
    30  		SetHostURL(ts.URL).
    31  		SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
    32  
    33  	resp, err := c.R().
    34  		SetResult(&AuthSuccess{}).
    35  		Post("/login")
    36  
    37  	assertError(t, err)
    38  	assertEqual(t, http.StatusOK, resp.StatusCode())
    39  
    40  	t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
    41  	logResponse(t, resp)
    42  }
    43  
    44  func TestClientAuthToken(t *testing.T) {
    45  	ts := createAuthServer(t)
    46  	defer ts.Close()
    47  
    48  	c := dc()
    49  	c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
    50  		SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
    51  		SetHostURL(ts.URL + "/")
    52  
    53  	resp, err := c.R().Get("/profile")
    54  
    55  	assertError(t, err)
    56  	assertEqual(t, http.StatusOK, resp.StatusCode())
    57  }
    58  
    59  func TestClientAuthScheme(t *testing.T) {
    60  	ts := createAuthServer(t)
    61  	defer ts.Close()
    62  
    63  	c := dc()
    64  	// Ensure default Bearer
    65  	c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
    66  		SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
    67  		SetHostURL(ts.URL + "/")
    68  
    69  	resp, err := c.R().Get("/profile")
    70  
    71  	assertError(t, err)
    72  	assertEqual(t, http.StatusOK, resp.StatusCode())
    73  
    74  	// Ensure setting the scheme works as well
    75  	c.SetAuthScheme("Bearer")
    76  
    77  	resp2, err2 := c.R().Get("/profile")
    78  	assertError(t, err2)
    79  	assertEqual(t, http.StatusOK, resp2.StatusCode())
    80  
    81  }
    82  
    83  func TestOnAfterMiddleware(t *testing.T) {
    84  	ts := createGenServer(t)
    85  	defer ts.Close()
    86  
    87  	c := dc()
    88  	c.OnAfterResponse(func(c *Client, res *Response) error {
    89  		t.Logf("Request sent at: %v", res.Request.Time)
    90  		t.Logf("Response Received at: %v", res.ReceivedAt())
    91  
    92  		return nil
    93  	})
    94  
    95  	resp, err := c.R().
    96  		SetBody("OnAfterResponse: This is plain text body to server").
    97  		Put(ts.URL + "/plaintext")
    98  
    99  	assertError(t, err)
   100  	assertEqual(t, http.StatusOK, resp.StatusCode())
   101  	assertEqual(t, "TestPut: plain text response", resp.String())
   102  }
   103  
   104  func TestClientRedirectPolicy(t *testing.T) {
   105  	ts := createRedirectServer(t)
   106  	defer ts.Close()
   107  
   108  	c := dc().SetRedirectPolicy(FlexibleRedirectPolicy(20))
   109  	_, err := c.R().Get(ts.URL + "/redirect-1")
   110  
   111  	assertEqual(t, true, ("Get /redirect-21: stopped after 20 redirects" == err.Error() ||
   112  		"Get \"/redirect-21\": stopped after 20 redirects" == err.Error()))
   113  
   114  	c.SetRedirectPolicy(NoRedirectPolicy())
   115  	_, err = c.R().Get(ts.URL + "/redirect-1")
   116  	assertEqual(t, true, ("Get /redirect-2: auto redirect is disabled" == err.Error() ||
   117  		"Get \"/redirect-2\": auto redirect is disabled" == err.Error()))
   118  }
   119  
   120  func TestClientTimeout(t *testing.T) {
   121  	ts := createGetServer(t)
   122  	defer ts.Close()
   123  
   124  	c := dc().SetTimeout(time.Second * 3)
   125  	_, err := c.R().Get(ts.URL + "/set-timeout-test")
   126  
   127  	assertEqual(t, true, strings.Contains(strings.ToLower(err.Error()), "timeout"))
   128  }
   129  
   130  func TestClientTimeoutWithinThreshold(t *testing.T) {
   131  	ts := createGetServer(t)
   132  	defer ts.Close()
   133  
   134  	c := dc().SetTimeout(time.Second * 3)
   135  	resp, err := c.R().Get(ts.URL + "/set-timeout-test-with-sequence")
   136  
   137  	assertError(t, err)
   138  
   139  	seq1, _ := strconv.ParseInt(resp.String(), 10, 32)
   140  
   141  	resp, err = c.R().Get(ts.URL + "/set-timeout-test-with-sequence")
   142  	assertError(t, err)
   143  
   144  	seq2, _ := strconv.ParseInt(resp.String(), 10, 32)
   145  
   146  	assertEqual(t, seq1+1, seq2)
   147  }
   148  
   149  func TestClientTimeoutInternalError(t *testing.T) {
   150  	c := dc().SetTimeout(time.Second * 1)
   151  	_, _ = c.R().Get("http://localhost:9000/set-timeout-test")
   152  }
   153  
   154  func TestClientProxy(t *testing.T) {
   155  	ts := createGetServer(t)
   156  	defer ts.Close()
   157  
   158  	c := dc()
   159  	c.SetTimeout(1 * time.Second)
   160  	c.SetProxy("http://sampleproxy:8888")
   161  
   162  	resp, err := c.R().Get(ts.URL)
   163  	assertNotNil(t, resp)
   164  	assertNotNil(t, err)
   165  
   166  	// Error
   167  	c.SetProxy("//not.a.user@%66%6f%6f.com:8888")
   168  
   169  	resp, err = c.R().
   170  		Get(ts.URL)
   171  	assertNotNil(t, err)
   172  	assertNotNil(t, resp)
   173  }
   174  
   175  func TestClientSetCertificates(t *testing.T) {
   176  	client := dc()
   177  	client.SetCertificates(tls.Certificate{})
   178  
   179  	transport, err := client.transport()
   180  
   181  	assertNil(t, err)
   182  	assertEqual(t, 1, len(transport.TLSClientConfig.Certificates))
   183  }
   184  
   185  func TestClientSetRootCertificate(t *testing.T) {
   186  	client := dc()
   187  	client.SetRootCertificate(filepath.Join(getTestDataPath(), "sample-root.pem"))
   188  
   189  	transport, err := client.transport()
   190  
   191  	assertNil(t, err)
   192  	assertNotNil(t, transport.TLSClientConfig.RootCAs)
   193  }
   194  
   195  func TestClientSetRootCertificateNotExists(t *testing.T) {
   196  	client := dc()
   197  	client.SetRootCertificate(filepath.Join(getTestDataPath(), "not-exists-sample-root.pem"))
   198  
   199  	transport, err := client.transport()
   200  
   201  	assertNil(t, err)
   202  	assertNil(t, transport.TLSClientConfig)
   203  }
   204  
   205  func TestClientSetRootCertificateFromString(t *testing.T) {
   206  	client := dc()
   207  	rootPemData, err := ioutil.ReadFile(filepath.Join(getTestDataPath(), "sample-root.pem"))
   208  	assertNil(t, err)
   209  
   210  	client.SetRootCertificateFromString(string(rootPemData))
   211  
   212  	transport, err := client.transport()
   213  
   214  	assertNil(t, err)
   215  	assertNotNil(t, transport.TLSClientConfig.RootCAs)
   216  }
   217  
   218  func TestClientSetRootCertificateFromStringErrorTls(t *testing.T) {
   219  	client := NewWithClient(&http.Client{})
   220  	client.outputLogTo(ioutil.Discard)
   221  
   222  	rootPemData, err := ioutil.ReadFile(filepath.Join(getTestDataPath(), "sample-root.pem"))
   223  	assertNil(t, err)
   224  	rt := &CustomRoundTripper{}
   225  	client.SetTransport(rt)
   226  	transport, err := client.transport()
   227  
   228  	client.SetRootCertificateFromString(string(rootPemData))
   229  
   230  	assertNotNil(t, rt)
   231  	assertNotNil(t, err)
   232  	assertNil(t, transport)
   233  }
   234  
   235  func TestClientOnBeforeRequestModification(t *testing.T) {
   236  	tc := dc()
   237  	tc.OnBeforeRequest(func(c *Client, r *Request) error {
   238  		r.SetAuthToken("This is test auth token")
   239  		return nil
   240  	})
   241  
   242  	ts := createGetServer(t)
   243  	defer ts.Close()
   244  
   245  	resp, err := tc.R().Get(ts.URL + "/")
   246  
   247  	assertError(t, err)
   248  	assertEqual(t, http.StatusOK, resp.StatusCode())
   249  	assertEqual(t, "200 OK", resp.Status())
   250  	assertNotNil(t, resp.Body())
   251  	assertEqual(t, "TestGet: text response", resp.String())
   252  
   253  	logResponse(t, resp)
   254  }
   255  
   256  func TestClientSetHeaderVerbatim(t *testing.T) {
   257  	ts := createPostServer(t)
   258  	defer ts.Close()
   259  
   260  	c := dc().
   261  		SetHeaderVerbatim("header-lowercase", "value_lowercase").
   262  		SetHeader("header-lowercase", "value_standard")
   263  
   264  	assertEqual(t, "value_lowercase", strings.Join(c.Header["header-lowercase"], "")) //nolint
   265  	assertEqual(t, "value_standard", c.Header.Get("Header-Lowercase"))
   266  }
   267  
   268  func TestClientSetTransport(t *testing.T) {
   269  	ts := createGetServer(t)
   270  	defer ts.Close()
   271  	client := dc()
   272  
   273  	transport := &http.Transport{
   274  		// something like Proxying to httptest.Server, etc...
   275  		Proxy: func(req *http.Request) (*url.URL, error) {
   276  			return url.Parse(ts.URL)
   277  		},
   278  	}
   279  	client.SetTransport(transport)
   280  	transportInUse, err := client.transport()
   281  
   282  	assertNil(t, err)
   283  	assertEqual(t, true, transport == transportInUse)
   284  }
   285  
   286  func TestClientSetScheme(t *testing.T) {
   287  	client := dc()
   288  
   289  	client.SetScheme("http")
   290  
   291  	assertEqual(t, true, client.scheme == "http")
   292  }
   293  
   294  func TestClientSetCookieJar(t *testing.T) {
   295  	client := dc()
   296  	backupJar := client.httpClient.Jar
   297  
   298  	client.SetCookieJar(nil)
   299  	assertNil(t, client.httpClient.Jar)
   300  
   301  	client.SetCookieJar(backupJar)
   302  	assertEqual(t, true, client.httpClient.Jar == backupJar)
   303  }
   304  
   305  func TestClientOptions(t *testing.T) {
   306  	client := dc()
   307  	client.SetContentLength(true)
   308  	assertEqual(t, client.setContentLength, true)
   309  
   310  	client.SetHostURL("http://httpbin.org")
   311  	assertEqual(t, "http://httpbin.org", client.HostURL)
   312  
   313  	client.SetHeader(hdrContentTypeKey, "application/json; charset=utf-8")
   314  	client.SetHeaders(map[string]string{
   315  		hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.1",
   316  		"X-Request-Id":  strconv.FormatInt(time.Now().UnixNano(), 10),
   317  	})
   318  	assertEqual(t, "application/json; charset=utf-8", client.Header.Get(hdrContentTypeKey))
   319  
   320  	client.SetCookie(&http.Cookie{
   321  		Name:  "default-cookie",
   322  		Value: "This is cookie default-cookie value",
   323  	})
   324  	assertEqual(t, "default-cookie", client.Cookies[0].Name)
   325  
   326  	cookies := []*http.Cookie{
   327  		{
   328  			Name:  "default-cookie-1",
   329  			Value: "This is default-cookie 1 value",
   330  		}, {
   331  			Name:  "default-cookie-2",
   332  			Value: "This is default-cookie 2 value",
   333  		},
   334  	}
   335  	client.SetCookies(cookies)
   336  	assertEqual(t, "default-cookie-1", client.Cookies[1].Name)
   337  	assertEqual(t, "default-cookie-2", client.Cookies[2].Name)
   338  
   339  	client.SetQueryParam("test_param_1", "Param_1")
   340  	client.SetQueryParams(map[string]string{"test_param_2": "Param_2", "test_param_3": "Param_3"})
   341  	assertEqual(t, "Param_3", client.QueryParam.Get("test_param_3"))
   342  
   343  	rTime := strconv.FormatInt(time.Now().UnixNano(), 10)
   344  	client.SetFormData(map[string]string{"r_time": rTime})
   345  	assertEqual(t, rTime, client.FormData.Get("r_time"))
   346  
   347  	client.SetBasicAuth("myuser", "mypass")
   348  	assertEqual(t, "myuser", client.UserInfo.Username)
   349  
   350  	client.SetAuthToken("AC75BD37F019E08FBC594900518B4F7E")
   351  	assertEqual(t, "AC75BD37F019E08FBC594900518B4F7E", client.Token)
   352  
   353  	client.SetDisableWarn(true)
   354  	assertEqual(t, client.DisableWarn, true)
   355  
   356  	client.SetRetryCount(3)
   357  	assertEqual(t, 3, client.RetryCount)
   358  
   359  	rwt := time.Duration(1000) * time.Millisecond
   360  	client.SetRetryWaitTime(rwt)
   361  	assertEqual(t, rwt, client.RetryWaitTime)
   362  
   363  	mrwt := time.Duration(2) * time.Second
   364  	client.SetRetryMaxWaitTime(mrwt)
   365  	assertEqual(t, mrwt, client.RetryMaxWaitTime)
   366  
   367  	client.AddRetryAfterErrorCondition()
   368  	equal(client.RetryConditions[0], func(response *Response, err error) bool {
   369  		return response.IsError()
   370  	})
   371  
   372  	err := &AuthError{}
   373  	client.SetError(err)
   374  	if reflect.TypeOf(err) == client.Error {
   375  		t.Error("SetError failed")
   376  	}
   377  
   378  	client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
   379  	transport, transportErr := client.transport()
   380  
   381  	assertNil(t, transportErr)
   382  	assertEqual(t, true, transport.TLSClientConfig.InsecureSkipVerify)
   383  
   384  	client.OnBeforeRequest(func(c *Client, r *Request) error {
   385  		c.log.Debugf("I'm in Request middleware")
   386  		return nil // if it success
   387  	})
   388  	client.OnAfterResponse(func(c *Client, r *Response) error {
   389  		c.log.Debugf("I'm in Response middleware")
   390  		return nil // if it success
   391  	})
   392  
   393  	client.SetTimeout(5 * time.Second)
   394  	client.SetRedirectPolicy(FlexibleRedirectPolicy(10), func(req *http.Request, via []*http.Request) error {
   395  		return errors.New("sample test redirect")
   396  	})
   397  	client.SetContentLength(true)
   398  
   399  	client.SetDebug(true)
   400  	assertEqual(t, client.Debug, true)
   401  
   402  	var sl int64 = 1000000
   403  	client.SetDebugBodyLimit(sl)
   404  	assertEqual(t, client.debugBodySizeLimit, sl)
   405  
   406  	client.SetAllowGetMethodPayload(true)
   407  	assertEqual(t, client.AllowGetMethodPayload, true)
   408  
   409  	client.SetScheme("http")
   410  	assertEqual(t, client.scheme, "http")
   411  
   412  	client.SetCloseConnection(true)
   413  	assertEqual(t, client.closeConnection, true)
   414  }
   415  
   416  func TestClientPreRequestHook(t *testing.T) {
   417  	client := dc()
   418  	client.SetPreRequestHook(func(c *Client, r *http.Request) error {
   419  		c.log.Debugf("I'm in Pre-Request Hook")
   420  		return nil
   421  	})
   422  
   423  	client.SetPreRequestHook(func(c *Client, r *http.Request) error {
   424  		c.log.Debugf("I'm Overwriting existing Pre-Request Hook")
   425  
   426  		// Reading Request `N` no of times
   427  		for i := 0; i < 5; i++ {
   428  			b, _ := r.GetBody()
   429  			rb, _ := ioutil.ReadAll(b)
   430  			c.log.Debugf("%s %v", string(rb), len(rb))
   431  			assertEqual(t, true, len(rb) >= 45)
   432  		}
   433  		return nil
   434  	})
   435  
   436  	ts := createPostServer(t)
   437  	defer ts.Close()
   438  
   439  	// Regular bodybuf use case
   440  	resp, _ := client.R().
   441  		SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
   442  		Post(ts.URL + "/login")
   443  	assertEqual(t, http.StatusOK, resp.StatusCode())
   444  	assertEqual(t, `{ "id": "success", "message": "login successful" }`, resp.String())
   445  
   446  	// io.Reader body use case
   447  	resp, _ = client.R().
   448  		SetHeader(hdrContentTypeKey, jsonContentType).
   449  		SetBody(bytes.NewReader([]byte(`{"username":"testuser", "password":"testpass"}`))).
   450  		Post(ts.URL + "/login")
   451  	assertEqual(t, http.StatusOK, resp.StatusCode())
   452  	assertEqual(t, `{ "id": "success", "message": "login successful" }`, resp.String())
   453  }
   454  
   455  func TestClientAllowsGetMethodPayload(t *testing.T) {
   456  	ts := createGetServer(t)
   457  	defer ts.Close()
   458  
   459  	c := dc()
   460  	c.SetAllowGetMethodPayload(true)
   461  	c.SetPreRequestHook(func(*Client, *http.Request) error { return nil }) // for coverage
   462  
   463  	payload := "test-payload"
   464  	resp, err := c.R().SetBody(payload).Get(ts.URL + "/get-method-payload-test")
   465  
   466  	assertError(t, err)
   467  	assertEqual(t, http.StatusOK, resp.StatusCode())
   468  	assertEqual(t, payload, resp.String())
   469  }
   470  
   471  func TestClientRoundTripper(t *testing.T) {
   472  	c := NewWithClient(&http.Client{})
   473  	c.outputLogTo(ioutil.Discard)
   474  
   475  	rt := &CustomRoundTripper{}
   476  	c.SetTransport(rt)
   477  
   478  	ct, err := c.transport()
   479  	assertNotNil(t, err)
   480  	assertNil(t, ct)
   481  	assertEqual(t, "current transport is not an *http.Transport instance", err.Error())
   482  
   483  	c.SetTLSClientConfig(&tls.Config{})
   484  	c.SetProxy("http://localhost:9090")
   485  	c.RemoveProxy()
   486  	c.SetCertificates(tls.Certificate{})
   487  	c.SetRootCertificate(filepath.Join(getTestDataPath(), "sample-root.pem"))
   488  }
   489  
   490  func TestClientNewRequest(t *testing.T) {
   491  	c := New()
   492  	request := c.NewRequest()
   493  	assertNotNil(t, request)
   494  }
   495  
   496  func TestDebugBodySizeLimit(t *testing.T) {
   497  	ts := createGetServer(t)
   498  	defer ts.Close()
   499  
   500  	var lgr bytes.Buffer
   501  	c := dc()
   502  	c.SetDebug(true)
   503  	c.SetDebugBodyLimit(30)
   504  	c.outputLogTo(&lgr)
   505  
   506  	testcases := []struct{ url, want string }{
   507  		// Text, does not exceed limit.
   508  		{ts.URL, "TestGet: text response"},
   509  		// Empty response.
   510  		{ts.URL + "/no-content", "***** NO CONTENT *****"},
   511  		// JSON, does not exceed limit.
   512  		{ts.URL + "/json", "{\n   \"TestGet\": \"JSON response\"\n}"},
   513  		// Invalid JSON, does not exceed limit.
   514  		{ts.URL + "/json-invalid", "TestGet: Invalid JSON"},
   515  		// Text, exceeds limit.
   516  		{ts.URL + "/long-text", "RESPONSE TOO LARGE"},
   517  		// JSON, exceeds limit.
   518  		{ts.URL + "/long-json", "RESPONSE TOO LARGE"},
   519  	}
   520  
   521  	for _, tc := range testcases {
   522  		_, err := c.R().Get(tc.url)
   523  		assertError(t, err)
   524  		debugLog := lgr.String()
   525  		if !strings.Contains(debugLog, tc.want) {
   526  			t.Errorf("Expected logs to contain [%v], got [\n%v]", tc.want, debugLog)
   527  		}
   528  		lgr.Reset()
   529  	}
   530  }
   531  
   532  // CustomRoundTripper just for test
   533  type CustomRoundTripper struct {
   534  }
   535  
   536  // RoundTrip just for test
   537  func (rt *CustomRoundTripper) RoundTrip(_ *http.Request) (*http.Response, error) {
   538  	return &http.Response{}, nil
   539  }
   540  
   541  func TestAutoGzip(t *testing.T) {
   542  	ts := createGenServer(t)
   543  	defer ts.Close()
   544  
   545  	c := New()
   546  	testcases := []struct{ url, want string }{
   547  		{ts.URL + "/gzip-test", "This is Gzip response testing"},
   548  		{ts.URL + "/gzip-test-gziped-empty-body", ""},
   549  		{ts.URL + "/gzip-test-no-gziped-body", ""},
   550  	}
   551  	for _, tc := range testcases {
   552  		resp, err := c.R().
   553  			SetHeader("Accept-Encoding", "gzip").
   554  			Get(tc.url)
   555  
   556  		assertError(t, err)
   557  		assertEqual(t, http.StatusOK, resp.StatusCode())
   558  		assertEqual(t, "200 OK", resp.Status())
   559  		assertNotNil(t, resp.Body())
   560  		assertEqual(t, tc.want, resp.String())
   561  
   562  		logResponse(t, resp)
   563  	}
   564  }
   565  
   566  func TestLogCallbacks(t *testing.T) {
   567  	ts := createAuthServer(t)
   568  	defer ts.Close()
   569  
   570  	c := New().SetDebug(true)
   571  
   572  	var lgr bytes.Buffer
   573  	c.outputLogTo(&lgr)
   574  
   575  	c.OnRequestLog(func(r *RequestLog) error {
   576  		// masking authorzation header
   577  		r.Header.Set("Authorization", "Bearer *******************************")
   578  		return nil
   579  	})
   580  	c.OnResponseLog(func(r *ResponseLog) error {
   581  		r.Header.Add("X-Debug-Resposne-Log", "Modified :)")
   582  		r.Body += "\nModified the response body content"
   583  		return nil
   584  	})
   585  
   586  	c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
   587  		SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF")
   588  
   589  	resp, err := c.R().
   590  		SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
   591  		Get(ts.URL + "/profile")
   592  
   593  	assertError(t, err)
   594  	assertEqual(t, http.StatusOK, resp.StatusCode())
   595  
   596  	// Validating debug log updates
   597  	logInfo := lgr.String()
   598  	assertEqual(t, true, strings.Contains(logInfo, "Bearer *******************************"))
   599  	assertEqual(t, true, strings.Contains(logInfo, "X-Debug-Resposne-Log"))
   600  	assertEqual(t, true, strings.Contains(logInfo, "Modified the response body content"))
   601  
   602  	// Error scenario
   603  	c.OnRequestLog(func(r *RequestLog) error { return errors.New("request test error") })
   604  	resp, err = c.R().
   605  		SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
   606  		Get(ts.URL + "/profile")
   607  	assertEqual(t, errors.New("request test error"), err)
   608  	assertNil(t, resp)
   609  	assertNotNil(t, err)
   610  
   611  	c.OnRequestLog(nil)
   612  	c.OnResponseLog(func(r *ResponseLog) error { return errors.New("response test error") })
   613  	resp, err = c.R().
   614  		SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
   615  		Get(ts.URL + "/profile")
   616  	assertEqual(t, errors.New("response test error"), err)
   617  	assertNotNil(t, resp)
   618  }
   619  
   620  func TestNewWithLocalAddr(t *testing.T) {
   621  	ts := createGetServer(t)
   622  	defer ts.Close()
   623  
   624  	localAddress, _ := net.ResolveTCPAddr("tcp", "127.0.0.1")
   625  	client := NewWithLocalAddr(localAddress)
   626  	client.SetHostURL(ts.URL)
   627  
   628  	resp, err := client.R().Get("/")
   629  	assertNil(t, err)
   630  	assertEqual(t, resp.String(), "TestGet: text response")
   631  }
   632  
   633  func TestClientOnResponseError(t *testing.T) {
   634  	ts := createAuthServer(t)
   635  	defer ts.Close()
   636  
   637  	tests := []struct {
   638  		name        string
   639  		setup       func(*Client)
   640  		isError     bool
   641  		hasResponse bool
   642  	}{
   643  		{
   644  			name: "successful_request",
   645  		},
   646  		{
   647  			name: "http_status_error",
   648  			setup: func(client *Client) {
   649  				client.SetAuthToken("BAD")
   650  			},
   651  		},
   652  		{
   653  			name: "before_request_error",
   654  			setup: func(client *Client) {
   655  				client.OnBeforeRequest(func(client *Client, request *Request) error {
   656  					return fmt.Errorf("before request")
   657  				})
   658  			},
   659  			isError: true,
   660  		},
   661  		{
   662  			name: "before_request_error_retry",
   663  			setup: func(client *Client) {
   664  				client.SetRetryCount(3).OnBeforeRequest(func(client *Client, request *Request) error {
   665  					return fmt.Errorf("before request")
   666  				})
   667  			},
   668  			isError: true,
   669  		},
   670  		{
   671  			name: "after_response_error",
   672  			setup: func(client *Client) {
   673  				client.OnAfterResponse(func(client *Client, response *Response) error {
   674  					return fmt.Errorf("after response")
   675  				})
   676  			},
   677  			isError:     true,
   678  			hasResponse: true,
   679  		},
   680  		{
   681  			name: "after_response_error_retry",
   682  			setup: func(client *Client) {
   683  				client.SetRetryCount(3).OnAfterResponse(func(client *Client, response *Response) error {
   684  					return fmt.Errorf("after response")
   685  				})
   686  			},
   687  			isError:     true,
   688  			hasResponse: true,
   689  		},
   690  	}
   691  
   692  	for _, test := range tests {
   693  		t.Run(test.name, func(t *testing.T) {
   694  			var assertErrorHook = func(r *Request, err error) {
   695  				assertNotNil(t, r)
   696  				v, ok := err.(*ResponseError)
   697  				assertEqual(t, test.hasResponse, ok)
   698  				if ok {
   699  					assertNotNil(t, v.Response)
   700  					assertNotNil(t, v.Err)
   701  				}
   702  			}
   703  			var hook1, hook2 int
   704  			c := New().outputLogTo(ioutil.Discard).
   705  				SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
   706  				SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
   707  				SetRetryCount(0).
   708  				SetRetryMaxWaitTime(time.Microsecond).
   709  				AddRetryCondition(func(response *Response, err error) bool {
   710  					if err != nil {
   711  						return true
   712  					}
   713  					return response.IsError()
   714  				}).
   715  				OnError(func(r *Request, err error) {
   716  					assertErrorHook(r, err)
   717  					hook1++
   718  				}).
   719  				OnError(func(r *Request, err error) {
   720  					assertErrorHook(r, err)
   721  					hook2++
   722  				})
   723  			if test.setup != nil {
   724  				test.setup(c)
   725  			}
   726  			_, err := c.R().Get(ts.URL + "/profile")
   727  			if test.isError {
   728  				assertNotNil(t, err)
   729  				assertEqual(t, 1, hook1)
   730  				assertEqual(t, 1, hook2)
   731  			} else {
   732  				assertError(t, err)
   733  			}
   734  		})
   735  	}
   736  }
   737  
   738  func TestResponseError(t *testing.T) {
   739  	err := errors.New("error message")
   740  	re := &ResponseError{
   741  		Response: &Response{},
   742  		Err:      err,
   743  	}
   744  	assertNotNil(t, re.Unwrap())
   745  	assertEqual(t, err.Error(), re.Error())
   746  }
   747  
   748  func TestHostURLForGH318AndGH407(t *testing.T) {
   749  	ts := createPostServer(t)
   750  	defer ts.Close()
   751  
   752  	targetURL, _ := url.Parse(ts.URL)
   753  	t.Log("ts.URL:", ts.URL)
   754  	t.Log("targetURL.Host:", targetURL.Host)
   755  	// Sample output
   756  	// ts.URL: http://127.0.0.1:55967
   757  	// targetURL.Host: 127.0.0.1:55967
   758  
   759  	// Unable use the local http test server for this
   760  	// use case testing
   761  	//
   762  	// using `targetURL.Host` value or test case yield to ERROR
   763  	// "parse "127.0.0.1:55967": first path segment in URL cannot contain colon"
   764  
   765  	// test the functionality with httpbin.org locally
   766  	// will figure out later
   767  
   768  	c := dc()
   769  	// c.SetScheme("http")
   770  	// c.SetHostURL(targetURL.Host + "/")
   771  
   772  	// t.Log("with leading `/`")
   773  	// resp, err := c.R().Post("/login")
   774  	// assertNil(t, err)
   775  	// assertNotNil(t, resp)
   776  
   777  	// t.Log("\nwithout leading `/`")
   778  	// resp, err = c.R().Post("login")
   779  	// assertNil(t, err)
   780  	// assertNotNil(t, resp)
   781  
   782  	t.Log("with leading `/` on request & with trailing `/` on host url")
   783  	c.SetHostURL(ts.URL + "/")
   784  	resp, err := c.R().
   785  		SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
   786  		Post("/login")
   787  	assertNil(t, err)
   788  	assertNotNil(t, resp)
   789  }
   790  

View as plain text