resty_test.go 18 KB

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