client_test.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. // Copyright (c) 2015-2019 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. package resty
  5. import (
  6. "bytes"
  7. "crypto/tls"
  8. "errors"
  9. "io/ioutil"
  10. "net/http"
  11. "net/url"
  12. "path/filepath"
  13. "reflect"
  14. "strconv"
  15. "strings"
  16. "testing"
  17. "time"
  18. )
  19. func TestClientBasicAuth(t *testing.T) {
  20. ts := createAuthServer(t)
  21. defer ts.Close()
  22. c := dc()
  23. c.SetBasicAuth("myuser", "basicauth").
  24. SetHostURL(ts.URL).
  25. SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
  26. resp, err := c.R().
  27. SetResult(&AuthSuccess{}).
  28. Post("/login")
  29. assertError(t, err)
  30. assertEqual(t, http.StatusOK, resp.StatusCode())
  31. t.Logf("Result Success: %q", resp.Result().(*AuthSuccess))
  32. logResponse(t, resp)
  33. }
  34. func TestClientAuthToken(t *testing.T) {
  35. ts := createAuthServer(t)
  36. defer ts.Close()
  37. c := dc()
  38. c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
  39. SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF").
  40. SetHostURL(ts.URL + "/")
  41. resp, err := c.R().Get("/profile")
  42. assertError(t, err)
  43. assertEqual(t, http.StatusOK, resp.StatusCode())
  44. }
  45. func TestOnAfterMiddleware(t *testing.T) {
  46. ts := createGenServer(t)
  47. defer ts.Close()
  48. c := dc()
  49. c.OnAfterResponse(func(c *Client, res *Response) error {
  50. t.Logf("Request sent at: %v", res.Request.Time)
  51. t.Logf("Response Received at: %v", res.ReceivedAt())
  52. return nil
  53. })
  54. resp, err := c.R().
  55. SetBody("OnAfterResponse: This is plain text body to server").
  56. Put(ts.URL + "/plaintext")
  57. assertError(t, err)
  58. assertEqual(t, http.StatusOK, resp.StatusCode())
  59. assertEqual(t, "TestPut: plain text response", resp.String())
  60. }
  61. func TestClientRedirectPolicy(t *testing.T) {
  62. ts := createRedirectServer(t)
  63. defer ts.Close()
  64. c := dc()
  65. c.SetHTTPMode().
  66. SetRedirectPolicy(FlexibleRedirectPolicy(20))
  67. _, err := c.R().Get(ts.URL + "/redirect-1")
  68. assertEqual(t, "Get /redirect-21: stopped after 20 redirects", err.Error())
  69. }
  70. func TestClientTimeout(t *testing.T) {
  71. ts := createGetServer(t)
  72. defer ts.Close()
  73. c := dc()
  74. c.SetHTTPMode().
  75. SetTimeout(time.Second * 3)
  76. _, err := c.R().Get(ts.URL + "/set-timeout-test")
  77. assertEqual(t, true, strings.Contains(strings.ToLower(err.Error()), "timeout"))
  78. }
  79. func TestClientTimeoutWithinThreshold(t *testing.T) {
  80. ts := createGetServer(t)
  81. defer ts.Close()
  82. c := dc()
  83. c.SetHTTPMode().
  84. SetTimeout(time.Second * 3)
  85. resp, err := c.R().Get(ts.URL + "/set-timeout-test-with-sequence")
  86. assertError(t, err)
  87. seq1, _ := strconv.ParseInt(resp.String(), 10, 32)
  88. resp, err = c.R().Get(ts.URL + "/set-timeout-test-with-sequence")
  89. assertError(t, err)
  90. seq2, _ := strconv.ParseInt(resp.String(), 10, 32)
  91. assertEqual(t, seq1+1, seq2)
  92. }
  93. func TestClientTimeoutInternalError(t *testing.T) {
  94. c := dc()
  95. c.SetHTTPMode()
  96. c.SetTimeout(time.Second * 1)
  97. _, _ = c.R().Get("http://localhost:9000/set-timeout-test")
  98. }
  99. func TestClientProxy(t *testing.T) {
  100. ts := createGetServer(t)
  101. defer ts.Close()
  102. c := dc()
  103. c.SetTimeout(1 * time.Second)
  104. c.SetProxy("http://sampleproxy:8888")
  105. resp, err := c.R().Get(ts.URL)
  106. assertNotNil(t, resp)
  107. assertNotNil(t, err)
  108. // Error
  109. c.SetProxy("//not.a.user@%66%6f%6f.com:8888")
  110. resp, err = c.R().
  111. Get(ts.URL)
  112. assertNil(t, err)
  113. assertNotNil(t, resp)
  114. }
  115. func TestClientSetCertificates(t *testing.T) {
  116. DefaultClient = dc()
  117. SetCertificates(tls.Certificate{})
  118. transport, err := DefaultClient.getTransport()
  119. assertNil(t, err)
  120. assertEqual(t, 1, len(transport.TLSClientConfig.Certificates))
  121. }
  122. func TestClientSetRootCertificate(t *testing.T) {
  123. DefaultClient = dc()
  124. SetRootCertificate(filepath.Join(getTestDataPath(), "sample-root.pem"))
  125. transport, err := DefaultClient.getTransport()
  126. assertNil(t, err)
  127. assertNotNil(t, transport.TLSClientConfig.RootCAs)
  128. }
  129. func TestClientSetRootCertificateNotExists(t *testing.T) {
  130. DefaultClient = dc()
  131. SetRootCertificate(filepath.Join(getTestDataPath(), "not-exists-sample-root.pem"))
  132. transport, err := DefaultClient.getTransport()
  133. assertNil(t, err)
  134. assertNil(t, transport.TLSClientConfig)
  135. }
  136. func TestClientOnBeforeRequestModification(t *testing.T) {
  137. tc := New()
  138. tc.OnBeforeRequest(func(c *Client, r *Request) error {
  139. r.SetAuthToken("This is test auth token")
  140. return nil
  141. })
  142. ts := createGetServer(t)
  143. defer ts.Close()
  144. resp, err := tc.R().Get(ts.URL + "/")
  145. assertError(t, err)
  146. assertEqual(t, http.StatusOK, resp.StatusCode())
  147. assertEqual(t, "200 OK", resp.Status())
  148. assertNotNil(t, resp.Body())
  149. assertEqual(t, "TestGet: text response", resp.String())
  150. logResponse(t, resp)
  151. }
  152. func TestClientSetTransport(t *testing.T) {
  153. ts := createGetServer(t)
  154. defer ts.Close()
  155. DefaultClient = dc()
  156. transport := &http.Transport{
  157. // something like Proxying to httptest.Server, etc...
  158. Proxy: func(req *http.Request) (*url.URL, error) {
  159. return url.Parse(ts.URL)
  160. },
  161. }
  162. SetTransport(transport)
  163. transportInUse, err := DefaultClient.getTransport()
  164. assertNil(t, err)
  165. assertEqual(t, true, transport == transportInUse)
  166. }
  167. func TestClientSetScheme(t *testing.T) {
  168. DefaultClient = dc()
  169. SetScheme("http")
  170. assertEqual(t, true, DefaultClient.scheme == "http")
  171. }
  172. func TestClientSetCookieJar(t *testing.T) {
  173. DefaultClient = dc()
  174. backupJar := DefaultClient.httpClient.Jar
  175. SetCookieJar(nil)
  176. assertNil(t, DefaultClient.httpClient.Jar)
  177. SetCookieJar(backupJar)
  178. assertEqual(t, true, DefaultClient.httpClient.Jar == backupJar)
  179. }
  180. func TestClientOptions(t *testing.T) {
  181. SetHTTPMode().SetContentLength(true)
  182. assertEqual(t, Mode(), "http")
  183. assertEqual(t, DefaultClient.setContentLength, true)
  184. SetRESTMode()
  185. assertEqual(t, Mode(), "rest")
  186. SetHostURL("http://httpbin.org")
  187. assertEqual(t, "http://httpbin.org", DefaultClient.HostURL)
  188. SetHeader(hdrContentTypeKey, jsonContentType)
  189. SetHeaders(map[string]string{
  190. hdrUserAgentKey: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) go-resty v0.1",
  191. "X-Request-Id": strconv.FormatInt(time.Now().UnixNano(), 10),
  192. })
  193. assertEqual(t, jsonContentType, DefaultClient.Header.Get(hdrContentTypeKey))
  194. SetCookie(&http.Cookie{
  195. Name: "default-cookie",
  196. Value: "This is cookie default-cookie value",
  197. Path: "/",
  198. Domain: "localhost",
  199. MaxAge: 36000,
  200. HttpOnly: true,
  201. Secure: false,
  202. })
  203. assertEqual(t, "default-cookie", DefaultClient.Cookies[0].Name)
  204. var cookies []*http.Cookie
  205. cookies = append(cookies, &http.Cookie{
  206. Name: "default-cookie-1",
  207. Value: "This is default-cookie 1 value",
  208. Path: "/",
  209. })
  210. cookies = append(cookies, &http.Cookie{
  211. Name: "default-cookie-2",
  212. Value: "This is default-cookie 2 value",
  213. Path: "/",
  214. })
  215. SetCookies(cookies)
  216. assertEqual(t, "default-cookie-1", DefaultClient.Cookies[1].Name)
  217. assertEqual(t, "default-cookie-2", DefaultClient.Cookies[2].Name)
  218. SetQueryParam("test_param_1", "Param_1")
  219. SetQueryParams(map[string]string{"test_param_2": "Param_2", "test_param_3": "Param_3"})
  220. assertEqual(t, "Param_3", DefaultClient.QueryParam.Get("test_param_3"))
  221. rTime := strconv.FormatInt(time.Now().UnixNano(), 10)
  222. SetFormData(map[string]string{"r_time": rTime})
  223. assertEqual(t, rTime, DefaultClient.FormData.Get("r_time"))
  224. SetBasicAuth("myuser", "mypass")
  225. assertEqual(t, "myuser", DefaultClient.UserInfo.Username)
  226. SetAuthToken("AC75BD37F019E08FBC594900518B4F7E")
  227. assertEqual(t, "AC75BD37F019E08FBC594900518B4F7E", DefaultClient.Token)
  228. SetDisableWarn(true)
  229. assertEqual(t, DefaultClient.DisableWarn, true)
  230. SetRetryCount(3)
  231. assertEqual(t, 3, DefaultClient.RetryCount)
  232. rwt := time.Duration(1000) * time.Millisecond
  233. SetRetryWaitTime(rwt)
  234. assertEqual(t, rwt, DefaultClient.RetryWaitTime)
  235. mrwt := time.Duration(2) * time.Second
  236. SetRetryMaxWaitTime(mrwt)
  237. assertEqual(t, mrwt, DefaultClient.RetryMaxWaitTime)
  238. err := &AuthError{}
  239. SetError(err)
  240. if reflect.TypeOf(err) == DefaultClient.Error {
  241. t.Error("SetError failed")
  242. }
  243. SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
  244. transport, transportErr := DefaultClient.getTransport()
  245. assertNil(t, transportErr)
  246. assertEqual(t, true, transport.TLSClientConfig.InsecureSkipVerify)
  247. OnBeforeRequest(func(c *Client, r *Request) error {
  248. c.Log.Println("I'm in Request middleware")
  249. return nil // if it success
  250. })
  251. OnAfterResponse(func(c *Client, r *Response) error {
  252. c.Log.Println("I'm in Response middleware")
  253. return nil // if it success
  254. })
  255. SetTimeout(5 * time.Second)
  256. SetRedirectPolicy(FlexibleRedirectPolicy(10), func(req *http.Request, via []*http.Request) error {
  257. return errors.New("sample test redirect")
  258. })
  259. SetContentLength(true)
  260. SetDebug(true)
  261. assertEqual(t, DefaultClient.Debug, true)
  262. var sl int64 = 1000000
  263. SetDebugBodyLimit(sl)
  264. assertEqual(t, DefaultClient.debugBodySizeLimit, sl)
  265. SetAllowGetMethodPayload(true)
  266. assertEqual(t, DefaultClient.AllowGetMethodPayload, true)
  267. SetScheme("http")
  268. assertEqual(t, DefaultClient.scheme, "http")
  269. SetCloseConnection(true)
  270. assertEqual(t, DefaultClient.closeConnection, true)
  271. SetLogger(ioutil.Discard)
  272. }
  273. func TestClientPreRequestHook(t *testing.T) {
  274. SetPreRequestHook(func(c *Client, r *Request) error {
  275. c.Log.Println("I'm in Pre-Request Hook")
  276. return nil
  277. })
  278. SetPreRequestHook(func(c *Client, r *Request) error {
  279. c.Log.Println("I'm Overwriting existing Pre-Request Hook")
  280. return nil
  281. })
  282. }
  283. func TestClientAllowsGetMethodPayload(t *testing.T) {
  284. ts := createGetServer(t)
  285. defer ts.Close()
  286. c := dc()
  287. c.SetAllowGetMethodPayload(true)
  288. c.SetPreRequestHook(func(*Client, *Request) error { return nil }) // for coverage
  289. payload := "test-payload"
  290. resp, err := c.R().SetBody(payload).Get(ts.URL + "/get-method-payload-test")
  291. assertError(t, err)
  292. assertEqual(t, http.StatusOK, resp.StatusCode())
  293. assertEqual(t, payload, resp.String())
  294. }
  295. func TestClientRoundTripper(t *testing.T) {
  296. c := NewWithClient(&http.Client{})
  297. c.SetLogger(ioutil.Discard)
  298. rt := &CustomRoundTripper{}
  299. c.SetTransport(rt)
  300. ct, err := c.getTransport()
  301. assertNotNil(t, err)
  302. assertNil(t, ct)
  303. assertEqual(t, "current transport is not an *http.Transport instance", err.Error())
  304. c.SetTLSClientConfig(&tls.Config{})
  305. c.SetProxy("http://localhost:9090")
  306. c.RemoveProxy()
  307. c.SetCertificates(tls.Certificate{})
  308. c.SetRootCertificate(filepath.Join(getTestDataPath(), "sample-root.pem"))
  309. }
  310. func TestClientNewRequest(t *testing.T) {
  311. c := New()
  312. request := c.NewRequest()
  313. assertNotNil(t, request)
  314. }
  315. func TestNewRequest(t *testing.T) {
  316. request := NewRequest()
  317. assertNotNil(t, request)
  318. }
  319. func TestDebugBodySizeLimit(t *testing.T) {
  320. ts := createGetServer(t)
  321. defer ts.Close()
  322. var lgr bytes.Buffer
  323. c := dc()
  324. c.SetDebug(true)
  325. c.SetLogger(&lgr)
  326. c.SetDebugBodyLimit(30)
  327. testcases := []struct{ url, want string }{
  328. // Text, does not exceed limit.
  329. {ts.URL, "TestGet: text response"},
  330. // Empty response.
  331. {ts.URL + "/no-content", "***** NO CONTENT *****"},
  332. // JSON, does not exceed limit.
  333. {ts.URL + "/json", "{\n \"TestGet\": \"JSON response\"\n}"},
  334. // Invalid JSON, does not exceed limit.
  335. {ts.URL + "/json-invalid", "TestGet: Invalid JSON"},
  336. // Text, exceeds limit.
  337. {ts.URL + "/long-text", "RESPONSE TOO LARGE"},
  338. // JSON, exceeds limit.
  339. {ts.URL + "/long-json", "RESPONSE TOO LARGE"},
  340. }
  341. for _, tc := range testcases {
  342. _, err := c.R().Get(tc.url)
  343. assertError(t, err)
  344. debugLog := lgr.String()
  345. if !strings.Contains(debugLog, tc.want) {
  346. t.Errorf("Expected logs to contain [%v], got [\n%v]", tc.want, debugLog)
  347. }
  348. lgr.Reset()
  349. }
  350. }
  351. // CustomRoundTripper just for test
  352. type CustomRoundTripper struct {
  353. }
  354. // RoundTrip just for test
  355. func (rt *CustomRoundTripper) RoundTrip(_ *http.Request) (*http.Response, error) {
  356. return &http.Response{}, nil
  357. }
  358. func TestSetLogPrefix(t *testing.T) {
  359. c := New()
  360. c.SetLogPrefix("CUSTOM ")
  361. assertEqual(t, "CUSTOM ", c.logPrefix)
  362. assertEqual(t, "CUSTOM ", c.Log.Prefix())
  363. c.disableLogPrefix()
  364. c.enableLogPrefix()
  365. assertEqual(t, "CUSTOM ", c.logPrefix)
  366. assertEqual(t, "CUSTOM ", c.Log.Prefix())
  367. }
  368. func TestAutoGzip(t *testing.T) {
  369. ts := createGenServer(t)
  370. defer ts.Close()
  371. c := New()
  372. testcases := []struct{ url, want string }{
  373. {ts.URL + "/gzip-test", "This is Gzip response testing"},
  374. {ts.URL + "/gzip-test-gziped-empty-body", ""},
  375. {ts.URL + "/gzip-test-no-gziped-body", ""},
  376. }
  377. for _, tc := range testcases {
  378. resp, err := c.R().
  379. SetHeader("Accept-Encoding", "gzip").
  380. Get(tc.url)
  381. assertError(t, err)
  382. assertEqual(t, http.StatusOK, resp.StatusCode())
  383. assertEqual(t, "200 OK", resp.Status())
  384. assertNotNil(t, resp.Body())
  385. assertEqual(t, tc.want, resp.String())
  386. logResponse(t, resp)
  387. }
  388. }
  389. func TestLogCallbacks(t *testing.T) {
  390. ts := createAuthServer(t)
  391. defer ts.Close()
  392. c := New().SetDebug(true)
  393. var lgr bytes.Buffer
  394. c.SetLogger(&lgr)
  395. c.OnRequestLog(func(r *RequestLog) error {
  396. // masking authorzation header
  397. r.Header.Set("Authorization", "Bearer *******************************")
  398. return nil
  399. })
  400. c.OnResponseLog(func(r *ResponseLog) error {
  401. r.Header.Add("X-Debug-Resposne-Log", "Modified :)")
  402. r.Body += "\nModified the response body content"
  403. return nil
  404. })
  405. c.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true}).
  406. SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF")
  407. resp, err := c.R().
  408. SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
  409. Get(ts.URL + "/profile")
  410. assertError(t, err)
  411. assertEqual(t, http.StatusOK, resp.StatusCode())
  412. // Validating debug log updates
  413. logInfo := lgr.String()
  414. assertEqual(t, true, strings.Contains(logInfo, "Bearer *******************************"))
  415. assertEqual(t, true, strings.Contains(logInfo, "X-Debug-Resposne-Log"))
  416. assertEqual(t, true, strings.Contains(logInfo, "Modified the response body content"))
  417. // Error scenario
  418. c.OnRequestLog(func(r *RequestLog) error { return errors.New("request test error") })
  419. resp, err = c.R().
  420. SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
  421. Get(ts.URL + "/profile")
  422. assertEqual(t, errors.New("request test error"), err)
  423. assertNil(t, resp)
  424. c.OnRequestLog(nil)
  425. c.OnResponseLog(func(r *ResponseLog) error { return errors.New("response test error") })
  426. resp, err = c.R().
  427. SetAuthToken("004DDB79-6801-4587-B976-F093E6AC44FF-Request").
  428. Get(ts.URL + "/profile")
  429. assertEqual(t, errors.New("response test error"), err)
  430. assertNotNil(t, resp)
  431. }