github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/resty/client_test.go (about) 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" 13 "net" 14 "net/http" 15 "net/url" 16 "os" 17 "path/filepath" 18 "reflect" 19 "strconv" 20 "strings" 21 "testing" 22 "time" 23 24 "github.com/stretchr/testify/assert" 25 ) 26 27 func TestClientBasicAuth(t *testing.T) { 28 ts := createAuthServer(t) 29 defer ts.Close() 30 31 c := dc() 32 c.SetBasicAuth("myuser", "basicauth"). 33 SetBaseURL(ts.URL). 34 SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) 35 36 resp, err := c.R(). 37 SetResult(&AuthSuccess{}). 38 Post("/login") 39 40 assert.Nil(t, err) 41 assert.Equal(t, http.StatusOK, resp.StatusCode()) 42 43 t.Logf("Result Success: %q", resp.Result().(*AuthSuccess)) 44 logResponse(t, resp) 45 } 46 47 func TestClientAuthToken(t *testing.T) { 48 ts := createAuthServer(t) 49 defer ts.Close() 50 51 c := dc() 52 c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}). 53 SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF"). 54 SetBaseURL(ts.URL + "/") 55 56 resp, err := c.R().Get("/profile") 57 58 assert.Nil(t, err) 59 assert.Equal(t, http.StatusOK, resp.StatusCode()) 60 } 61 62 func TestClientAuthScheme(t *testing.T) { 63 ts := createAuthServer(t) 64 defer ts.Close() 65 66 c := dc() 67 // Ensure default Bearer 68 c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}). 69 SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF"). 70 SetBaseURL(ts.URL + "/") 71 72 resp, err := c.R().Get("/profile") 73 74 assert.Nil(t, err) 75 assert.Equal(t, http.StatusOK, resp.StatusCode()) 76 77 // Ensure setting the scheme works as well 78 c.SetAuthScheme("Bearer") 79 80 resp2, err2 := c.R().Get("/profile") 81 assert.Nil(t, err2) 82 assert.Equal(t, http.StatusOK, resp2.StatusCode()) 83 } 84 85 func TestOnAfterMiddleware(t *testing.T) { 86 ts := createGenServer(t) 87 defer ts.Close() 88 89 c := dc() 90 c.OnAfterResponse(func(c *Client, res *Response) error { 91 t.Logf("Request sent at: %v", res.Request.Time) 92 t.Logf("Response Received at: %v", res.ReceivedAt()) 93 94 return nil 95 }) 96 97 resp, err := c.R(). 98 SetBody("OnAfterResponse: This is plain text body to server"). 99 Put(ts.URL + "/plaintext") 100 101 assert.Nil(t, err) 102 assert.Equal(t, http.StatusOK, resp.StatusCode()) 103 assert.Equal(t, "TestPut: plain text response", resp.String()) 104 } 105 106 func TestClientRedirectPolicy(t *testing.T) { 107 ts := createRedirectServer(t) 108 defer ts.Close() 109 110 c := dc().SetRedirectPolicy(FlexibleRedirectPolicy(20)) 111 _, err := c.R().Get(ts.URL + "/redirect-1") 112 113 assert.Equal(t, true, "Get /redirect-21: stopped after 20 redirects" == err.Error() || 114 "Get \"/redirect-21\": stopped after 20 redirects" == err.Error()) 115 116 c.SetRedirectPolicy(NoRedirectPolicy()) 117 _, err = c.R().Get(ts.URL + "/redirect-1") 118 assert.Equal(t, true, "Get /redirect-2: auto redirect is disabled" == err.Error() || 119 "Get \"/redirect-2\": auto redirect is disabled" == err.Error()) 120 } 121 122 func TestClientTimeout(t *testing.T) { 123 ts := createGetServer(t) 124 defer ts.Close() 125 126 c := dc().SetTimeout(time.Second * 3) 127 _, err := c.R().Get(ts.URL + "/set-timeout-test") 128 129 assert.Equal(t, true, strings.Contains(strings.ToLower(err.Error()), "timeout")) 130 } 131 132 func TestClientTimeoutWithinThreshold(t *testing.T) { 133 ts := createGetServer(t) 134 defer ts.Close() 135 136 c := dc().SetTimeout(time.Second * 3) 137 resp, err := c.R().Get(ts.URL + "/set-timeout-test-with-sequence") 138 139 assert.Nil(t, err) 140 141 seq1, _ := strconv.ParseInt(resp.String(), 10, 32) 142 143 resp, err = c.R().Get(ts.URL + "/set-timeout-test-with-sequence") 144 assert.Nil(t, err) 145 146 seq2, _ := strconv.ParseInt(resp.String(), 10, 32) 147 148 assert.Equal(t, seq1+1, seq2) 149 } 150 151 func TestClientTimeoutInternalError(t *testing.T) { 152 c := dc().SetTimeout(time.Second * 1) 153 _, _ = c.R().Get("http://localhost:9000/set-timeout-test") 154 } 155 156 func TestClientProxy(t *testing.T) { 157 ts := createGetServer(t) 158 defer ts.Close() 159 160 c := dc() 161 c.SetTimeout(1 * time.Second) 162 c.SetProxy("http://sampleproxy:8888") 163 164 resp, err := c.R().Get(ts.URL) 165 assert.NotNil(t, resp) 166 assert.NotNil(t, err) 167 168 // Error 169 c.SetProxy("//not.a.user@%66%6f%6f.com:8888") 170 171 resp, err = c.R(). 172 Get(ts.URL) 173 assert.NotNil(t, err) 174 assert.NotNil(t, resp) 175 } 176 177 func TestClientSetCertificates(t *testing.T) { 178 client := dc() 179 client.SetCertificates(tls.Certificate{}) 180 181 transport, err := client.transport() 182 183 assert.Nil(t, err) 184 assert.Equal(t, 1, len(transport.TLSClientConfig.Certificates)) 185 } 186 187 func TestClientSetRootCertificate(t *testing.T) { 188 client := dc() 189 client.SetRootCertificate(filepath.Join(getTestDataPath(), "sample-root.pem")) 190 191 transport, err := client.transport() 192 193 assert.Nil(t, err) 194 assert.NotNil(t, transport.TLSClientConfig.RootCAs) 195 } 196 197 func TestClientSetRootCertificateNotExists(t *testing.T) { 198 client := dc() 199 client.SetRootCertificate(filepath.Join(getTestDataPath(), "not-exists-sample-root.pem")) 200 201 transport, err := client.transport() 202 203 assert.Nil(t, err) 204 assert.Nil(t, transport.TLSClientConfig) 205 } 206 207 func TestClientSetRootCertificateFromString(t *testing.T) { 208 client := dc() 209 rootPemData, err := os.ReadFile(filepath.Join(getTestDataPath(), "sample-root.pem")) 210 assert.Nil(t, err) 211 212 client.SetRootCertificateFromString(string(rootPemData)) 213 214 transport, err := client.transport() 215 216 assert.Nil(t, err) 217 assert.NotNil(t, transport.TLSClientConfig.RootCAs) 218 } 219 220 func TestClientSetRootCertificateFromStringErrorTls(t *testing.T) { 221 client := NewWithClient(&http.Client{}) 222 client.outputLogTo(io.Discard) 223 224 rootPemData, err := os.ReadFile(filepath.Join(getTestDataPath(), "sample-root.pem")) 225 assert.Nil(t, err) 226 rt := &CustomRoundTripper{} 227 client.SetTransport(rt) 228 transport, err := client.transport() 229 230 client.SetRootCertificateFromString(string(rootPemData)) 231 232 assert.NotNil(t, rt) 233 assert.NotNil(t, err) 234 assert.Nil(t, transport) 235 } 236 237 func TestClientOnBeforeRequestModification(t *testing.T) { 238 tc := dc() 239 tc.OnBeforeRequest(func(c *Client, r *Request) error { 240 r.SetAuthToken("This is test auth token") 241 return nil 242 }) 243 244 ts := createGetServer(t) 245 defer ts.Close() 246 247 resp, err := tc.R().Get(ts.URL + "/") 248 249 assert.Nil(t, err) 250 assert.Equal(t, http.StatusOK, resp.StatusCode()) 251 assert.Equal(t, "200 OK", resp.Status()) 252 assert.NotNil(t, resp.Body()) 253 assert.Equal(t, "TestGet: text response", resp.String()) 254 255 logResponse(t, resp) 256 } 257 258 func TestClientSetHeaderVerbatim(t *testing.T) { 259 ts := createPostServer(t) 260 defer ts.Close() 261 262 c := dc(). 263 SetHeaderVerbatim("header-lowercase", "value_lowercase"). 264 SetHeader("header-lowercase", "value_standard") 265 266 assert.Equal(t, "value_lowercase", strings.Join(c.Header["header-lowercase"], "")) //nolint 267 assert.Equal(t, "value_standard", c.Header.Get("Header-Lowercase")) 268 } 269 270 func TestClientSetTransport(t *testing.T) { 271 ts := createGetServer(t) 272 defer ts.Close() 273 client := dc() 274 275 transport := &http.Transport{ 276 // something like Proxying to httptest.Server, etc... 277 Proxy: func(req *http.Request) (*url.URL, error) { 278 return url.Parse(ts.URL) 279 }, 280 } 281 client.SetTransport(transport) 282 transportInUse, err := client.transport() 283 284 assert.Nil(t, err) 285 assert.Equal(t, true, transport == transportInUse) 286 } 287 288 func TestClientSetScheme(t *testing.T) { 289 client := dc() 290 291 client.SetScheme("http") 292 293 assert.Equal(t, true, client.scheme == "http") 294 } 295 296 func TestClientSetCookieJar(t *testing.T) { 297 client := dc() 298 backupJar := client.httpClient.Jar 299 300 client.SetCookieJar(nil) 301 assert.Nil(t, client.httpClient.Jar) 302 303 client.SetCookieJar(backupJar) 304 assert.Equal(t, true, client.httpClient.Jar == backupJar) 305 } 306 307 func TestClientOptions(t *testing.T) { 308 client := dc() 309 client.SetContentLength(true) 310 assert.Equal(t, client.setContentLength, true) 311 312 client.SetBaseURL("http://httpbin.org") 313 assert.Equal(t, "http://httpbin.org", client.BaseURL) 314 315 client.SetHeader(hdrContentTypeKey, "application/json; charset=utf-8") 316 client.SetHeaders(map[string]string{ 317 hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.1", 318 "X-Request-Id": strconv.FormatInt(time.Now().UnixNano(), 10), 319 }) 320 assert.Equal(t, "application/json; charset=utf-8", client.Header.Get(hdrContentTypeKey)) 321 322 client.SetCookies(&http.Cookie{ 323 Name: "default-cookie", 324 Value: "This is cookie default-cookie value", 325 }) 326 assert.Equal(t, "default-cookie", client.Cookies[0].Name) 327 328 cookies := []*http.Cookie{ 329 { 330 Name: "default-cookie-1", 331 Value: "This is default-cookie 1 value", 332 }, { 333 Name: "default-cookie-2", 334 Value: "This is default-cookie 2 value", 335 }, 336 } 337 client.SetCookies(cookies...) 338 assert.Equal(t, "default-cookie-1", client.Cookies[1].Name) 339 assert.Equal(t, "default-cookie-2", client.Cookies[2].Name) 340 341 client.SetQueryParam("test_param_1", "Param_1") 342 client.SetQueryParams(map[string]string{"test_param_2": "Param_2", "test_param_3": "Param_3"}) 343 assert.Equal(t, "Param_3", client.QueryParam.Get("test_param_3")) 344 345 rTime := strconv.FormatInt(time.Now().UnixNano(), 10) 346 client.SetFormData(map[string]string{"r_time": rTime}) 347 assert.Equal(t, rTime, client.FormData.Get("r_time")) 348 349 client.SetBasicAuth("myuser", "mypass") 350 assert.Equal(t, "myuser", client.UserInfo.Username) 351 352 client.SetAuthToken("AC75BD37F019E08FBC594900518B4F7E") 353 assert.Equal(t, "AC75BD37F019E08FBC594900518B4F7E", client.Token) 354 355 client.SetDisableWarn(true) 356 assert.Equal(t, client.DisableWarn, true) 357 358 client.SetRetryCount(3) 359 assert.Equal(t, 3, client.RetryCount) 360 361 rwt := time.Duration(1000) * time.Millisecond 362 client.SetRetryWaitTime(rwt) 363 assert.Equal(t, rwt, client.RetryWaitTime) 364 365 mrwt := time.Duration(2) * time.Second 366 client.SetRetryMaxWaitTime(mrwt) 367 assert.Equal(t, mrwt, client.RetryMaxWaitTime) 368 369 client.AddRetryAfterErrorCondition() 370 // assert.True(t, reflect.DeepEqual(client.RetryConditions[0], 371 // func(response *Response, err error) bool { return response.IsError() })) 372 373 err := &AuthError{} 374 client.SetError(err) 375 if reflect.TypeOf(err) == client.Error { 376 t.Error("SetError failed") 377 } 378 379 client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}) 380 transport, transportErr := client.transport() 381 382 assert.Nil(t, transportErr) 383 assert.Equal(t, true, transport.TLSClientConfig.InsecureSkipVerify) 384 385 client.OnBeforeRequest(func(c *Client, r *Request) error { 386 c.log.Debugf("I'm in Request middleware") 387 return nil // if it success 388 }) 389 client.OnAfterResponse(func(c *Client, r *Response) error { 390 c.log.Debugf("I'm in Response middleware") 391 return nil // if it success 392 }) 393 394 client.SetTimeout(5 * time.Second) 395 client.SetRedirectPolicy(FlexibleRedirectPolicy(10), func(req *http.Request, via []*http.Request) error { 396 return errors.New("sample test redirect") 397 }) 398 client.SetContentLength(true) 399 400 client.SetDebug(true) 401 assert.Equal(t, client.Debug, true) 402 403 var sl int64 = 1000000 404 client.SetDebugBodyLimit(sl) 405 assert.Equal(t, client.debugBodySizeLimit, sl) 406 407 client.SetAllowGetMethodPayload(true) 408 assert.Equal(t, client.AllowGetMethodPayload, true) 409 410 client.SetScheme("http") 411 assert.Equal(t, client.scheme, "http") 412 413 client.SetCloseConnection(true) 414 assert.Equal(t, client.closeConnection, true) 415 } 416 417 func TestClientPreRequestHook(t *testing.T) { 418 client := dc() 419 client.SetPreRequestHook(func(c *Client, r *http.Request) error { 420 c.log.Debugf("I'm in Pre-Request Hook") 421 return nil 422 }) 423 424 client.SetPreRequestHook(func(c *Client, r *http.Request) error { 425 c.log.Debugf("I'm Overwriting existing Pre-Request Hook") 426 427 // Reading Request `N` no of times 428 for i := 0; i < 5; i++ { 429 b, _ := r.GetBody() 430 rb, _ := io.ReadAll(b) 431 c.log.Debugf("%s %v", string(rb), len(rb)) 432 assert.Equal(t, true, len(rb) >= 45) 433 } 434 return nil 435 }) 436 437 ts := createPostServer(t) 438 defer ts.Close() 439 440 // Regular bodybuf use case 441 resp, _ := client.R(). 442 SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}). 443 Post(ts.URL + "/login") 444 assert.Equal(t, http.StatusOK, resp.StatusCode()) 445 assert.Equal(t, `{ "id": "success", "message": "login successful" }`, resp.String()) 446 447 // io.Reader body use case 448 resp, _ = client.R(). 449 SetHeader(hdrContentTypeKey, jsonContentType). 450 SetBody(bytes.NewReader([]byte(`{"username":"testuser", "password":"testpass"}`))). 451 Post(ts.URL + "/login") 452 assert.Equal(t, http.StatusOK, resp.StatusCode()) 453 assert.Equal(t, `{ "id": "success", "message": "login successful" }`, resp.String()) 454 } 455 456 func TestClientAllowsGetMethodPayload(t *testing.T) { 457 ts := createGetServer(t) 458 defer ts.Close() 459 460 c := dc() 461 c.SetAllowGetMethodPayload(true) 462 c.SetPreRequestHook(func(*Client, *http.Request) error { return nil }) // for coverage 463 464 payload := "test-payload" 465 resp, err := c.R().SetBody(payload).Get(ts.URL + "/get-method-payload-test") 466 467 assert.Nil(t, err) 468 assert.Equal(t, http.StatusOK, resp.StatusCode()) 469 assert.Equal(t, payload, resp.String()) 470 } 471 472 func TestClientRoundTripper(t *testing.T) { 473 c := NewWithClient(&http.Client{}) 474 c.outputLogTo(io.Discard) 475 476 rt := &CustomRoundTripper{} 477 c.SetTransport(rt) 478 479 ct, err := c.transport() 480 assert.NotNil(t, err) 481 assert.Nil(t, ct) 482 assert.Equal(t, "current transport is not an *http.Transport instance", err.Error()) 483 484 c.SetTLSClientConfig(&tls.Config{}) 485 c.SetProxy("http://localhost:9090") 486 c.RemoveProxy() 487 c.SetCertificates(tls.Certificate{}) 488 c.SetRootCertificate(filepath.Join(getTestDataPath(), "sample-root.pem")) 489 } 490 491 func TestClientNewRequest(t *testing.T) { 492 c := New() 493 request := c.NewRequest() 494 assert.NotNil(t, request) 495 } 496 497 func TestDebugBodySizeLimit(t *testing.T) { 498 ts := createGetServer(t) 499 defer ts.Close() 500 501 var lgr bytes.Buffer 502 c := dc() 503 c.SetDebug(true) 504 c.SetDebugBodyLimit(30) 505 c.outputLogTo(&lgr) 506 507 testcases := []struct{ url, want string }{ 508 // Text, does not exceed limit. 509 {ts.URL, "TestGet: text response"}, 510 // Empty response. 511 {ts.URL + "/no-content", "***** NO CONTENT *****"}, 512 // JSON, does not exceed limit. 513 {ts.URL + "/json", "{\n \"TestGet\": \"JSON response\"\n}"}, 514 // Invalid JSON, does not exceed limit. 515 {ts.URL + "/json-invalid", "TestGet: Invalid JSON"}, 516 // Text, exceeds limit. 517 {ts.URL + "/long-text", "RESPONSE TOO LARGE"}, 518 // JSON, exceeds limit. 519 {ts.URL + "/long-json", "RESPONSE TOO LARGE"}, 520 } 521 522 for _, tc := range testcases { 523 _, err := c.R().Get(tc.url) 524 assert.Nil(t, err) 525 debugLog := lgr.String() 526 if !strings.Contains(debugLog, tc.want) { 527 t.Errorf("Expected logs to contain [%v], got [\n%v]", tc.want, debugLog) 528 } 529 lgr.Reset() 530 } 531 } 532 533 // CustomRoundTripper just for test 534 type CustomRoundTripper struct{} 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 assert.Nil(t, err) 557 assert.Equal(t, http.StatusOK, resp.StatusCode()) 558 assert.Equal(t, "200 OK", resp.Status()) 559 assert.NotNil(t, resp.Body()) 560 assert.Equal(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 assert.Nil(t, err) 594 assert.Equal(t, http.StatusOK, resp.StatusCode()) 595 596 // Validating debug log updates 597 logInfo := lgr.String() 598 assert.Equal(t, true, strings.Contains(logInfo, "Bearer *******************************")) 599 assert.Equal(t, true, strings.Contains(logInfo, "X-Debug-Resposne-Log")) 600 assert.Equal(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 assert.Equal(t, errors.New("request test error"), err) 608 assert.Nil(t, resp) 609 assert.NotNil(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 assert.Equal(t, errors.New("response test error"), err) 617 assert.NotNil(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.SetBaseURL(ts.URL) 627 628 resp, err := client.R().Get("/") 629 assert.Nil(t, err) 630 assert.Equal(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 assertErrorHook := func(r *Request, err error) { 695 assert.NotNil(t, r) 696 v, ok := err.(*ResponseError) 697 assert.Equal(t, test.hasResponse, ok) 698 if ok { 699 assert.NotNil(t, v.Response) 700 assert.NotNil(t, v.Err) 701 } 702 } 703 var hook1, hook2 int 704 c := New().outputLogTo(io.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 assert.NotNil(t, err) 729 assert.Equal(t, 1, hook1) 730 assert.Equal(t, 1, hook2) 731 } else { 732 assert.Nil(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 assert.NotNil(t, re.Unwrap()) 745 assert.Equal(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 // assert.Nil(t, err) 775 // assert.NotNil(t, resp) 776 777 // t.Log("\nwithout leading `/`") 778 // resp, err = c.R().Post("login") 779 // assert.Nil(t, err) 780 // assert.NotNil(t, resp) 781 782 t.Log("with leading `/` on request & with trailing `/` on host url") 783 c.SetBaseURL(ts.URL + "/") 784 resp, err := c.R(). 785 SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}). 786 Post("/login") 787 assert.Nil(t, err) 788 assert.NotNil(t, resp) 789 }