...

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

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

     1  // Copyright (c) 2015-2021 Jeevanandam M (jeeva@myjeeva.com), All rights reserved.
     2  // resty source code and usage is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package resty
     6  
     7  import (
     8  	"compress/gzip"
     9  	"encoding/base64"
    10  	"encoding/json"
    11  	"encoding/xml"
    12  	"fmt"
    13  	"io"
    14  	"io/ioutil"
    15  	"net/http"
    16  	"net/http/httptest"
    17  	"os"
    18  	"path/filepath"
    19  	"reflect"
    20  	"strconv"
    21  	"strings"
    22  	"sync/atomic"
    23  	"testing"
    24  	"time"
    25  )
    26  
    27  //‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
    28  // Testing Unexported methods
    29  //___________________________________
    30  
    31  func getTestDataPath() string {
    32  	pwd, _ := os.Getwd()
    33  	return filepath.Join(pwd, ".testdata")
    34  }
    35  
    36  func createGetServer(t *testing.T) *httptest.Server {
    37  	var attempt int32
    38  	var sequence int32
    39  	var lastRequest time.Time
    40  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
    41  		t.Logf("Method: %v", r.Method)
    42  		t.Logf("Path: %v", r.URL.Path)
    43  
    44  		if r.Method == MethodGet {
    45  			switch r.URL.Path {
    46  			case "/":
    47  				_, _ = w.Write([]byte("TestGet: text response"))
    48  			case "/no-content":
    49  				_, _ = w.Write([]byte(""))
    50  			case "/json":
    51  				w.Header().Set("Content-Type", "application/json")
    52  				_, _ = w.Write([]byte(`{"TestGet": "JSON response"}`))
    53  			case "/json-invalid":
    54  				w.Header().Set("Content-Type", "application/json")
    55  				_, _ = w.Write([]byte("TestGet: Invalid JSON"))
    56  			case "/long-text":
    57  				_, _ = w.Write([]byte("TestGet: text response with size > 30"))
    58  			case "/long-json":
    59  				w.Header().Set("Content-Type", "application/json")
    60  				_, _ = w.Write([]byte(`{"TestGet": "JSON response with size > 30"}`))
    61  			case "/mypage":
    62  				w.WriteHeader(http.StatusBadRequest)
    63  			case "/mypage2":
    64  				_, _ = w.Write([]byte("TestGet: text response from mypage2"))
    65  			case "/set-retrycount-test":
    66  				attp := atomic.AddInt32(&attempt, 1)
    67  				if attp <= 4 {
    68  					time.Sleep(time.Second * 6)
    69  				}
    70  				_, _ = w.Write([]byte("TestClientRetry page"))
    71  			case "/set-retrywaittime-test":
    72  				// Returns time.Duration since last request here
    73  				// or 0 for the very first request
    74  				if atomic.LoadInt32(&attempt) == 0 {
    75  					lastRequest = time.Now()
    76  					_, _ = fmt.Fprint(w, "0")
    77  				} else {
    78  					now := time.Now()
    79  					sinceLastRequest := now.Sub(lastRequest)
    80  					lastRequest = now
    81  					_, _ = fmt.Fprintf(w, "%d", uint64(sinceLastRequest))
    82  				}
    83  				atomic.AddInt32(&attempt, 1)
    84  
    85  			case "/set-retry-error-recover":
    86  				w.Header().Set(hdrContentTypeKey, "application/json; charset=utf-8")
    87  				if atomic.LoadInt32(&attempt) == 0 {
    88  					w.WriteHeader(http.StatusTooManyRequests)
    89  					_, _ = w.Write([]byte(`{ "message": "too many" }`))
    90  				} else {
    91  					_, _ = w.Write([]byte(`{ "message": "hello" }`))
    92  				}
    93  				atomic.AddInt32(&attempt, 1)
    94  			case "/set-timeout-test-with-sequence":
    95  				seq := atomic.AddInt32(&sequence, 1)
    96  				time.Sleep(time.Second * 2)
    97  				_, _ = fmt.Fprintf(w, "%d", seq)
    98  			case "/set-timeout-test":
    99  				time.Sleep(time.Second * 6)
   100  				_, _ = w.Write([]byte("TestClientTimeout page"))
   101  			case "/my-image.png":
   102  				fileBytes, _ := ioutil.ReadFile(filepath.Join(getTestDataPath(), "test-img.png"))
   103  				w.Header().Set("Content-Type", "image/png")
   104  				w.Header().Set("Content-Length", strconv.Itoa(len(fileBytes)))
   105  				_, _ = w.Write(fileBytes)
   106  			case "/get-method-payload-test":
   107  				body, err := ioutil.ReadAll(r.Body)
   108  				if err != nil {
   109  					t.Errorf("Error: could not read get body: %s", err.Error())
   110  				}
   111  				_, _ = w.Write(body)
   112  			case "/host-header":
   113  				_, _ = w.Write([]byte(r.Host))
   114  			}
   115  
   116  			switch {
   117  			case strings.HasPrefix(r.URL.Path, "/v1/users/sample@sample.com/100002"):
   118  				if strings.HasSuffix(r.URL.Path, "details") {
   119  					_, _ = w.Write([]byte("TestGetPathParams: text response: " + r.URL.String()))
   120  				} else {
   121  					_, _ = w.Write([]byte("TestPathParamURLInput: text response: " + r.URL.String()))
   122  				}
   123  			}
   124  
   125  		}
   126  	})
   127  
   128  	return ts
   129  }
   130  
   131  func handleLoginEndpoint(t *testing.T, w http.ResponseWriter, r *http.Request) {
   132  	if r.URL.Path == "/login" {
   133  		user := &User{}
   134  
   135  		// JSON
   136  		if IsJSONType(r.Header.Get(hdrContentTypeKey)) {
   137  			jd := json.NewDecoder(r.Body)
   138  			err := jd.Decode(user)
   139  			if r.URL.Query().Get("ct") == "problem" {
   140  				w.Header().Set(hdrContentTypeKey, "application/problem+json; charset=utf-8")
   141  			} else if r.URL.Query().Get("ct") == "rpc" {
   142  				w.Header().Set(hdrContentTypeKey, "application/json-rpc")
   143  			} else {
   144  				w.Header().Set(hdrContentTypeKey, "application/json")
   145  			}
   146  
   147  			if err != nil {
   148  				t.Logf("Error: %#v", err)
   149  				w.WriteHeader(http.StatusBadRequest)
   150  				_, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to read user info" }`))
   151  				return
   152  			}
   153  
   154  			if user.Username == "testuser" && user.Password == "testpass" {
   155  				_, _ = w.Write([]byte(`{ "id": "success", "message": "login successful" }`))
   156  			} else if user.Username == "testuser" && user.Password == "invalidjson" {
   157  				_, _ = w.Write([]byte(`{ "id": "success", "message": "login successful", }`))
   158  			} else {
   159  				w.WriteHeader(http.StatusUnauthorized)
   160  				_, _ = w.Write([]byte(`{ "id": "unauthorized", "message": "Invalid credentials" }`))
   161  			}
   162  
   163  			return
   164  		}
   165  
   166  		// XML
   167  		if IsXMLType(r.Header.Get(hdrContentTypeKey)) {
   168  			xd := xml.NewDecoder(r.Body)
   169  			err := xd.Decode(user)
   170  
   171  			w.Header().Set(hdrContentTypeKey, "application/xml")
   172  			if err != nil {
   173  				t.Logf("Error: %v", err)
   174  				w.WriteHeader(http.StatusBadRequest)
   175  				_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`))
   176  				_, _ = w.Write([]byte(`<AuthError><Id>bad_request</Id><Message>Unable to read user info</Message></AuthError>`))
   177  				return
   178  			}
   179  
   180  			if user.Username == "testuser" && user.Password == "testpass" {
   181  				_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`))
   182  				_, _ = w.Write([]byte(`<AuthSuccess><Id>success</Id><Message>login successful</Message></AuthSuccess>`))
   183  			} else if user.Username == "testuser" && user.Password == "invalidxml" {
   184  				_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`))
   185  				_, _ = w.Write([]byte(`<AuthSuccess><Id>success</Id><Message>login successful</AuthSuccess>`))
   186  			} else {
   187  				w.Header().Set("Www-Authenticate", "Protected Realm")
   188  				w.WriteHeader(http.StatusUnauthorized)
   189  				_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?>`))
   190  				_, _ = w.Write([]byte(`<AuthError><Id>unauthorized</Id><Message>Invalid credentials</Message></AuthError>`))
   191  			}
   192  
   193  			return
   194  		}
   195  	}
   196  }
   197  
   198  func handleUsersEndpoint(t *testing.T, w http.ResponseWriter, r *http.Request) {
   199  	if r.URL.Path == "/users" {
   200  		// JSON
   201  		if IsJSONType(r.Header.Get(hdrContentTypeKey)) {
   202  			var users []ExampleUser
   203  			jd := json.NewDecoder(r.Body)
   204  			err := jd.Decode(&users)
   205  			w.Header().Set(hdrContentTypeKey, "application/json")
   206  			if err != nil {
   207  				t.Logf("Error: %v", err)
   208  				w.WriteHeader(http.StatusBadRequest)
   209  				_, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to read user info" }`))
   210  				return
   211  			}
   212  
   213  			// logic check, since we are excepting to reach 3 records
   214  			if len(users) != 3 {
   215  				t.Log("Error: Excepted count of 3 records")
   216  				w.WriteHeader(http.StatusBadRequest)
   217  				_, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Expected record count doesn't match" }`))
   218  				return
   219  			}
   220  
   221  			eu := users[2]
   222  			if eu.FirstName == "firstname3" && eu.ZipCode == "10003" {
   223  				w.WriteHeader(http.StatusAccepted)
   224  				_, _ = w.Write([]byte(`{ "message": "Accepted" }`))
   225  			}
   226  
   227  			return
   228  		}
   229  	}
   230  }
   231  
   232  func createPostServer(t *testing.T) *httptest.Server {
   233  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   234  		t.Logf("Method: %v", r.Method)
   235  		t.Logf("Path: %v", r.URL.Path)
   236  		t.Logf("RawQuery: %v", r.URL.RawQuery)
   237  		t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey))
   238  
   239  		if r.Method == MethodPost {
   240  			handleLoginEndpoint(t, w, r)
   241  
   242  			handleUsersEndpoint(t, w, r)
   243  
   244  			if r.URL.Path == "/login-json-html" {
   245  				w.Header().Set(hdrContentTypeKey, "text/html")
   246  				w.WriteHeader(http.StatusOK)
   247  				_, _ = w.Write([]byte(`<htm><body>Test JSON request with HTML response</body></html>`))
   248  				return
   249  			}
   250  
   251  			if r.URL.Path == "/usersmap" {
   252  				// JSON
   253  				if IsJSONType(r.Header.Get(hdrContentTypeKey)) {
   254  					if r.URL.Query().Get("status") == "500" {
   255  						body, err := ioutil.ReadAll(r.Body)
   256  						if err != nil {
   257  							t.Errorf("Error: could not read post body: %s", err.Error())
   258  						}
   259  						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))
   260  						w.Header().Set(hdrContentTypeKey, "application/json; charset=utf-8")
   261  						w.WriteHeader(http.StatusInternalServerError)
   262  						_, _ = w.Write(body)
   263  						return
   264  					}
   265  
   266  					var users []map[string]interface{}
   267  					jd := json.NewDecoder(r.Body)
   268  					err := jd.Decode(&users)
   269  					w.Header().Set(hdrContentTypeKey, "application/json; charset=utf-8")
   270  					if err != nil {
   271  						t.Logf("Error: %v", err)
   272  						w.WriteHeader(http.StatusBadRequest)
   273  						_, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Unable to read user info" }`))
   274  						return
   275  					}
   276  
   277  					// logic check, since we are excepting to reach 1 map records
   278  					if len(users) != 1 {
   279  						t.Log("Error: Excepted count of 1 map records")
   280  						w.WriteHeader(http.StatusBadRequest)
   281  						_, _ = w.Write([]byte(`{ "id": "bad_request", "message": "Expected record count doesn't match" }`))
   282  						return
   283  					}
   284  
   285  					w.WriteHeader(http.StatusAccepted)
   286  					_, _ = w.Write([]byte(`{ "message": "Accepted" }`))
   287  
   288  					return
   289  				}
   290  			} else if r.URL.Path == "/redirect" {
   291  				w.Header().Set(hdrLocationKey, "/login")
   292  				w.WriteHeader(http.StatusTemporaryRedirect)
   293  			}
   294  		}
   295  	})
   296  
   297  	return ts
   298  }
   299  
   300  func createFormPostServer(t *testing.T) *httptest.Server {
   301  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   302  		t.Logf("Method: %v", r.Method)
   303  		t.Logf("Path: %v", r.URL.Path)
   304  		t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey))
   305  
   306  		if r.Method == MethodPost {
   307  			_ = r.ParseMultipartForm(10e6)
   308  
   309  			if r.URL.Path == "/profile" {
   310  				t.Logf("FirstName: %v", r.FormValue("first_name"))
   311  				t.Logf("LastName: %v", r.FormValue("last_name"))
   312  				t.Logf("City: %v", r.FormValue("city"))
   313  				t.Logf("Zip Code: %v", r.FormValue("zip_code"))
   314  
   315  				_, _ = w.Write([]byte("Success"))
   316  				return
   317  			} else if r.URL.Path == "/search" {
   318  				formEncodedData := r.Form.Encode()
   319  				t.Logf("Received Form Encoded values: %v", formEncodedData)
   320  
   321  				assertEqual(t, true, strings.Contains(formEncodedData, "search_criteria=pencil"))
   322  				assertEqual(t, true, strings.Contains(formEncodedData, "search_criteria=glass"))
   323  
   324  				_, _ = w.Write([]byte("Success"))
   325  				return
   326  			} else if r.URL.Path == "/upload" {
   327  				t.Logf("FirstName: %v", r.FormValue("first_name"))
   328  				t.Logf("LastName: %v", r.FormValue("last_name"))
   329  
   330  				targetPath := filepath.Join(getTestDataPath(), "upload")
   331  				_ = os.MkdirAll(targetPath, 0700)
   332  
   333  				for _, fhdrs := range r.MultipartForm.File {
   334  					for _, hdr := range fhdrs {
   335  						t.Logf("Name: %v", hdr.Filename)
   336  						t.Logf("Header: %v", hdr.Header)
   337  						dotPos := strings.LastIndex(hdr.Filename, ".")
   338  
   339  						fname := fmt.Sprintf("%s-%v%s", hdr.Filename[:dotPos], time.Now().Unix(), hdr.Filename[dotPos:])
   340  						t.Logf("Write name: %v", fname)
   341  
   342  						infile, _ := hdr.Open()
   343  						f, err := os.OpenFile(filepath.Join(targetPath, fname), os.O_WRONLY|os.O_CREATE, 0666)
   344  						if err != nil {
   345  							t.Logf("Error: %v", err)
   346  							return
   347  						}
   348  						defer func() {
   349  							_ = f.Close()
   350  						}()
   351  						_, _ = io.Copy(f, infile)
   352  
   353  						_, _ = w.Write([]byte(fmt.Sprintf("File: %v, uploaded as: %v\n", hdr.Filename, fname)))
   354  					}
   355  				}
   356  
   357  				return
   358  			}
   359  		}
   360  	})
   361  
   362  	return ts
   363  }
   364  
   365  func createFilePostServer(t *testing.T) *httptest.Server {
   366  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   367  		t.Logf("Method: %v", r.Method)
   368  		t.Logf("Path: %v", r.URL.Path)
   369  		t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey))
   370  
   371  		if r.Method != MethodPost {
   372  			t.Log("createPostServer:: Not a Post request")
   373  			w.WriteHeader(http.StatusBadRequest)
   374  			fmt.Fprint(w, http.StatusText(http.StatusBadRequest))
   375  			return
   376  		}
   377  
   378  		targetPath := filepath.Join(getTestDataPath(), "upload-large")
   379  		_ = os.MkdirAll(targetPath, 0700)
   380  		defer cleanupFiles(targetPath)
   381  
   382  		switch r.URL.Path {
   383  		case "/upload":
   384  			f, err := os.OpenFile(filepath.Join(targetPath, "large-file.png"),
   385  				os.O_WRONLY|os.O_CREATE, 0666)
   386  			if err != nil {
   387  				t.Logf("Error: %v", err)
   388  				return
   389  			}
   390  			defer func() {
   391  				_ = f.Close()
   392  			}()
   393  			size, _ := io.Copy(f, r.Body)
   394  
   395  			fmt.Fprintf(w, "File Uploaded successfully, file size: %v", size)
   396  		}
   397  	})
   398  
   399  	return ts
   400  }
   401  
   402  func createAuthServer(t *testing.T) *httptest.Server {
   403  	ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   404  		t.Logf("Method: %v", r.Method)
   405  		t.Logf("Path: %v", r.URL.Path)
   406  		t.Logf("Content-Type: %v", r.Header.Get(hdrContentTypeKey))
   407  
   408  		if r.Method == MethodGet {
   409  			if r.URL.Path == "/profile" {
   410  				// 004DDB79-6801-4587-B976-F093E6AC44FF
   411  				auth := r.Header.Get("Authorization")
   412  				t.Logf("Bearer Auth: %v", auth)
   413  
   414  				w.Header().Set(hdrContentTypeKey, "application/json; charset=utf-8")
   415  
   416  				if !strings.HasPrefix(auth, "Bearer ") {
   417  					w.Header().Set("Www-Authenticate", "Protected Realm")
   418  					w.WriteHeader(http.StatusUnauthorized)
   419  					_, _ = w.Write([]byte(`{ "id": "unauthorized", "message": "Invalid credentials" }`))
   420  
   421  					return
   422  				}
   423  
   424  				if auth[7:] == "004DDB79-6801-4587-B976-F093E6AC44FF" || auth[7:] == "004DDB79-6801-4587-B976-F093E6AC44FF-Request" {
   425  					_, _ = w.Write([]byte(`{ "id": "success", "message": "login successful" }`))
   426  				}
   427  			}
   428  
   429  			return
   430  		}
   431  
   432  		if r.Method == MethodPost {
   433  			if r.URL.Path == "/login" {
   434  				auth := r.Header.Get("Authorization")
   435  				t.Logf("Basic Auth: %v", auth)
   436  
   437  				w.Header().Set(hdrContentTypeKey, "application/json; charset=utf-8")
   438  
   439  				password, err := base64.StdEncoding.DecodeString(auth[6:])
   440  				if err != nil || string(password) != "myuser:basicauth" {
   441  					w.Header().Set("Www-Authenticate", "Protected Realm")
   442  					w.WriteHeader(http.StatusUnauthorized)
   443  					_, _ = w.Write([]byte(`{ "id": "unauthorized", "message": "Invalid credentials" }`))
   444  
   445  					return
   446  				}
   447  
   448  				_, _ = w.Write([]byte(`{ "id": "success", "message": "login successful" }`))
   449  			}
   450  
   451  			return
   452  		}
   453  	}))
   454  
   455  	return ts
   456  }
   457  
   458  func createGenServer(t *testing.T) *httptest.Server {
   459  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   460  		t.Logf("Method: %v", r.Method)
   461  		t.Logf("Path: %v", r.URL.Path)
   462  
   463  		if r.Method == MethodGet {
   464  			if r.URL.Path == "/json-no-set" {
   465  				// Set empty header value for testing, since Go server sets to
   466  				// text/plain; charset=utf-8
   467  				w.Header().Set(hdrContentTypeKey, "")
   468  				_, _ = w.Write([]byte(`{"response":"json response no content type set"}`))
   469  			} else if r.URL.Path == "/gzip-test" {
   470  				w.Header().Set(hdrContentTypeKey, plainTextType)
   471  				w.Header().Set(hdrContentEncodingKey, "gzip")
   472  				zw := gzip.NewWriter(w)
   473  				_, _ = zw.Write([]byte("This is Gzip response testing"))
   474  				zw.Close()
   475  			} else if r.URL.Path == "/gzip-test-gziped-empty-body" {
   476  				w.Header().Set(hdrContentTypeKey, plainTextType)
   477  				w.Header().Set(hdrContentEncodingKey, "gzip")
   478  				zw := gzip.NewWriter(w)
   479  				// write gziped empty body
   480  				_, _ = zw.Write([]byte(""))
   481  				zw.Close()
   482  			} else if r.URL.Path == "/gzip-test-no-gziped-body" {
   483  				w.Header().Set(hdrContentTypeKey, plainTextType)
   484  				w.Header().Set(hdrContentEncodingKey, "gzip")
   485  				// don't write body
   486  			}
   487  
   488  			return
   489  		}
   490  
   491  		if r.Method == MethodPut {
   492  			if r.URL.Path == "/plaintext" {
   493  				_, _ = w.Write([]byte("TestPut: plain text response"))
   494  			} else if r.URL.Path == "/json" {
   495  				w.Header().Set(hdrContentTypeKey, "application/json; charset=utf-8")
   496  				_, _ = w.Write([]byte(`{"response":"json response"}`))
   497  			} else if r.URL.Path == "/xml" {
   498  				w.Header().Set(hdrContentTypeKey, "application/xml")
   499  				_, _ = w.Write([]byte(`<?xml version="1.0" encoding="UTF-8"?><Response>XML response</Response>`))
   500  			}
   501  			return
   502  		}
   503  
   504  		if r.Method == MethodOptions && r.URL.Path == "/options" {
   505  			w.Header().Set("Access-Control-Allow-Origin", "localhost")
   506  			w.Header().Set("Access-Control-Allow-Methods", "PUT, PATCH")
   507  			w.Header().Set("Access-Control-Expose-Headers", "x-go-resty-id")
   508  			w.WriteHeader(http.StatusOK)
   509  			return
   510  		}
   511  
   512  		if r.Method == MethodPatch && r.URL.Path == "/patch" {
   513  			w.WriteHeader(http.StatusOK)
   514  			return
   515  		}
   516  
   517  		if r.Method == "REPORT" && r.URL.Path == "/report" {
   518  			body, _ := ioutil.ReadAll(r.Body)
   519  			if len(body) == 0 {
   520  				w.WriteHeader(http.StatusOK)
   521  			}
   522  			return
   523  		}
   524  	})
   525  
   526  	return ts
   527  }
   528  
   529  func createRedirectServer(t *testing.T) *httptest.Server {
   530  	ts := createTestServer(func(w http.ResponseWriter, r *http.Request) {
   531  		t.Logf("Method: %v", r.Method)
   532  		t.Logf("Path: %v", r.URL.Path)
   533  
   534  		if r.Method == MethodGet {
   535  			if strings.HasPrefix(r.URL.Path, "/redirect-host-check-") {
   536  				cntStr := strings.SplitAfter(r.URL.Path, "-")[3]
   537  				cnt, _ := strconv.Atoi(cntStr)
   538  
   539  				if cnt != 7 { // Testing hard stop via logical
   540  					if cnt >= 5 {
   541  						http.Redirect(w, r, "http://httpbin.org/get", http.StatusTemporaryRedirect)
   542  					} else {
   543  						http.Redirect(w, r, fmt.Sprintf("/redirect-host-check-%d", cnt+1), http.StatusTemporaryRedirect)
   544  					}
   545  				}
   546  			} else if strings.HasPrefix(r.URL.Path, "/redirect-") {
   547  				cntStr := strings.SplitAfter(r.URL.Path, "-")[1]
   548  				cnt, _ := strconv.Atoi(cntStr)
   549  
   550  				http.Redirect(w, r, fmt.Sprintf("/redirect-%d", cnt+1), http.StatusTemporaryRedirect)
   551  			}
   552  		}
   553  	})
   554  
   555  	return ts
   556  }
   557  
   558  func createTestServer(fn func(w http.ResponseWriter, r *http.Request)) *httptest.Server {
   559  	return httptest.NewServer(http.HandlerFunc(fn))
   560  }
   561  
   562  func dc() *Client {
   563  	c := New().
   564  		outputLogTo(ioutil.Discard)
   565  	return c
   566  }
   567  
   568  func dcl() *Client {
   569  	c := New().
   570  		SetDebug(true).
   571  		outputLogTo(ioutil.Discard)
   572  	return c
   573  }
   574  
   575  func dcr() *Request {
   576  	return dc().R()
   577  }
   578  
   579  func dclr() *Request {
   580  	c := dc().
   581  		SetDebug(true).
   582  		outputLogTo(ioutil.Discard)
   583  	return c.R()
   584  }
   585  
   586  func assertNil(t *testing.T, v interface{}) {
   587  	if !isNil(v) {
   588  		t.Errorf("[%v] was expected to be nil", v)
   589  	}
   590  }
   591  
   592  func assertNotNil(t *testing.T, v interface{}) {
   593  	if isNil(v) {
   594  		t.Errorf("[%v] was expected to be non-nil", v)
   595  	}
   596  }
   597  
   598  func assertType(t *testing.T, typ, v interface{}) {
   599  	if reflect.DeepEqual(reflect.TypeOf(typ), reflect.TypeOf(v)) {
   600  		t.Errorf("Expected type %t, got %t", typ, v)
   601  	}
   602  }
   603  
   604  func assertError(t *testing.T, err error) {
   605  	if err != nil {
   606  		t.Errorf("Error occurred [%v]", err)
   607  	}
   608  }
   609  
   610  func assertEqual(t *testing.T, e, g interface{}) (r bool) {
   611  	if !equal(e, g) {
   612  		t.Errorf("Expected [%v], got [%v]", e, g)
   613  	}
   614  
   615  	return
   616  }
   617  
   618  func assertNotEqual(t *testing.T, e, g interface{}) (r bool) {
   619  	if equal(e, g) {
   620  		t.Errorf("Expected [%v], got [%v]", e, g)
   621  	} else {
   622  		r = true
   623  	}
   624  
   625  	return
   626  }
   627  
   628  func equal(expected, got interface{}) bool {
   629  	return reflect.DeepEqual(expected, got)
   630  }
   631  
   632  func isNil(v interface{}) bool {
   633  	if v == nil {
   634  		return true
   635  	}
   636  
   637  	rv := reflect.ValueOf(v)
   638  	kind := rv.Kind()
   639  	if kind >= reflect.Chan && kind <= reflect.Slice && rv.IsNil() {
   640  		return true
   641  	}
   642  
   643  	return false
   644  }
   645  
   646  func logResponse(t *testing.T, resp *Response) {
   647  	t.Logf("Response Status: %v", resp.Status())
   648  	t.Logf("Response Time: %v", resp.Time())
   649  	t.Logf("Response Headers: %v", resp.Header())
   650  	t.Logf("Response Cookies: %v", resp.Cookies())
   651  	t.Logf("Response Body: %v", resp)
   652  }
   653  
   654  func cleanupFiles(files ...string) {
   655  	pwd, _ := os.Getwd()
   656  
   657  	for _, f := range files {
   658  		if filepath.IsAbs(f) {
   659  			_ = os.RemoveAll(f)
   660  		} else {
   661  			_ = os.RemoveAll(filepath.Join(pwd, f))
   662  		}
   663  	}
   664  }
   665  

View as plain text