// Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
// resty source code and usage is governed by a MIT style
// license that can be found in the LICENSE file.
package resty
import (
"bytes"
"crypto/tls"
"encoding/xml"
"errors"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
)
type AuthSuccess struct {
ID, Message string
}
type AuthError struct {
ID, Message string
}
func TestGet(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dc().R().
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
Get(ts.URL + "/")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "HTTP/1.1", resp.Proto())
assertEqual(t, "200 OK", resp.Status())
assertNotNil(t, resp.Body())
assertEqual(t, "TestGet: text response", resp.String())
logResponse(t, resp)
}
func TestIllegalRetryCount(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dc().SetRetryCount(-1).R().Get(ts.URL + "/")
assertNil(t, err)
assertNil(t, resp)
}
func TestGetCustomUserAgent(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dcr().
SetHeader(hdrUserAgentKey, "Test Custom User agent").
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
Get(ts.URL + "/")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "HTTP/1.1", resp.Proto())
assertEqual(t, "200 OK", resp.Status())
assertEqual(t, "TestGet: text response", resp.String())
logResponse(t, resp)
}
func TestGetClientParamRequestParam(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
c := dc()
c.SetQueryParam("client_param", "true").
SetQueryParams(map[string]string{"req_1": "jeeva", "req_3": "jeeva3"}).
SetDebug(true)
c.outputLogTo(ioutil.Discard)
resp, err := c.R().
SetQueryParams(map[string]string{"req_1": "req 1 value", "req_2": "req 2 value"}).
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
SetHeader(hdrUserAgentKey, "Test Custom User agent").
Get(ts.URL + "/")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "HTTP/1.1", resp.Proto())
assertEqual(t, "200 OK", resp.Status())
assertEqual(t, "TestGet: text response", resp.String())
logResponse(t, resp)
}
func TestGetRelativePath(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
c := dc()
c.SetHostURL(ts.URL)
resp, err := c.R().Get("mypage2")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "TestGet: text response from mypage2", resp.String())
logResponse(t, resp)
}
func TestGet400Error(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dcr().Get(ts.URL + "/mypage")
assertError(t, err)
assertEqual(t, http.StatusBadRequest, resp.StatusCode())
assertEqual(t, "", resp.String())
logResponse(t, resp)
}
func TestPostJSONStringSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetHeader(hdrContentTypeKey, "application/json; charset=utf-8").
SetHeaders(map[string]string{hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.1", hdrAcceptKey: "application/json; charset=utf-8"})
resp, err := c.R().
SetBody(`{"username":"testuser", "password":"testpass"}`).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
logResponse(t, resp)
// PostJSONStringError
resp, err = c.R().
SetBody(`{"username":"testuser" "password":"testpass"}`).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusBadRequest, resp.StatusCode())
logResponse(t, resp)
}
func TestPostJSONBytesSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetHeader(hdrContentTypeKey, "application/json; charset=utf-8").
SetHeaders(map[string]string{hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.7", hdrAcceptKey: "application/json; charset=utf-8"})
resp, err := c.R().
SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
logResponse(t, resp)
}
func TestPostJSONBytesIoReader(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetHeader(hdrContentTypeKey, "application/json; charset=utf-8")
bodyBytes := []byte(`{"username":"testuser", "password":"testpass"}`)
resp, err := c.R().
SetBody(bytes.NewReader(bodyBytes)).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
logResponse(t, resp)
}
func TestPostJSONStructSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
user := &User{Username: "testuser", Password: "testpass"}
c := dc().SetJSONEscapeHTML(false)
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/json; charset=utf-8").
SetBody(user).
SetResult(&AuthSuccess{}).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestPostJSONRPCStructSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
user := &User{Username: "testuser", Password: "testpass"}
c := dc().SetJSONEscapeHTML(false)
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/json-rpc").
SetBody(user).
SetResult(&AuthSuccess{}).
SetQueryParam("ct", "rpc").
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestPostJSONStructInvalidLogin(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetDebug(false)
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/json; charset=utf-8").
SetBody(User{Username: "testuser", Password: "testpass1"}).
SetError(AuthError{}).
SetJSONEscapeHTML(false).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusUnauthorized, resp.StatusCode())
authError := resp.Error().(*AuthError)
assertEqual(t, "unauthorized", authError.ID)
assertEqual(t, "Invalid credentials", authError.Message)
t.Logf("Result Error: %q", resp.Error().(*AuthError))
logResponse(t, resp)
}
func TestPostJSONErrorRFC7807(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/json; charset=utf-8").
SetBody(User{Username: "testuser", Password: "testpass1"}).
SetError(AuthError{}).
Post(ts.URL + "/login?ct=problem")
assertError(t, err)
assertEqual(t, http.StatusUnauthorized, resp.StatusCode())
authError := resp.Error().(*AuthError)
assertEqual(t, "unauthorized", authError.ID)
assertEqual(t, "Invalid credentials", authError.Message)
t.Logf("Result Error: %q", resp.Error().(*AuthError))
logResponse(t, resp)
}
func TestPostJSONMapSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetDebug(false)
resp, err := c.R().
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
SetResult(AuthSuccess{}).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestPostJSONMapInvalidResponseJson(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
resp, err := dclr().
SetBody(map[string]interface{}{"username": "testuser", "password": "invalidjson"}).
SetResult(&AuthSuccess{}).
Post(ts.URL + "/login")
assertEqual(t, "invalid character '}' looking for beginning of object key string", err.Error())
assertEqual(t, http.StatusOK, resp.StatusCode())
authSuccess := resp.Result().(*AuthSuccess)
assertEqual(t, "", authSuccess.ID)
assertEqual(t, "", authSuccess.Message)
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
type brokenMarshalJSON struct{}
func (b brokenMarshalJSON) MarshalJSON() ([]byte, error) {
return nil, errors.New("b0rk3d")
}
func TestPostJSONMarshalError(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
b := brokenMarshalJSON{}
exp := "b0rk3d"
_, err := dclr().
SetHeader(hdrContentTypeKey, "application/json").
SetBody(b).
Post(ts.URL + "/login")
if err == nil {
t.Fatalf("expected error but got %v", err)
}
if !strings.Contains(err.Error(), exp) {
t.Errorf("expected error string %q to contain %q", err, exp)
}
}
func TestForceContentTypeForGH276andGH240(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
retried := 0
c := dc()
c.SetDebug(false)
c.SetRetryCount(3)
c.SetRetryAfter(RetryAfterFunc(func(*Client, *Response) (time.Duration, error) {
retried++
return 0, nil
}))
resp, err := c.R().
SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
SetResult(AuthSuccess{}).
ForceContentType("application/json").
Post(ts.URL + "/login-json-html")
assertNotNil(t, err) // expecting error due to incorrect content type from server end
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, 0, retried)
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestPostXMLStringSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetDebug(false)
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(`testusertestpass`).
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
logResponse(t, resp)
}
type brokenMarshalXML struct{}
func (b brokenMarshalXML) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return errors.New("b0rk3d")
}
func TestPostXMLMarshalError(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
b := brokenMarshalXML{}
exp := "b0rk3d"
_, err := dclr().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(b).
Post(ts.URL + "/login")
if err == nil {
t.Fatalf("expected error but got %v", err)
}
if !strings.Contains(err.Error(), exp) {
t.Errorf("expected error string %q to contain %q", err, exp)
}
}
func TestPostXMLStringError(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
resp, err := dclr().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(`testusertestpass`).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusBadRequest, resp.StatusCode())
assertEqual(t, `bad_requestUnable to read user info`, resp.String())
logResponse(t, resp)
}
func TestPostXMLBytesSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetDebug(false)
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody([]byte(`testusertestpass`)).
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
SetContentLength(true).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
logResponse(t, resp)
}
func TestPostXMLStructSuccess(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
resp, err := dclr().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(User{Username: "testuser", Password: "testpass"}).
SetContentLength(true).
SetResult(&AuthSuccess{}).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestPostXMLStructInvalidLogin(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
c.SetError(&AuthError{})
resp, err := c.R().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(User{Username: "testuser", Password: "testpass1"}).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusUnauthorized, resp.StatusCode())
assertEqual(t, resp.Header().Get("Www-Authenticate"), "Protected Realm")
t.Logf("Result Error: %q", resp.Error().(*AuthError))
logResponse(t, resp)
}
func TestPostXMLStructInvalidResponseXml(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
resp, err := dclr().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(User{Username: "testuser", Password: "invalidxml"}).
SetResult(&AuthSuccess{}).
Post(ts.URL + "/login")
assertEqual(t, "XML syntax error on line 1: element closed by ", err.Error())
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestPostXMLMapNotSupported(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
_, err := dclr().
SetHeader(hdrContentTypeKey, "application/xml").
SetBody(map[string]interface{}{"Username": "testuser", "Password": "testpass"}).
Post(ts.URL + "/login")
assertEqual(t, "unsupported 'Body' type/value", err.Error())
}
func TestRequestBasicAuth(t *testing.T) {
ts := createAuthServer(t)
defer ts.Close()
c := dc()
c.SetHostURL(ts.URL).
SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
resp, err := c.R().
SetBasicAuth("myuser", "basicauth").
SetResult(&AuthSuccess{}).
Post("/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
func TestRequestBasicAuthFail(t *testing.T) {
ts := createAuthServer(t)
defer ts.Close()
c := dc()
c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
SetError(AuthError{})
resp, err := c.R().
SetBasicAuth("myuser", "basicauth1").
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusUnauthorized, resp.StatusCode())
t.Logf("Result Error: %q", resp.Error().(*AuthError))
logResponse(t, resp)
}
func TestRequestAuthToken(t *testing.T) {
ts := createAuthServer(t)
defer ts.Close()
c := dc()
c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF")
resp, err := c.R().
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
Get(ts.URL + "/profile")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestRequestAuthScheme(t *testing.T) {
ts := createAuthServer(t)
defer ts.Close()
c := dc()
c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
SetAuthScheme("OAuth").
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF")
resp, err := c.R().
SetAuthScheme("Bearer").
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
Get(ts.URL + "/profile")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestFormData(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
c := dc()
c.SetFormData(map[string]string{"zip_code": "00000", "city": "Los Angeles"}).
SetContentLength(true).
SetDebug(true)
c.outputLogTo(ioutil.Discard)
resp, err := c.R().
SetFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M", "zip_code": "00001"}).
SetBasicAuth("myuser", "mypass").
Post(ts.URL + "/profile")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "Success", resp.String())
}
func TestMultiValueFormData(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
v := url.Values{
"search_criteria": []string{"book", "glass", "pencil"},
}
c := dc()
c.SetContentLength(true).SetDebug(true)
c.outputLogTo(ioutil.Discard)
resp, err := c.R().
SetQueryParamsFromValues(v).
Post(ts.URL + "/search")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "Success", resp.String())
}
func TestFormDataDisableWarn(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
c := dc()
c.SetFormData(map[string]string{"zip_code": "00000", "city": "Los Angeles"}).
SetContentLength(true).
SetDebug(true).
SetDisableWarn(true)
c.outputLogTo(ioutil.Discard)
resp, err := c.R().
SetFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M", "zip_code": "00001"}).
SetBasicAuth("myuser", "mypass").
Post(ts.URL + "/profile")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "Success", resp.String())
}
func TestMultiPartUploadFile(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
basePath := getTestDataPath()
c := dc()
c.SetFormData(map[string]string{"zip_code": "00001", "city": "Los Angeles"})
resp, err := c.R().
SetFile("profile_img", filepath.Join(basePath, "test-img.png")).
SetContentLength(true).
Post(ts.URL + "/upload")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestMultiPartUploadFileError(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
basePath := getTestDataPath()
c := dc()
c.SetFormData(map[string]string{"zip_code": "00001", "city": "Los Angeles"})
resp, err := c.R().
SetFile("profile_img", filepath.Join(basePath, "test-img-not-exists.png")).
Post(ts.URL + "/upload")
if err == nil {
t.Errorf("Expected [%v], got [%v]", nil, err)
}
if resp != nil {
t.Errorf("Expected [%v], got [%v]", nil, resp)
}
}
func TestMultiPartUploadFiles(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
basePath := getTestDataPath()
resp, err := dclr().
SetFormDataFromValues(url.Values{
"first_name": []string{"Jeevanandam"},
"last_name": []string{"M"},
}).
SetFiles(map[string]string{"profile_img": filepath.Join(basePath, "test-img.png"), "notes": filepath.Join(basePath, "text-file.txt")}).
Post(ts.URL + "/upload")
responseStr := resp.String()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(responseStr, "test-img.png"))
assertEqual(t, true, strings.Contains(responseStr, "text-file.txt"))
}
func TestMultiPartIoReaderFiles(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
basePath := getTestDataPath()
profileImgBytes, _ := ioutil.ReadFile(filepath.Join(basePath, "test-img.png"))
notesBytes, _ := ioutil.ReadFile(filepath.Join(basePath, "text-file.txt"))
// Just info values
file := File{
Name: "test_file_name.jpg",
ParamName: "test_param",
Reader: bytes.NewBuffer([]byte("test bytes")),
}
t.Logf("File Info: %v", file.String())
resp, err := dclr().
SetFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M"}).
SetFileReader("profile_img", "test-img.png", bytes.NewReader(profileImgBytes)).
SetFileReader("notes", "text-file.txt", bytes.NewReader(notesBytes)).
Post(ts.URL + "/upload")
responseStr := resp.String()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(responseStr, "test-img.png"))
assertEqual(t, true, strings.Contains(responseStr, "text-file.txt"))
}
func TestMultiPartUploadFileNotOnGetOrDelete(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
basePath := getTestDataPath()
_, err := dclr().
SetFile("profile_img", filepath.Join(basePath, "test-img.png")).
Get(ts.URL + "/upload")
assertEqual(t, "multipart content is not allowed in HTTP verb [GET]", err.Error())
_, err = dclr().
SetFile("profile_img", filepath.Join(basePath, "test-img.png")).
Delete(ts.URL + "/upload")
assertEqual(t, "multipart content is not allowed in HTTP verb [DELETE]", err.Error())
}
func TestMultiPartFormData(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
resp, err := dclr().
SetMultipartFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M", "zip_code": "00001"}).
SetBasicAuth("myuser", "mypass").
Post(ts.URL + "/profile")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "Success", resp.String())
}
func TestMultiPartMultipartField(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
jsonBytes := []byte(`{"input": {"name": "Uploaded document", "_filename" : ["file.txt"]}}`)
resp, err := dclr().
SetFormDataFromValues(url.Values{
"first_name": []string{"Jeevanandam"},
"last_name": []string{"M"},
}).
SetMultipartField("uploadManifest", "upload-file.json", "application/json", bytes.NewReader(jsonBytes)).
Post(ts.URL + "/upload")
responseStr := resp.String()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(responseStr, "upload-file.json"))
}
func TestMultiPartMultipartFields(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/upload")
jsonStr1 := `{"input": {"name": "Uploaded document 1", "_filename" : ["file1.txt"]}}`
jsonStr2 := `{"input": {"name": "Uploaded document 2", "_filename" : ["file2.txt"]}}`
fields := []*MultipartField{
{
Param: "uploadManifest1",
FileName: "upload-file-1.json",
ContentType: "application/json",
Reader: strings.NewReader(jsonStr1),
},
{
Param: "uploadManifest2",
FileName: "upload-file-2.json",
ContentType: "application/json",
Reader: strings.NewReader(jsonStr2),
},
{
Param: "uploadManifest3",
ContentType: "application/json",
Reader: strings.NewReader(jsonStr2),
},
}
resp, err := dclr().
SetFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M"}).
SetMultipartFields(fields...).
Post(ts.URL + "/upload")
responseStr := resp.String()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(responseStr, "upload-file-1.json"))
assertEqual(t, true, strings.Contains(responseStr, "upload-file-2.json"))
}
func TestGetWithCookie(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
c := dcl()
c.SetHostURL(ts.URL)
c.SetCookie(&http.Cookie{
Name: "go-resty-1",
Value: "This is cookie 1 value",
})
resp, err := c.R().
SetCookie(&http.Cookie{
Name: "go-resty-2",
Value: "This is cookie 2 value",
}).
SetCookies([]*http.Cookie{
{
Name: "go-resty-1",
Value: "This is cookie 1 value additional append",
},
}).
Get("mypage2")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "TestGet: text response from mypage2", resp.String())
logResponse(t, resp)
}
func TestGetWithCookies(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
c := dc()
c.SetHostURL(ts.URL).SetDebug(true)
tu, _ := url.Parse(ts.URL)
c.GetClient().Jar.SetCookies(tu, []*http.Cookie{
{
Name: "jar-go-resty-1",
Value: "From Jar - This is cookie 1 value",
},
{
Name: "jar-go-resty-2",
Value: "From Jar - This is cookie 2 value",
},
})
resp, err := c.R().SetHeader("Cookie", "").Get("mypage2")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
// Client cookies
c.SetCookies([]*http.Cookie{
{
Name: "go-resty-1",
Value: "This is cookie 1 value",
},
{
Name: "go-resty-2",
Value: "This is cookie 2 value",
},
})
resp, err = c.R().
SetCookie(&http.Cookie{
Name: "req-go-resty-1",
Value: "This is request cookie 1 value additional append",
}).
Get("mypage2")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "TestGet: text response from mypage2", resp.String())
logResponse(t, resp)
}
func TestPutPlainString(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
resp, err := dc().R().
SetBody("This is plain text body to server").
Put(ts.URL + "/plaintext")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "TestPut: plain text response", resp.String())
}
func TestPutJSONString(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
client := dc()
client.OnBeforeRequest(func(c *Client, r *Request) error {
r.SetHeader("X-Custom-Request-Middleware", "OnBeforeRequest middleware")
return nil
})
client.OnBeforeRequest(func(c *Client, r *Request) error {
c.SetContentLength(true)
r.SetHeader("X-ContentLength", "OnBeforeRequest ContentLength set")
return nil
})
client.SetDebug(true)
client.outputLogTo(ioutil.Discard)
resp, err := client.R().
SetHeaders(map[string]string{hdrContentTypeKey: "application/json; charset=utf-8", hdrAcceptKey: "application/json; charset=utf-8"}).
SetBody(`{"content":"json content sending to server"}`).
Put(ts.URL + "/json")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, `{"response":"json response"}`, resp.String())
}
func TestPutXMLString(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
resp, err := dc().R().
SetHeaders(map[string]string{hdrContentTypeKey: "application/xml", hdrAcceptKey: "application/xml"}).
SetBody(`XML Content sending to server`).
Put(ts.URL + "/xml")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, `XML response`, resp.String())
}
func TestOnBeforeMiddleware(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
c := dc()
c.OnBeforeRequest(func(c *Client, r *Request) error {
r.SetHeader("X-Custom-Request-Middleware", "OnBeforeRequest middleware")
return nil
})
c.OnBeforeRequest(func(c *Client, r *Request) error {
c.SetContentLength(true)
r.SetHeader("X-ContentLength", "OnBeforeRequest ContentLength set")
return nil
})
resp, err := c.R().
SetBody("OnBeforeRequest: This is plain text body to server").
Put(ts.URL + "/plaintext")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "TestPut: plain text response", resp.String())
}
func TestHTTPAutoRedirectUpTo10(t *testing.T) {
ts := createRedirectServer(t)
defer ts.Close()
_, err := dc().R().Get(ts.URL + "/redirect-1")
assertEqual(t, true, ("Get /redirect-11: stopped after 10 redirects" == err.Error() ||
"Get \"/redirect-11\": stopped after 10 redirects" == err.Error()))
}
func TestHostCheckRedirectPolicy(t *testing.T) {
ts := createRedirectServer(t)
defer ts.Close()
c := dc().
SetRedirectPolicy(DomainCheckRedirectPolicy("127.0.0.1"))
_, err := c.R().Get(ts.URL + "/redirect-host-check-1")
assertNotNil(t, err)
assertEqual(t, true, strings.Contains(err.Error(), "redirect is not allowed as per DomainCheckRedirectPolicy"))
}
func TestHeadMethod(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dclr().Head(ts.URL + "/")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestOptionsMethod(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
resp, err := dclr().Options(ts.URL + "/options")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, resp.Header().Get("Access-Control-Expose-Headers"), "x-go-resty-id")
}
func TestPatchMethod(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
resp, err := dclr().Patch(ts.URL + "/patch")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
resp.body = nil
assertEqual(t, "", resp.String())
}
func TestSendMethod(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
t.Run("send-get", func(t *testing.T) {
req := dclr()
req.Method = http.MethodGet
req.URL = ts.URL + "/gzip-test"
resp, err := req.Send()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "This is Gzip response testing", resp.String())
})
t.Run("send-options", func(t *testing.T) {
req := dclr()
req.Method = http.MethodOptions
req.URL = ts.URL + "/options"
resp, err := req.Send()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "", resp.String())
assertEqual(t, "x-go-resty-id", resp.Header().Get("Access-Control-Expose-Headers"))
})
t.Run("send-patch", func(t *testing.T) {
req := dclr()
req.Method = http.MethodPatch
req.URL = ts.URL + "/patch"
resp, err := req.Send()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "", resp.String())
})
t.Run("send-put", func(t *testing.T) {
req := dclr()
req.Method = http.MethodPut
req.URL = ts.URL + "/plaintext"
resp, err := req.Send()
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "TestPut: plain text response", resp.String())
})
}
func TestRawFileUploadByBody(t *testing.T) {
ts := createFormPostServer(t)
defer ts.Close()
file, err := os.Open(filepath.Join(getTestDataPath(), "test-img.png"))
assertNil(t, err)
fileBytes, err := ioutil.ReadAll(file)
assertNil(t, err)
resp, err := dclr().
SetBody(fileBytes).
SetContentLength(true).
SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
Put(ts.URL + "/raw-upload")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "image/png", resp.Request.Header.Get(hdrContentTypeKey))
}
func TestProxySetting(t *testing.T) {
c := dc()
transport, err := c.transport()
assertNil(t, err)
assertEqual(t, false, c.IsProxySet())
assertNotNil(t, transport.Proxy)
c.SetProxy("http://sampleproxy:8888")
assertEqual(t, true, c.IsProxySet())
assertNotNil(t, transport.Proxy)
c.SetProxy("//not.a.user@%66%6f%6f.com:8888")
assertEqual(t, true, c.IsProxySet())
assertNotNil(t, transport.Proxy)
c.SetProxy("http://sampleproxy:8888")
assertEqual(t, true, c.IsProxySet())
c.RemoveProxy()
assertNil(t, c.proxyURL)
assertNil(t, transport.Proxy)
}
func TestGetClient(t *testing.T) {
client := New()
custom := New()
customClient := custom.GetClient()
assertNotNil(t, customClient)
assertNotEqual(t, client, http.DefaultClient)
assertNotEqual(t, customClient, http.DefaultClient)
assertNotEqual(t, client, customClient)
}
func TestIncorrectURL(t *testing.T) {
c := dc()
_, err := c.R().Get("//not.a.user@%66%6f%6f.com/just/a/path/also")
assertEqual(t, true, (strings.Contains(err.Error(), "parse //not.a.user@%66%6f%6f.com/just/a/path/also") ||
strings.Contains(err.Error(), "parse \"//not.a.user@%66%6f%6f.com/just/a/path/also\"")))
c.SetHostURL("//not.a.user@%66%6f%6f.com")
_, err1 := c.R().Get("/just/a/path/also")
assertEqual(t, true, (strings.Contains(err1.Error(), "parse //not.a.user@%66%6f%6f.com/just/a/path/also") ||
strings.Contains(err1.Error(), "parse \"//not.a.user@%66%6f%6f.com/just/a/path/also\"")))
}
func TestDetectContentTypeForPointer(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
user := &User{Username: "testuser", Password: "testpass"}
resp, err := dclr().
SetBody(user).
SetResult(AuthSuccess{}).
Post(ts.URL + "/login")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
logResponse(t, resp)
}
type ExampleUser struct {
FirstName string `json:"frist_name"`
LastName string `json:"last_name"`
ZipCode string `json:"zip_code"`
}
func TestDetectContentTypeForPointerWithSlice(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
users := &[]ExampleUser{
{FirstName: "firstname1", LastName: "lastname1", ZipCode: "10001"},
{FirstName: "firstname2", LastName: "lastname3", ZipCode: "10002"},
{FirstName: "firstname3", LastName: "lastname3", ZipCode: "10003"},
}
resp, err := dclr().
SetBody(users).
Post(ts.URL + "/users")
assertError(t, err)
assertEqual(t, http.StatusAccepted, resp.StatusCode())
t.Logf("Result Success: %q", resp)
logResponse(t, resp)
}
func TestDetectContentTypeForPointerWithSliceMap(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
usersmap := map[string]interface{}{
"user1": ExampleUser{FirstName: "firstname1", LastName: "lastname1", ZipCode: "10001"},
"user2": &ExampleUser{FirstName: "firstname2", LastName: "lastname3", ZipCode: "10002"},
"user3": ExampleUser{FirstName: "firstname3", LastName: "lastname3", ZipCode: "10003"},
}
var users []map[string]interface{}
users = append(users, usersmap)
resp, err := dclr().
SetBody(&users).
Post(ts.URL + "/usersmap")
assertError(t, err)
assertEqual(t, http.StatusAccepted, resp.StatusCode())
t.Logf("Result Success: %q", resp)
logResponse(t, resp)
}
func TestDetectContentTypeForSlice(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
users := []ExampleUser{
{FirstName: "firstname1", LastName: "lastname1", ZipCode: "10001"},
{FirstName: "firstname2", LastName: "lastname3", ZipCode: "10002"},
{FirstName: "firstname3", LastName: "lastname3", ZipCode: "10003"},
}
resp, err := dclr().
SetBody(users).
Post(ts.URL + "/users")
assertError(t, err)
assertEqual(t, http.StatusAccepted, resp.StatusCode())
t.Logf("Result Success: %q", resp)
logResponse(t, resp)
}
func TestMultiParamsQueryString(t *testing.T) {
ts1 := createGetServer(t)
defer ts1.Close()
client := dc()
req1 := client.R()
client.SetQueryParam("status", "open")
_, _ = req1.SetQueryParam("status", "pending").
Get(ts1.URL)
assertEqual(t, true, strings.Contains(req1.URL, "status=pending"))
// pending overrides open
assertEqual(t, false, strings.Contains(req1.URL, "status=open"))
_, _ = req1.SetQueryParam("status", "approved").
Get(ts1.URL)
assertEqual(t, true, strings.Contains(req1.URL, "status=approved"))
// approved overrides pending
assertEqual(t, false, strings.Contains(req1.URL, "status=pending"))
ts2 := createGetServer(t)
defer ts2.Close()
req2 := client.R()
v := url.Values{
"status": []string{"pending", "approved", "reject"},
}
_, _ = req2.SetQueryParamsFromValues(v).Get(ts2.URL)
assertEqual(t, true, strings.Contains(req2.URL, "status=pending"))
assertEqual(t, true, strings.Contains(req2.URL, "status=approved"))
assertEqual(t, true, strings.Contains(req2.URL, "status=reject"))
// because it's removed by key
assertEqual(t, false, strings.Contains(req2.URL, "status=open"))
}
func TestSetQueryStringTypical(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dclr().
SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
Get(ts.URL)
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "200 OK", resp.Status())
assertEqual(t, "TestGet: text response", resp.String())
resp, err = dclr().
SetQueryString("&%%amp;").
Get(ts.URL)
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "200 OK", resp.Status())
assertEqual(t, "TestGet: text response", resp.String())
}
func TestSetHeaderVerbatim(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
r := dclr().
SetHeaderVerbatim("header-lowercase", "value_lowercase").
SetHeader("header-lowercase", "value_standard")
assertEqual(t, "value_lowercase", strings.Join(r.Header["header-lowercase"], "")) //nolint
assertEqual(t, "value_standard", r.Header.Get("Header-Lowercase"))
}
func TestSetHeaderMultipleValue(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
r := dclr().
SetHeaderMultiValues(map[string][]string{
"Content": {"text/*", "text/html", "*"},
"Authorization": {"Bearer xyz"},
})
assertEqual(t, "text/*, text/html, *", r.Header.Get("content"))
assertEqual(t, "Bearer xyz", r.Header.Get("authorization"))
}
func TestOutputFileWithBaseDirAndRelativePath(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
defer cleanupFiles(".testdata/dir-sample")
client := dc().
SetRedirectPolicy(FlexibleRedirectPolicy(10)).
SetOutputDirectory(filepath.Join(getTestDataPath(), "dir-sample")).
SetDebug(true)
client.outputLogTo(ioutil.Discard)
resp, err := client.R().
SetOutput("go-resty/test-img-success.png").
Get(ts.URL + "/my-image.png")
assertError(t, err)
assertEqual(t, true, resp.Size() != 0)
assertEqual(t, true, resp.Time() > 0)
}
func TestOutputFileWithBaseDirError(t *testing.T) {
c := dc().SetRedirectPolicy(FlexibleRedirectPolicy(10)).
SetOutputDirectory(filepath.Join(getTestDataPath(), `go-resty\0`))
_ = c
}
func TestOutputPathDirNotExists(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
defer cleanupFiles(filepath.Join(".testdata", "not-exists-dir"))
client := dc().
SetRedirectPolicy(FlexibleRedirectPolicy(10)).
SetOutputDirectory(filepath.Join(getTestDataPath(), "not-exists-dir"))
resp, err := client.R().
SetOutput("test-img-success.png").
Get(ts.URL + "/my-image.png")
assertError(t, err)
assertEqual(t, true, resp.Size() != 0)
assertEqual(t, true, resp.Time() > 0)
}
func TestOutputFileAbsPath(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
defer cleanupFiles(filepath.Join(".testdata", "go-resty"))
_, err := dcr().
SetOutput(filepath.Join(getTestDataPath(), "go-resty", "test-img-success-2.png")).
Get(ts.URL + "/my-image.png")
assertError(t, err)
}
func TestContextInternal(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
r := dc().R().
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10))
resp, err := r.Get(ts.URL + "/")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestSRV(t *testing.T) {
c := dc().
SetRedirectPolicy(FlexibleRedirectPolicy(20)).
SetScheme("http")
r := c.R().
SetSRV(&SRVRecord{"xmpp-server", "google.com"})
assertEqual(t, "xmpp-server", r.SRV.Service)
assertEqual(t, "google.com", r.SRV.Domain)
resp, err := r.Get("/")
if err == nil {
assertError(t, err)
assertNotNil(t, resp)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
}
func TestSRVInvalidService(t *testing.T) {
_, err := dc().R().
SetSRV(&SRVRecord{"nonexistantservice", "sampledomain"}).
Get("/")
assertNotNil(t, err)
assertType(t, net.DNSError{}, err)
}
func TestRequestDoNotParseResponse(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
client := dc().SetDoNotParseResponse(true)
resp, err := client.R().
SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)).
Get(ts.URL + "/")
assertError(t, err)
buf := acquireBuffer()
defer releaseBuffer(buf)
_, _ = io.Copy(buf, resp.RawBody())
assertEqual(t, "TestGet: text response", buf.String())
_ = resp.RawBody().Close()
// Manually setting RawResponse as nil
resp, err = dc().R().
SetDoNotParseResponse(true).
Get(ts.URL + "/")
assertError(t, err)
resp.RawResponse = nil
assertNil(t, resp.RawBody())
}
type noCtTest struct {
Response string `json:"response"`
}
func TestRequestExpectContentTypeTest(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
c := dc()
resp, err := c.R().
SetResult(noCtTest{}).
ExpectContentType("application/json").
Get(ts.URL + "/json-no-set")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertNotNil(t, resp.Result())
assertEqual(t, "json response no content type set", resp.Result().(*noCtTest).Response)
assertEqual(t, "", firstNonEmpty("", ""))
}
func TestGetPathParamAndPathParams(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
c := dc().
SetHostURL(ts.URL).
SetPathParam("userId", "sample@sample.com")
resp, err := c.R().SetPathParam("subAccountId", "100002").
Get("/v1/users/{userId}/{subAccountId}/details")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(resp.String(), "TestGetPathParams: text response"))
assertEqual(t, true, strings.Contains(resp.String(), "/v1/users/sample@sample.com/100002/details"))
logResponse(t, resp)
}
func TestReportMethodSupportsPayload(t *testing.T) {
ts := createGenServer(t)
defer ts.Close()
c := dc()
resp, err := c.R().
SetBody("body").
Execute("REPORT", ts.URL+"/report")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestRequestQueryStringOrder(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := New().R().
SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
Get(ts.URL + "/?UniqueId=ead1d0ed-XXX-XXX-XXX-abb7612b3146&Translate=false&tempauth=eyJ0eXAiOiJKV1QiLC...HZEhwVnJ1d0NSUGVLaUpSaVNLRG5scz0&ApiVersion=2.0")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "200 OK", resp.Status())
assertNotNil(t, resp.Body())
assertEqual(t, "TestGet: text response", resp.String())
logResponse(t, resp)
}
func TestRequestOverridesClientAuthorizationHeader(t *testing.T) {
ts := createAuthServer(t)
defer ts.Close()
c := dc()
c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
SetHeader("Authorization", "some token").
SetHostURL(ts.URL + "/")
resp, err := c.R().
SetHeader("Authorization", "Bearer 004DDB79-6801-4587-B976-F093E6AC44FF").
Get("/profile")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
func TestRequestFileUploadAsReader(t *testing.T) {
ts := createFilePostServer(t)
defer ts.Close()
file, _ := os.Open(filepath.Join(getTestDataPath(), "test-img.png"))
defer file.Close()
resp, err := dclr().
SetBody(file).
SetHeader("Content-Type", "image/png").
Post(ts.URL + "/upload")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(resp.String(), "File Uploaded successfully"))
file, _ = os.Open(filepath.Join(getTestDataPath(), "test-img.png"))
defer file.Close()
resp, err = dclr().
SetBody(file).
SetHeader("Content-Type", "image/png").
SetContentLength(true).
Post(ts.URL + "/upload")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(resp.String(), "File Uploaded successfully"))
}
func TestHostHeaderOverride(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
resp, err := dc().R().
SetHeader("Host", "myhostname").
Get(ts.URL + "/host-header")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, "200 OK", resp.Status())
assertNotNil(t, resp.Body())
assertEqual(t, "myhostname", resp.String())
logResponse(t, resp)
}
func TestPathParamURLInput(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
c := dc().SetDebug(true).
SetHostURL(ts.URL).
SetPathParams(map[string]string{
"userId": "sample@sample.com",
})
resp, err := c.R().
SetPathParams(map[string]string{
"subAccountId": "100002",
"website": "https://example.com",
}).Get("/v1/users/{userId}/{subAccountId}/{website}")
assertError(t, err)
assertEqual(t, http.StatusOK, resp.StatusCode())
assertEqual(t, true, strings.Contains(resp.String(), "TestPathParamURLInput: text response"))
assertEqual(t, true, strings.Contains(resp.String(), "/v1/users/sample@sample.com/100002/https:%2F%2Fexample.com"))
logResponse(t, resp)
}
// This test case is kind of pass always
func TestTraceInfo(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
serverAddr := ts.URL[strings.LastIndex(ts.URL, "/")+1:]
client := dc()
client.SetHostURL(ts.URL).EnableTrace()
for _, u := range []string{"/", "/json", "/long-text", "/long-json"} {
resp, err := client.R().Get(u)
assertNil(t, err)
assertNotNil(t, resp)
tr := resp.Request.TraceInfo()
assertEqual(t, true, tr.DNSLookup >= 0)
assertEqual(t, true, tr.ConnTime >= 0)
assertEqual(t, true, tr.TLSHandshake >= 0)
assertEqual(t, true, tr.ServerTime >= 0)
assertEqual(t, true, tr.ResponseTime >= 0)
assertEqual(t, true, tr.TotalTime >= 0)
assertEqual(t, true, tr.TotalTime < time.Hour)
assertEqual(t, true, tr.TotalTime == resp.Time())
assertEqual(t, tr.RemoteAddr.String(), serverAddr)
}
client.DisableTrace()
for _, u := range []string{"/", "/json", "/long-text", "/long-json"} {
resp, err := client.R().EnableTrace().Get(u)
assertNil(t, err)
assertNotNil(t, resp)
tr := resp.Request.TraceInfo()
assertEqual(t, true, tr.DNSLookup >= 0)
assertEqual(t, true, tr.ConnTime >= 0)
assertEqual(t, true, tr.TLSHandshake >= 0)
assertEqual(t, true, tr.ServerTime >= 0)
assertEqual(t, true, tr.ResponseTime >= 0)
assertEqual(t, true, tr.TotalTime >= 0)
assertEqual(t, true, tr.TotalTime == resp.Time())
assertEqual(t, tr.RemoteAddr.String(), serverAddr)
}
// for sake of hook funcs
_, _ = client.R().EnableTrace().Get("https://httpbin.org/get")
}
func TestTraceInfoWithoutEnableTrace(t *testing.T) {
ts := createGetServer(t)
defer ts.Close()
client := dc()
client.SetHostURL(ts.URL)
for _, u := range []string{"/", "/json", "/long-text", "/long-json"} {
resp, err := client.R().Get(u)
assertNil(t, err)
assertNotNil(t, resp)
tr := resp.Request.TraceInfo()
assertEqual(t, true, tr.DNSLookup == 0)
assertEqual(t, true, tr.ConnTime == 0)
assertEqual(t, true, tr.TLSHandshake == 0)
assertEqual(t, true, tr.ServerTime == 0)
assertEqual(t, true, tr.ResponseTime == 0)
assertEqual(t, true, tr.TotalTime == 0)
}
}
func TestTraceInfoOnTimeout(t *testing.T) {
client := dc()
client.SetHostURL("http://resty-nowhere.local").EnableTrace()
resp, err := client.R().Get("/")
assertNotNil(t, err)
assertNotNil(t, resp)
tr := resp.Request.TraceInfo()
assertEqual(t, true, tr.DNSLookup >= 0)
assertEqual(t, true, tr.ConnTime == 0)
assertEqual(t, true, tr.TLSHandshake == 0)
assertEqual(t, true, tr.TCPConnTime == 0)
assertEqual(t, true, tr.ServerTime == 0)
assertEqual(t, true, tr.ResponseTime == 0)
assertEqual(t, true, tr.TotalTime > 0)
assertEqual(t, true, tr.TotalTime == resp.Time())
}
func TestDebugLoggerRequestBodyTooLarge(t *testing.T) {
ts := createFilePostServer(t)
defer ts.Close()
debugBodySizeLimit := int64(512)
// upload an image with more than 512 bytes
output := bytes.NewBufferString("")
resp, err := New().SetDebug(true).outputLogTo(output).SetDebugBodyLimit(debugBodySizeLimit).R().
SetFile("file", filepath.Join(getTestDataPath(), "test-img.png")).
SetHeader("Content-Type", "image/png").
Post(ts.URL + "/upload")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, true, strings.Contains(output.String(), "REQUEST TOO LARGE"))
// upload a text file with no more than 512 bytes
output = bytes.NewBufferString("")
resp, err = New().SetDebug(true).outputLogTo(output).SetDebugBodyLimit(debugBodySizeLimit).R().
SetFile("file", filepath.Join(getTestDataPath(), "text-file.txt")).
SetHeader("Content-Type", "text/plain").
Post(ts.URL + "/upload")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, true, strings.Contains(output.String(), " THIS IS TEXT FILE FOR MULTIPART UPLOAD TEST "))
formTs := createFormPostServer(t)
defer formTs.Close()
// post form with more than 512 bytes data
output = bytes.NewBufferString("")
resp, err = New().SetDebug(true).outputLogTo(output).SetDebugBodyLimit(debugBodySizeLimit).R().
SetFormData(map[string]string{
"first_name": "Alex",
"last_name": strings.Repeat("C", int(debugBodySizeLimit)),
"zip_code": "00001",
}).
SetBasicAuth("myuser", "mypass").
Post(formTs.URL + "/profile")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, true, strings.Contains(output.String(), "REQUEST TOO LARGE"))
// post form with no more than 512 bytes data
output = bytes.NewBufferString("")
resp, err = New().SetDebug(true).outputLogTo(output).SetDebugBodyLimit(debugBodySizeLimit).R().
SetFormData(map[string]string{
"first_name": "Alex",
"last_name": "C",
"zip_code": "00001",
}).
SetBasicAuth("myuser", "mypass").
Post(formTs.URL + "/profile")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, true, strings.Contains(output.String(), "Alex"))
// post string with more than 512 bytes data
output = bytes.NewBufferString("")
resp, err = New().SetDebug(true).outputLogTo(output).SetDebugBodyLimit(debugBodySizeLimit).R().
SetBody(`{
"first_name": "Alex",
"last_name": "`+strings.Repeat("C", int(debugBodySizeLimit))+`C",
"zip_code": "00001"}`).
SetBasicAuth("myuser", "mypass").
Post(formTs.URL + "/profile")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, true, strings.Contains(output.String(), "REQUEST TOO LARGE"))
// post slice with more than 512 bytes data
output = bytes.NewBufferString("")
resp, err = New().SetDebug(true).outputLogTo(output).SetDebugBodyLimit(debugBodySizeLimit).R().
SetBody([]string{strings.Repeat("C", int(debugBodySizeLimit))}).
SetBasicAuth("myuser", "mypass").
Post(formTs.URL + "/profile")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, true, strings.Contains(output.String(), "REQUEST TOO LARGE"))
}
func TestPostMapTemporaryRedirect(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
resp, err := c.R().SetBody(map[string]string{"username": "testuser", "password": "testpass"}).
Post(ts.URL + "/redirect")
assertNil(t, err)
assertNotNil(t, resp)
assertEqual(t, http.StatusOK, resp.StatusCode())
}
type brokenReadCloser struct{}
func (b brokenReadCloser) Read(p []byte) (n int, err error) {
return 0, errors.New("read error")
}
func (b brokenReadCloser) Close() error {
return nil
}
func TestPostBodyError(t *testing.T) {
ts := createPostServer(t)
defer ts.Close()
c := dc()
resp, err := c.R().SetBody(brokenReadCloser{}).Post(ts.URL + "/redirect")
assertNotNil(t, err)
assertEqual(t, "read error", err.Error())
assertNil(t, resp)
}