// Copyright (c) 2015-2017 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/base64" "encoding/json" "encoding/xml" "fmt" "io" "io/ioutil" "net/http" "net/http/httptest" "net/url" "os" "path/filepath" "reflect" "strconv" "strings" "sync/atomic" "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(`<?xml version="1.0" encoding="UTF-8"?><User><Username>testuser</Username><Password>testpass</Password></User>`). 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(`<?xml version="1.0" encoding="UTF-8"?><User><Username>testuser</Username>testpass</Password></User>`). Post(ts.URL + "/login") assertError(t, err) assertEqual(t, http.StatusBadRequest, resp.StatusCode()) assertEqual(t, `<?xml version="1.0" encoding="UTF-8"?><AuthError><Id>bad_request</Id><Message>Unable to read user info</Message></AuthError>`, 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(`<?xml version="1.0" encoding="UTF-8"?><User><Username>testuser</Username><Password>testpass</Password></User>`)). 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 <Message> closed by </AuthSuccess>", 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 version="1.0" encoding="UTF-8"?><Request>XML Content sending to server</Request>`). Put(ts.URL + "/xml") assertError(t, err) assertEqual(t, http.StatusOK, resp.StatusCode()) assertEqual(t, `<?xml version="1.0" encoding="UTF-8"?><Response>XML response</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 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("/") assertError(t, err) assertNotNil(t, resp) if resp != nil { 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(`<?xml version="1.0" encoding="UTF-8"?><User><Username>testuser</Username><Password>testpass</Password></User>`), &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 //___________________________________ func getTestDataPath() string { pwd, _ := os.Getwd() return pwd + "/test-data" } func createGetServer(t *testing.T) *httptest.Server { var attempt int32 var sequence int32 var lastRequest time.Time ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { t.Logf("Method: %v", r.Method) t.Logf("Path: %v", r.URL.Path) if r.Method == MethodGet { if r.URL.Path == "/" { _, _ = w.Write([]byte("TestGet: text response")) } else if r.URL.Path == "/mypage" { w.WriteHeader(http.StatusBadRequest) } else if r.URL.Path == "/mypage2" { _, _ = w.Write([]byte("TestGet: text response from mypage2")) } else if r.URL.Path == "/set-retrycount-test" { attp := atomic.AddInt32(&attempt, 1) if attp <= 3 { time.Sleep(time.Second * 6) } _, _ = w.Write([]byte("TestClientRetry page")) } else if r.URL.Path == "/set-retrywaittime-test" { // Returns time.Duration since last request here // or 0 for the very first request if atomic.LoadInt32(&attempt) == 0 { lastRequest = time.Now() _, _ = fmt.Fprint(w, "0") } else { now := time.Now() sinceLastRequest := now.Sub(lastRequest) lastRequest = now _, _ = fmt.Fprintf(w, "%d", uint64(sinceLastRequest)) } atomic.AddInt32(&attempt, 1) } else if r.URL.Path == "/set-timeout-test-with-sequence" { seq := atomic.AddInt32(&sequence, 1) time.Sleep(time.Second * 2) _, _ = fmt.Fprintf(w, "%d", seq) } else if r.URL.Path == "/set-timeout-test" { time.Sleep(time.Second * 6) _, _ = w.Write([]byte("TestClientTimeout page")) } else if r.URL.Path == "/my-image.png" { fileBytes, _ := ioutil.ReadFile(getTestDataPath() + "/test-img.png") w.Header().Set("Content-Type", "image/png") w.Header().Set("Content-Length", strconv.Itoa(len(fileBytes))) _, _ = w.Write(fileBytes) } else if r.URL.Path == "/get-method-payload-test" { body, err := ioutil.ReadAll(r.Body) if err != nil { t.Errorf("Error: could not read get body: %s", err.Error()) } _, _ = w.Write(body) } } }) return ts } func handleLoginEndpoint(t *testing.T, w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/login" { user := &User{} // JSON if IsJSONType(r.Header.Get(hdrContentTypeKey)) { jd := json.NewDecoder(r.Body) err := jd.Decode(user) w.Header().Set(hdrContentTypeKey, jsonContentType) if err != nil { t.Logf("Error: %#v", err) w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to read user info" }`)) return } if user.Username == "testuser" && user.Password == "testpass" { _, _ = w.Write([]byte(`{ "id": "success", "message": "login successful" }`)) } else if user.Username == "testuser" && user.Password == "invalidjson" { _, _ = w.Write([]byte(`{ "id": "success", "message": "login successful", }`)) } else { w.Header().Set("Www-Authenticate", "Protected Realm") w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`{ "id": "unauthorized", "message": "Invalid credentials" }`)) } return } // XML if IsXMLType(r.Header.Get(hdrContentTypeKey)) { xd := xml.NewDecoder(r.Body) err := xd.Decode(user) w.Header().Set(hdrContentTypeKey, "application/xml") if err != nil { t.Logf("Error: %v", err) w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`)) _, _ = w.Write([]byte(`<AuthError><Id>bad_request</Id><Message>Unable to read user info</Message></AuthError>`)) return } if user.Username == "testuser" && user.Password == "testpass" { _, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`)) _, _ = w.Write([]byte(`<AuthSuccess><Id>success</Id><Message>login successful</Message></AuthSuccess>`)) } else if user.Username == "testuser" && user.Password == "invalidxml" { _, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`)) _, _ = w.Write([]byte(`<AuthSuccess><Id>success</Id><Message>login successful</AuthSuccess>`)) } else { w.Header().Set("Www-Authenticate", "Protected Realm") w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`)) _, _ = w.Write([]byte(`<AuthError><Id>unauthorized</Id><Message>Invalid credentials</Message></AuthError>`)) } return } } } func handleUsersEndpoint(t *testing.T, w http.ResponseWriter, r *http.Request) { if r.URL.Path == "/users" { // JSON if IsJSONType(r.Header.Get(hdrContentTypeKey)) { var users []ExampleUser jd := json.NewDecoder(r.Body) err := jd.Decode(&users) w.Header().Set(hdrContentTypeKey, jsonContentType) if err != nil { t.Logf("Error: %v", err) w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to read user info" }`)) return } // logic check, since we are excepting to reach 3 records if len(users) != 3 { t.Log("Error: Excepted count of 3 records") w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Expected record count doesn't match" }`)) return } eu := users[2] if eu.FirstName == "firstname3" && eu.ZipCode == "10003" { w.WriteHeader(http.StatusAccepted) _, _ = w.Write([]byte(`{ "message": "Accepted" }`)) } return } } } func createPostServer(t *testing.T) *httptest.Server { ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { t.Logf("Method: %v", r.Method) t.Logf("Path: %v", r.URL.Path) t.Logf("RawQuery: %v", r.URL.RawQuery) t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey)) if r.Method == MethodPost { handleLoginEndpoint(t, w, r) handleUsersEndpoint(t, w, r) if r.URL.Path == "/usersmap" { // JSON if IsJSONType(r.Header.Get(hdrContentTypeKey)) { if r.URL.Query().Get("status") == "500" { body, err := ioutil.ReadAll(r.Body) if err != nil { t.Errorf("Error: could not read post body: %s", err.Error()) } t.Logf("Got query param: status=500 so we're returning the post body as response and a 500 status code. body: %s", string(body)) w.Header().Set(hdrContentTypeKey, jsonContentType) w.WriteHeader(http.StatusInternalServerError) _, _ = w.Write(body) return } var users []map[string]interface{} jd := json.NewDecoder(r.Body) err := jd.Decode(&users) w.Header().Set(hdrContentTypeKey, jsonContentType) if err != nil { t.Logf("Error: %v", err) w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to read user info" }`)) return } // logic check, since we are excepting to reach 1 map records if len(users) != 1 { t.Log("Error: Excepted count of 1 map records") w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Expected record count doesn't match" }`)) return } w.WriteHeader(http.StatusAccepted) _, _ = w.Write([]byte(`{ "message": "Accepted" }`)) return } } } }) return ts } func createFormPostServer(t *testing.T) *httptest.Server { ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { t.Logf("Method: %v", r.Method) t.Logf("Path: %v", r.URL.Path) t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey)) if r.Method == MethodPost { _ = r.ParseMultipartForm(10e6) if r.URL.Path == "/profile" { t.Logf("FirstName: %v", r.FormValue("first_name")) t.Logf("LastName: %v", r.FormValue("last_name")) t.Logf("City: %v", r.FormValue("city")) t.Logf("Zip Code: %v", r.FormValue("zip_code")) _, _ = w.Write([]byte("Success")) return } else if r.URL.Path == "/search" { formEncodedData := r.Form.Encode() t.Logf("Recevied Form Encoded values: %v", formEncodedData) assertEqual(t, true, strings.Contains(formEncodedData, "search_criteria=pencil")) assertEqual(t, true, strings.Contains(formEncodedData, "search_criteria=glass")) _, _ = w.Write([]byte("Success")) return } else if r.URL.Path == "/upload" { t.Logf("FirstName: %v", r.FormValue("first_name")) t.Logf("LastName: %v", r.FormValue("last_name")) targetPath := getTestDataPath() + "/upload" _ = os.MkdirAll(targetPath, 0700) for _, fhdrs := range r.MultipartForm.File { for _, hdr := range fhdrs { t.Logf("Name: %v", hdr.Filename) t.Logf("Header: %v", hdr.Header) dotPos := strings.LastIndex(hdr.Filename, ".") fname := fmt.Sprintf("%s-%v%s", hdr.Filename[:dotPos], time.Now().Unix(), hdr.Filename[dotPos:]) t.Logf("Write name: %v", fname) infile, _ := hdr.Open() f, err := os.OpenFile(targetPath+"/"+fname, os.O_WRONLY|os.O_CREATE, 0666) if err != nil { t.Logf("Error: %v", err) return } defer func() { _ = f.Close() }() _, _ = io.Copy(f, infile) _, _ = w.Write([]byte(fmt.Sprintf("File: %v, uploaded as: %v\n", hdr.Filename, fname))) } } return } } }) return ts } func createAuthServer(t *testing.T) *httptest.Server { ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { t.Logf("Method: %v", r.Method) t.Logf("Path: %v", r.URL.Path) t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey)) if r.Method == MethodGet { if r.URL.Path == "/profile" { // 004DDB79-6801-4587-B976-F093E6AC44FF auth := r.Header.Get("Authorization") t.Logf("Bearer Auth: %v", auth) w.Header().Set(hdrContentTypeKey, jsonContentType) if !strings.HasPrefix(auth, "Bearer ") { w.Header().Set("Www-Authenticate", "Protected Realm") w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`{ "id": "unauthorized", "message": "Invalid credentials" }`)) return } if auth[7:] == "004DDB79-6801-4587-B976-F093E6AC44FF" || auth[7:] == "004DDB79-6801-4587-B976-F093E6AC44FF-Request" { _, _ = w.Write([]byte(`{ "id": "success", "message": "login successful" }`)) } } return } if r.Method == MethodPost { if r.URL.Path == "/login" { auth := r.Header.Get("Authorization") t.Logf("Basic Auth: %v", auth) w.Header().Set(hdrContentTypeKey, jsonContentType) password, err := base64.StdEncoding.DecodeString(auth[6:]) if err != nil || string(password) != "myuser:basicauth" { w.Header().Set("Www-Authenticate", "Protected Realm") w.WriteHeader(http.StatusUnauthorized) _, _ = w.Write([]byte(`{ "id": "unauthorized", "message": "Invalid credentials" }`)) return } _, _ = w.Write([]byte(`{ "id": "success", "message": "login successful" }`)) } return } })) return ts } func createGenServer(t *testing.T) *httptest.Server { ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { t.Logf("Method: %v", r.Method) t.Logf("Path: %v", r.URL.Path) if r.Method == MethodGet { if r.URL.Path == "/json-no-set" { // Set empty header value for testing, since Go server sets to // text/plain; charset=utf-8 w.Header().Set(hdrContentTypeKey, "") _, _ = w.Write([]byte(`{"response":"json response no content type set"}`)) } return } if r.Method == MethodPut { if r.URL.Path == "/plaintext" { _, _ = w.Write([]byte("TestPut: plain text response")) } else if r.URL.Path == "/json" { w.Header().Set(hdrContentTypeKey, jsonContentType) _, _ = w.Write([]byte(`{"response":"json response"}`)) } else if r.URL.Path == "/xml" { w.Header().Set(hdrContentTypeKey, "application/xml") _, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?><Response>XML response</Response>`)) } return } if r.Method == MethodOptions && r.URL.Path == "/options" { w.Header().Set("Access-Control-Allow-Origin", "localhost") w.Header().Set("Access-Control-Allow-Methods", "PUT, PATCH") w.Header().Set("Access-Control-Expose-Headers", "x-go-resty-id") w.WriteHeader(http.StatusOK) return } if r.Method == MethodPatch && r.URL.Path == "/patch" { w.WriteHeader(http.StatusOK) return } }) return ts } func createRedirectServer(t *testing.T) *httptest.Server { ts := createTestServer(func(w http.ResponseWriter, r *http.Request) { t.Logf("Method: %v", r.Method) t.Logf("Path: %v", r.URL.Path) if r.Method == MethodGet { if strings.HasPrefix(r.URL.Path, "/redirect-host-check-") { cntStr := strings.SplitAfter(r.URL.Path, "-")[3] cnt, _ := strconv.Atoi(cntStr) if cnt != 7 { // Testing hard stop via logical if cnt >= 5 { http.Redirect(w, r, "http://httpbin.org/get", http.StatusTemporaryRedirect) } else { http.Redirect(w, r, fmt.Sprintf("/redirect-host-check-%d", (cnt+1)), http.StatusTemporaryRedirect) } } } else if strings.HasPrefix(r.URL.Path, "/redirect-") { cntStr := strings.SplitAfter(r.URL.Path, "-")[1] cnt, _ := strconv.Atoi(cntStr) http.Redirect(w, r, fmt.Sprintf("/redirect-%d", (cnt+1)), http.StatusTemporaryRedirect) } } }) return ts } func createTestServer(fn func(w http.ResponseWriter, r *http.Request)) *httptest.Server { return httptest.NewServer(http.HandlerFunc(fn)) } func dc() *Client { DefaultClient = New() return DefaultClient } func dcr() *Request { return dc().R() } func dclr() *Request { c := dc() c.SetDebug(true) c.SetLogger(ioutil.Discard) return c.R() } func assertNil(t *testing.T, v interface{}) { if !isNil(v) { t.Errorf("[%v] was expected to be nil", v) } } func assertNotNil(t *testing.T, v interface{}) { if isNil(v) { t.Errorf("[%v] was expected to be non-nil", v) } } func assertError(t *testing.T, err error) { if err != nil { t.Errorf("Error occurred [%v]", err) } } func assertEqual(t *testing.T, e, g interface{}) (r bool) { if !equal(e, g) { t.Errorf("Expected [%v], got [%v]", e, g) } return } func assertNotEqual(t *testing.T, e, g interface{}) (r bool) { if equal(e, g) { t.Errorf("Expected [%v], got [%v]", e, g) } else { r = true } return } func equal(expected, got interface{}) bool { return reflect.DeepEqual(expected, got) } func isNil(v interface{}) bool { if v == nil { return true } rv := reflect.ValueOf(v) kind := rv.Kind() if kind >= reflect.Chan && kind <= reflect.Slice && rv.IsNil() { return true } return false } func logResponse(t *testing.T, resp *Response) { t.Logf("Response Status: %v", resp.Status()) t.Logf("Response Time: %v", resp.Time()) t.Logf("Response Headers: %v", resp.Header()) t.Logf("Response Cookies: %v", resp.Cookies()) t.Logf("Response Body: %v", resp) } func cleaupFiles(files ...string) { pwd, _ := os.Getwd() for _, f := range files { _ = os.RemoveAll(filepath.Join(pwd, f)) } }