diff --git a/client.go b/client.go index e0c3ce58..be9f4377 100644 --- a/client.go +++ b/client.go @@ -95,6 +95,7 @@ type Client struct { notParseResponse bool debugBodySizeLimit int64 logPrefix string + pathParams map[string]string beforeRequest []func(*Client, *Request) error udBeforeRequest []func(*Client, *Request) error preReqHook func(*Client, *Request) error @@ -311,6 +312,7 @@ func (c *Client) R() *Request { client: c, bodyBuf: nil, multipartFiles: []*File{}, + pathParams: make(map[string]string), } return r @@ -719,6 +721,25 @@ func (c *Client) SetLogPrefix(prefix string) *Client { return c } +// SetPathParams method sets multiple URL path key-value pairs at one go in the +// resty client instance. +// resty.SetPathParams(map[string]string{ +// "userId": "sample@sample.com", +// "subAccountId": "100002", +// }) +// +// Result: +// URL - /v1/users/{userId}/{subAccountId}/details +// Composed URL - /v1/users/sample@sample.com/100002/details +// It replace the value of the key while composing request URL. Also it can be +// overridden at request level Path Params options, see `Request.SetPathParams`. +func (c *Client) SetPathParams(params map[string]string) *Client { + for p, v := range params { + c.pathParams[p] = v + } + return c +} + // IsProxySet method returns the true if proxy is set on client otherwise false. func (c *Client) IsProxySet() bool { return c.proxyURL != nil diff --git a/default.go b/default.go index c7a1145f..43ea1982 100644 --- a/default.go +++ b/default.go @@ -251,6 +251,12 @@ func SetDoNotParseResponse(parse bool) *Client { return DefaultClient.SetDoNotParseResponse(parse) } +// SetPathParams method sets the Request path parameter key-value pairs. See +// `Client.SetPathParams` for more information. +func SetPathParams(params map[string]string) *Client { + return DefaultClient.SetPathParams(params) +} + // IsProxySet method returns the true if proxy is set on client otherwise false. // See `Client.IsProxySet` for more information. func IsProxySet() bool { @@ -284,9 +290,12 @@ func createClient(hc *http.Client) *Client { JSONUnmarshal: json.Unmarshal, httpClient: hc, debugBodySizeLimit: math.MaxInt32, - logPrefix: "RESTY ", + pathParams: make(map[string]string), } + // Log Prefix + c.SetLogPrefix("RESTY ") + // Default transport c.SetTransport(&http.Transport{}) diff --git a/middleware.go b/middleware.go index 75470a8e..3fd997e3 100644 --- a/middleware.go +++ b/middleware.go @@ -31,14 +31,13 @@ func parseRequestURL(c *Client, r *Request) error { return err } + // GitHub #103 Path Params + reqURL.Path = composeRequestURL(reqURL.Path, c, r) + // If Request.Url is relative path then added c.HostUrl into // the request URL otherwise Request.Url will be used as-is if !reqURL.IsAbs() { - if !strings.HasPrefix(r.URL, "/") { - r.URL = "/" + r.URL - } - - reqURL, err = url.Parse(c.HostURL + r.URL) + reqURL, err = url.Parse(c.HostURL + reqURL.Path) if err != nil { return err } diff --git a/request.go b/request.go index e13bc7d4..c2ae6713 100644 --- a/request.go +++ b/request.go @@ -354,6 +354,25 @@ func (r *Request) SetDoNotParseResponse(parse bool) *Request { return r } +// SetPathParams method sets multiple URL path key-value pairs at one go in the +// resty current request instance. +// resty.R().SetPathParams(map[string]string{ +// "userId": "sample@sample.com", +// "subAccountId": "100002", +// }) +// +// Result: +// URL - /v1/users/{userId}/{subAccountId}/details +// Composed URL - /v1/users/sample@sample.com/100002/details +// It replace the value of the key while composing request URL. Also you can +// override Path Params value, which was set at client instance level. +func (r *Request) SetPathParams(params map[string]string) *Request { + for p, v := range params { + r.pathParams[p] = v + } + return r +} + // ExpectContentType method allows to provide fallback `Content-Type` for automatic unmarshalling // when `Content-Type` response header is unavailable. func (r *Request) ExpectContentType(contentType string) *Request { diff --git a/request16.go b/request16.go index 325a7d16..2b06766c 100644 --- a/request16.go +++ b/request16.go @@ -45,6 +45,7 @@ type Request struct { multipartFiles []*File notParseResponse bool fallbackContentType string + pathParams map[string]string } func (r *Request) addContextIfAvailable() { diff --git a/request17.go b/request17.go index 3819e84c..387957e3 100644 --- a/request17.go +++ b/request17.go @@ -47,6 +47,7 @@ type Request struct { notParseResponse bool ctx context.Context fallbackContentType string + pathParams map[string]string } // SetContext method sets the context.Context for current Request. It allows diff --git a/request_test.go b/request_test.go new file mode 100644 index 00000000..e4caf48f --- /dev/null +++ b/request_test.go @@ -0,0 +1,1248 @@ +// Copyright (c) 2015-2018 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" + "io" + "io/ioutil" + "net/http" + "net/url" + "os" + "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 := R(). + SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)). + Get(ts.URL + "/") + + 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 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, "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). + SetLogger(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, "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, jsonContentType). + SetHeaders(map[string]string{hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.1", hdrAcceptKey: jsonContentType}) + + 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, jsonContentType). + SetHeaders(map[string]string{hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.7", hdrAcceptKey: jsonContentType}) + + 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, jsonContentType) + + 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() + resp, err := c.R(). + SetHeader(hdrContentTypeKey, jsonContentType). + 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 TestPostJSONStructInvalidLogin(t *testing.T) { + ts := createPostServer(t) + defer ts.Close() + + c := dc() + c.SetDebug(false) + + resp, err := c.R(). + SetHeader(hdrContentTypeKey, jsonContentType). + SetBody(User{Username: "testuser", Password: "testpass1"}). + SetError(AuthError{}). + 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 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()) + + 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) +} + +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 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). + SetLogger(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). + SetLogger(ioutil.Discard) + + resp, err := c.R(). + SetMultiValueFormData(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). + SetLogger(ioutil.Discard). + SetDisableWarn(true) + + 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 cleaupFiles("test-data/upload") + + basePath := getTestDataPath() + + c := dc() + c.SetFormData(map[string]string{"zip_code": "00001", "city": "Los Angeles"}) + + resp, err := c.R(). + SetFile("profile_img", 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 cleaupFiles("test-data/upload") + + basePath := getTestDataPath() + + c := dc() + c.SetFormData(map[string]string{"zip_code": "00001", "city": "Los Angeles"}) + + resp, err := c.R(). + SetFile("profile_img", 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 cleaupFiles("test-data/upload") + + basePath := getTestDataPath() + + resp, err := dclr(). + SetFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M"}). + SetFiles(map[string]string{"profile_img": basePath + "/test-img.png", "notes": 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 cleaupFiles("test-data/upload") + + basePath := getTestDataPath() + profileImgBytes, _ := ioutil.ReadFile(basePath + "/test-img.png") + notesBytes, _ := ioutil.ReadFile(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 cleaupFiles("test-data/upload") + + basePath := getTestDataPath() + + _, err := dclr(). + SetFile("profile_img", 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", basePath+"/test-img.png"). + Delete(ts.URL + "/upload") + + assertEqual(t, "Multipart content is not allowed in HTTP verb [DELETE]", err.Error()) +} + +func TestGetWithCookie(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + + c := dc() + c.SetHostURL(ts.URL) + c.SetCookie(&http.Cookie{ + Name: "go-resty-1", + Value: "This is cookie 1 value", + Path: "/", + Domain: "localhost", + MaxAge: 36000, + HttpOnly: true, + Secure: false, + }) + + 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 TestGetWithCookies(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + + var cookies []*http.Cookie + + cookies = append(cookies, &http.Cookie{ + Name: "go-resty-1", + Value: "This is cookie 1 value", + Path: "/", + Domain: "sample.com", + MaxAge: 36000, + HttpOnly: true, + Secure: false, + }) + + cookies = append(cookies, &http.Cookie{ + Name: "go-resty-2", + Value: "This is cookie 2 value", + Path: "/", + Domain: "sample.com", + MaxAge: 36000, + HttpOnly: true, + Secure: false, + }) + + c := dc() + c.SetHostURL(ts.URL). + SetCookies(cookies) + + 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 TestPutPlainString(t *testing.T) { + ts := createGenServer(t) + defer ts.Close() + + resp, err := 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() + + DefaultClient.OnBeforeRequest(func(c *Client, r *Request) error { + r.SetHeader("X-Custom-Request-Middleware", "OnBeforeRequest middleware") + return nil + }) + DefaultClient.OnBeforeRequest(func(c *Client, r *Request) error { + c.SetContentLength(true) + r.SetHeader("X-ContentLength", "OnBeforeRequest ContentLength set") + return nil + }) + + DefaultClient.SetDebug(true).SetLogger(ioutil.Discard) + + resp, err := R(). + SetHeaders(map[string]string{hdrContentTypeKey: jsonContentType, hdrAcceptKey: jsonContentType}). + 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 := 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 TestNoAutoRedirect(t *testing.T) { + ts := createRedirectServer(t) + defer ts.Close() + + _, err := R().Get(ts.URL + "/redirect-1") + + assertEqual(t, "Get /redirect-2: Auto redirect is disabled", err.Error()) +} + +func TestHTTPAutoRedirectUpTo10(t *testing.T) { + ts := createRedirectServer(t) + defer ts.Close() + + c := dc() + c.SetHTTPMode() + _, err := c.R().Get(ts.URL + "/redirect-1") + + assertEqual(t, "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 TestRawFileUploadByBody(t *testing.T) { + ts := createFormPostServer(t) + defer ts.Close() + + file, _ := os.Open(getTestDataPath() + "/test-img.png") + fileBytes, _ := ioutil.ReadAll(file) + + 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.getTransport() + + assertNil(t, err) + + assertEqual(t, false, c.IsProxySet()) + assertNil(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, false, c.IsProxySet()) + assertNil(t, transport.Proxy) + + SetProxy("http://sampleproxy:8888") + assertEqual(t, true, IsProxySet()) + RemoveProxy() + assertNil(t, DefaultClient.proxyURL) + assertNil(t, transport.Proxy) +} + +func TestGetClient(t *testing.T) { + client := GetClient() + custom := New() + customClient := custom.GetClient() + + assertNotNil(t, client) + assertNotNil(t, customClient) + + assertNotEqual(t, client, http.DefaultClient) + assertNotEqual(t, customClient, http.DefaultClient) + assertNotEqual(t, client, customClient) + + assertEqual(t, DefaultClient.httpClient, client) +} + +func TestIncorrectURL(t *testing.T) { + _, err := 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")) + + c := dc() + 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")) +} + +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.SetMultiValueQueryParams(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 TestOutputFileWithBaseDirAndRelativePath(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + defer cleaupFiles("test-data/dir-sample") + + DefaultClient = dc() + SetRedirectPolicy(FlexibleRedirectPolicy(10)) + SetOutputDirectory(getTestDataPath() + "/dir-sample") + SetDebug(true) + + resp, err := R(). + SetOutput("go-resty/test-img-success.png"). + Get(ts.URL + "/my-image.png") + + assertError(t, err) + assertEqual(t, true, resp.Size() != 0) +} + +func TestOutputFileWithBaseDirError(t *testing.T) { + c := dc().SetRedirectPolicy(FlexibleRedirectPolicy(10)). + SetOutputDirectory(getTestDataPath() + `/go-resty\0`) + + _ = c +} + +func TestOutputPathDirNotExists(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + defer cleaupFiles("test-data/not-exists-dir") + + DefaultClient = dc() + SetRedirectPolicy(FlexibleRedirectPolicy(10)) + SetOutputDirectory(getTestDataPath() + "/not-exists-dir") + + resp, err := R(). + SetOutput("test-img-success.png"). + Get(ts.URL + "/my-image.png") + + assertError(t, err) + assertEqual(t, true, resp.Size() != 0) +} + +func TestOutputFileAbsPath(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + defer cleaupFiles("test-data/go-resty") + + _, err := dcr(). + SetOutput(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 := R(). + SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)) + + if r.isContextCancelledIfAvailable() { + t.Error("isContextCancelledIfAvailable != false for vanilla R()") + } + r.addContextIfAvailable() + + 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 := R(). + SetSRV(&SRVRecord{"nonexistantservice", "sampledomain"}). + Get("/") + + assertNotNil(t, err) + assertEqual(t, true, strings.Contains(err.Error(), "no such host")) +} + +func TestDeprecatedCodeCovergae(t *testing.T) { + var user1 User + err := Unmarshal("application/json", + []byte(`{"username":"testuser", "password":"testpass"}`), &user1) + assertError(t, err) + assertEqual(t, "testuser", user1.Username) + assertEqual(t, "testpass", user1.Password) + + var user2 User + err = Unmarshal("application/xml", + []byte(`testusertestpass`), + &user2) + assertError(t, err) + assertEqual(t, "testuser", user1.Username) + assertEqual(t, "testpass", user1.Password) +} + +func TestRequestDoNotParseResponse(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + + resp, err := dc().R(). + SetDoNotParseResponse(true). + 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()) + + // just set test part + SetDoNotParseResponse(true) + assertEqual(t, true, DefaultClient.notParseResponse) + SetDoNotParseResponse(false) +} + +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 TestGetPathParams(t *testing.T) { + ts := createGetServer(t) + defer ts.Close() + + c := dc() + c.SetHostURL(ts.URL). + SetPathParams(map[string]string{ + "userId": "sample@sample.com", + }) + + resp, err := c.R().SetPathParams(map[string]string{ + "subAccountId": "100002", + }). + Get("v1/users/{userId}/{subAccountId}/details") + + assertError(t, err) + assertEqual(t, http.StatusOK, resp.StatusCode()) + assertEqual(t, "TestPathParams: text response", resp.String()) + + logResponse(t, resp) + + SetPathParams(map[string]string{ + "userId": "sample@sample.com", + }) +} diff --git a/resty_test.go b/resty_test.go index ceaf610c..0372681a 100644 --- a/resty_test.go +++ b/resty_test.go @@ -5,8 +5,6 @@ package resty import ( - "bytes" - "crypto/tls" "encoding/base64" "encoding/json" "encoding/xml" @@ -15,7 +13,6 @@ import ( "io/ioutil" "net/http" "net/http/httptest" - "net/url" "os" "path/filepath" "reflect" @@ -26,1209 +23,6 @@ import ( "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 := R(). - SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)). - Get(ts.URL + "/") - - 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 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, "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). - SetLogger(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, "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, jsonContentType). - SetHeaders(map[string]string{hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.1", hdrAcceptKey: jsonContentType}) - - 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, jsonContentType). - SetHeaders(map[string]string{hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.7", hdrAcceptKey: jsonContentType}) - - 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, jsonContentType) - - 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() - resp, err := c.R(). - SetHeader(hdrContentTypeKey, jsonContentType). - 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 TestPostJSONStructInvalidLogin(t *testing.T) { - ts := createPostServer(t) - defer ts.Close() - - c := dc() - c.SetDebug(false) - - resp, err := c.R(). - SetHeader(hdrContentTypeKey, jsonContentType). - SetBody(User{Username: "testuser", Password: "testpass1"}). - SetError(AuthError{}). - 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 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()) - - 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) -} - -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 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). - SetLogger(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). - SetLogger(ioutil.Discard) - - resp, err := c.R(). - SetMultiValueFormData(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). - SetLogger(ioutil.Discard). - SetDisableWarn(true) - - 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 cleaupFiles("test-data/upload") - - basePath := getTestDataPath() - - c := dc() - c.SetFormData(map[string]string{"zip_code": "00001", "city": "Los Angeles"}) - - resp, err := c.R(). - SetFile("profile_img", 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 cleaupFiles("test-data/upload") - - basePath := getTestDataPath() - - c := dc() - c.SetFormData(map[string]string{"zip_code": "00001", "city": "Los Angeles"}) - - resp, err := c.R(). - SetFile("profile_img", 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 cleaupFiles("test-data/upload") - - basePath := getTestDataPath() - - resp, err := dclr(). - SetFormData(map[string]string{"first_name": "Jeevanandam", "last_name": "M"}). - SetFiles(map[string]string{"profile_img": basePath + "/test-img.png", "notes": 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 cleaupFiles("test-data/upload") - - basePath := getTestDataPath() - profileImgBytes, _ := ioutil.ReadFile(basePath + "/test-img.png") - notesBytes, _ := ioutil.ReadFile(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 cleaupFiles("test-data/upload") - - basePath := getTestDataPath() - - _, err := dclr(). - SetFile("profile_img", 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", basePath+"/test-img.png"). - Delete(ts.URL + "/upload") - - assertEqual(t, "Multipart content is not allowed in HTTP verb [DELETE]", err.Error()) -} - -func TestGetWithCookie(t *testing.T) { - ts := createGetServer(t) - defer ts.Close() - - c := dc() - c.SetHostURL(ts.URL) - c.SetCookie(&http.Cookie{ - Name: "go-resty-1", - Value: "This is cookie 1 value", - Path: "/", - Domain: "localhost", - MaxAge: 36000, - HttpOnly: true, - Secure: false, - }) - - 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 TestGetWithCookies(t *testing.T) { - ts := createGetServer(t) - defer ts.Close() - - var cookies []*http.Cookie - - cookies = append(cookies, &http.Cookie{ - Name: "go-resty-1", - Value: "This is cookie 1 value", - Path: "/", - Domain: "sample.com", - MaxAge: 36000, - HttpOnly: true, - Secure: false, - }) - - cookies = append(cookies, &http.Cookie{ - Name: "go-resty-2", - Value: "This is cookie 2 value", - Path: "/", - Domain: "sample.com", - MaxAge: 36000, - HttpOnly: true, - Secure: false, - }) - - c := dc() - c.SetHostURL(ts.URL). - SetCookies(cookies) - - 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 TestPutPlainString(t *testing.T) { - ts := createGenServer(t) - defer ts.Close() - - resp, err := 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() - - DefaultClient.OnBeforeRequest(func(c *Client, r *Request) error { - r.SetHeader("X-Custom-Request-Middleware", "OnBeforeRequest middleware") - return nil - }) - DefaultClient.OnBeforeRequest(func(c *Client, r *Request) error { - c.SetContentLength(true) - r.SetHeader("X-ContentLength", "OnBeforeRequest ContentLength set") - return nil - }) - - DefaultClient.SetDebug(true).SetLogger(ioutil.Discard) - - resp, err := R(). - SetHeaders(map[string]string{hdrContentTypeKey: jsonContentType, hdrAcceptKey: jsonContentType}). - 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 := 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 TestNoAutoRedirect(t *testing.T) { - ts := createRedirectServer(t) - defer ts.Close() - - _, err := R().Get(ts.URL + "/redirect-1") - - assertEqual(t, "Get /redirect-2: Auto redirect is disabled", err.Error()) -} - -func TestHTTPAutoRedirectUpTo10(t *testing.T) { - ts := createRedirectServer(t) - defer ts.Close() - - c := dc() - c.SetHTTPMode() - _, err := c.R().Get(ts.URL + "/redirect-1") - - assertEqual(t, "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 TestRawFileUploadByBody(t *testing.T) { - ts := createFormPostServer(t) - defer ts.Close() - - file, _ := os.Open(getTestDataPath() + "/test-img.png") - fileBytes, _ := ioutil.ReadAll(file) - - 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.getTransport() - - assertNil(t, err) - - assertEqual(t, false, c.IsProxySet()) - assertNil(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, false, c.IsProxySet()) - assertNil(t, transport.Proxy) - - SetProxy("http://sampleproxy:8888") - assertEqual(t, true, IsProxySet()) - RemoveProxy() - assertNil(t, DefaultClient.proxyURL) - assertNil(t, transport.Proxy) -} - -func TestGetClient(t *testing.T) { - client := GetClient() - custom := New() - customClient := custom.GetClient() - - assertNotNil(t, client) - assertNotNil(t, customClient) - - assertNotEqual(t, client, http.DefaultClient) - assertNotEqual(t, customClient, http.DefaultClient) - assertNotEqual(t, client, customClient) - - assertEqual(t, DefaultClient.httpClient, client) -} - -func TestIncorrectURL(t *testing.T) { - _, err := 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")) - - c := dc() - 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")) -} - -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.SetMultiValueQueryParams(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 TestOutputFileWithBaseDirAndRelativePath(t *testing.T) { - ts := createGetServer(t) - defer ts.Close() - defer cleaupFiles("test-data/dir-sample") - - DefaultClient = dc() - SetRedirectPolicy(FlexibleRedirectPolicy(10)) - SetOutputDirectory(getTestDataPath() + "/dir-sample") - SetDebug(true) - - resp, err := R(). - SetOutput("go-resty/test-img-success.png"). - Get(ts.URL + "/my-image.png") - - assertError(t, err) - assertEqual(t, true, resp.Size() != 0) -} - -func TestOutputFileWithBaseDirError(t *testing.T) { - c := dc().SetRedirectPolicy(FlexibleRedirectPolicy(10)). - SetOutputDirectory(getTestDataPath() + `/go-resty\0`) - - _ = c -} - -func TestOutputPathDirNotExists(t *testing.T) { - ts := createGetServer(t) - defer ts.Close() - defer cleaupFiles("test-data/not-exists-dir") - - DefaultClient = dc() - SetRedirectPolicy(FlexibleRedirectPolicy(10)) - SetOutputDirectory(getTestDataPath() + "/not-exists-dir") - - resp, err := R(). - SetOutput("test-img-success.png"). - Get(ts.URL + "/my-image.png") - - assertError(t, err) - assertEqual(t, true, resp.Size() != 0) -} - -func TestOutputFileAbsPath(t *testing.T) { - ts := createGetServer(t) - defer ts.Close() - defer cleaupFiles("test-data/go-resty") - - _, err := dcr(). - SetOutput(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 := R(). - SetQueryParam("request_no", strconv.FormatInt(time.Now().Unix(), 10)) - - if r.isContextCancelledIfAvailable() { - t.Error("isContextCancelledIfAvailable != false for vanilla R()") - } - r.addContextIfAvailable() - - 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 := R(). - SetSRV(&SRVRecord{"nonexistantservice", "sampledomain"}). - Get("/") - - assertNotNil(t, err) - assertEqual(t, true, strings.Contains(err.Error(), "no such host")) -} - -func TestDeprecatedCodeCovergae(t *testing.T) { - var user1 User - err := Unmarshal("application/json", - []byte(`{"username":"testuser", "password":"testpass"}`), &user1) - assertError(t, err) - assertEqual(t, "testuser", user1.Username) - assertEqual(t, "testpass", user1.Password) - - var user2 User - err = Unmarshal("application/xml", - []byte(`testusertestpass`), - &user2) - assertError(t, err) - assertEqual(t, "testuser", user1.Username) - assertEqual(t, "testpass", user1.Password) -} - -func TestRequestDoNotParseResponse(t *testing.T) { - ts := createGetServer(t) - defer ts.Close() - - resp, err := dc().R(). - SetDoNotParseResponse(true). - 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()) - - // just set test part - SetDoNotParseResponse(true) - assertEqual(t, true, DefaultClient.notParseResponse) - SetDoNotParseResponse(false) -} - -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("", "")) -} - //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ // Testing Unexported methods //___________________________________ @@ -1304,6 +98,8 @@ func createGetServer(t *testing.T) *httptest.Server { t.Errorf("Error: could not read get body: %s", err.Error()) } _, _ = w.Write(body) + case "/v1/users/sample@sample.com/100002/details": + _, _ = w.Write([]byte("TestPathParams: text response")) } } }) diff --git a/util.go b/util.go index d939b471..edf81d2b 100644 --- a/util.go +++ b/util.go @@ -15,6 +15,7 @@ import ( "net/http" "net/textproto" "os" + "path" "path/filepath" "reflect" "runtime" @@ -204,3 +205,29 @@ func releaseBuffer(buf *bytes.Buffer) { bufPool.Put(buf) } } + +func composeRequestURL(pathURL string, c *Client, r *Request) string { + if !strings.HasPrefix(pathURL, "/") { + pathURL = "/" + pathURL + } + + reqURL := "/" + for _, segment := range strings.Split(pathURL, "/") { + if strings.HasPrefix(segment, "{") && strings.HasSuffix(segment, "}") { + key := segment[1 : len(segment)-1] + if val, found := r.pathParams[key]; found { + reqURL = path.Join(reqURL, val) + continue + } + + if val, found := c.pathParams[key]; found { + reqURL = path.Join(reqURL, val) + continue + } + } + + reqURL = path.Join(reqURL, segment) + } + + return reqURL +}