httpclient_test.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package httpclient
  2. import (
  3. "crypto/tls"
  4. "io"
  5. "io/ioutil"
  6. "net"
  7. "net/http"
  8. "sync"
  9. "testing"
  10. "time"
  11. )
  12. var starter sync.Once
  13. var addr net.Addr
  14. func testHandler(w http.ResponseWriter, req *http.Request) {
  15. time.Sleep(200 * time.Millisecond)
  16. io.WriteString(w, "hello, world!\n")
  17. }
  18. func postHandler(w http.ResponseWriter, req *http.Request) {
  19. ioutil.ReadAll(req.Body)
  20. w.Header().Set("Content-Length", "2")
  21. io.WriteString(w, "OK")
  22. }
  23. func closeHandler(w http.ResponseWriter, req *http.Request) {
  24. hj, _ := w.(http.Hijacker)
  25. conn, bufrw, _ := hj.Hijack()
  26. defer conn.Close()
  27. bufrw.WriteString("HTTP/1.1 200 OK\r\nConnection: close\r\n\r\n")
  28. bufrw.Flush()
  29. }
  30. func redirectHandler(w http.ResponseWriter, req *http.Request) {
  31. ioutil.ReadAll(req.Body)
  32. http.Redirect(w, req, "/post", 302)
  33. }
  34. func redirect2Handler(w http.ResponseWriter, req *http.Request) {
  35. ioutil.ReadAll(req.Body)
  36. http.Redirect(w, req, "/redirect", 302)
  37. }
  38. func slowHandler(w http.ResponseWriter, r *http.Request) {
  39. w.WriteHeader(200)
  40. io.WriteString(w, "START\n")
  41. f := w.(http.Flusher)
  42. f.Flush()
  43. time.Sleep(200 * time.Millisecond)
  44. io.WriteString(w, "WORKING\n")
  45. f.Flush()
  46. time.Sleep(200 * time.Millisecond)
  47. io.WriteString(w, "DONE\n")
  48. return
  49. }
  50. func setupMockServer(t *testing.T) {
  51. http.HandleFunc("/test", testHandler)
  52. http.HandleFunc("/post", postHandler)
  53. http.HandleFunc("/redirect", redirectHandler)
  54. http.HandleFunc("/redirect2", redirect2Handler)
  55. http.HandleFunc("/close", closeHandler)
  56. http.HandleFunc("/slow", slowHandler)
  57. ln, err := net.Listen("tcp", ":0")
  58. if err != nil {
  59. t.Fatalf("failed to listen - %s", err.Error())
  60. }
  61. go func() {
  62. err = http.Serve(ln, nil)
  63. if err != nil {
  64. t.Fatalf("failed to start HTTP server - %s", err.Error())
  65. }
  66. }()
  67. addr = ln.Addr()
  68. }
  69. func TestHttpsConnection(t *testing.T) {
  70. transport := &Transport{
  71. ConnectTimeout: 1 * time.Second,
  72. RequestTimeout: 2 * time.Second,
  73. TLSClientConfig: &tls.Config{
  74. InsecureSkipVerify: true,
  75. },
  76. }
  77. defer transport.Close()
  78. client := &http.Client{Transport: transport}
  79. req, _ := http.NewRequest("GET", "https://httpbin.org/ip", nil)
  80. resp, err := client.Do(req)
  81. if err != nil {
  82. t.Fatalf("1st request failed - %s", err.Error())
  83. }
  84. _, err = ioutil.ReadAll(resp.Body)
  85. if err != nil {
  86. t.Fatalf("1st failed to read body - %s", err.Error())
  87. }
  88. resp.Body.Close()
  89. req2, _ := http.NewRequest("GET", "https://httpbin.org/delay/5", nil)
  90. _, err = client.Do(req2)
  91. if err == nil {
  92. t.Fatalf("HTTPS request should have timed out")
  93. }
  94. }
  95. func TestHttpClient(t *testing.T) {
  96. starter.Do(func() { setupMockServer(t) })
  97. transport := &Transport{
  98. ConnectTimeout: 1 * time.Second,
  99. RequestTimeout: 5 * time.Second,
  100. ReadWriteTimeout: 3 * time.Second,
  101. }
  102. client := &http.Client{Transport: transport}
  103. req, _ := http.NewRequest("GET", "http://"+addr.String()+"/test", nil)
  104. resp, err := client.Do(req)
  105. if err != nil {
  106. t.Fatalf("1st request failed - %s", err.Error())
  107. }
  108. _, err = ioutil.ReadAll(resp.Body)
  109. if err != nil {
  110. t.Fatalf("1st failed to read body - %s", err.Error())
  111. }
  112. resp.Body.Close()
  113. transport.Close()
  114. transport = &Transport{
  115. ConnectTimeout: 25 * time.Millisecond,
  116. RequestTimeout: 50 * time.Millisecond,
  117. ReadWriteTimeout: 50 * time.Millisecond,
  118. }
  119. client = &http.Client{Transport: transport}
  120. req2, _ := http.NewRequest("GET", "http://"+addr.String()+"/test", nil)
  121. resp, err = client.Do(req2)
  122. if err == nil {
  123. t.Fatal("2nd request should have timed out")
  124. }
  125. transport.Close()
  126. transport = &Transport{
  127. ConnectTimeout: 25 * time.Millisecond,
  128. RequestTimeout: 250 * time.Millisecond,
  129. ReadWriteTimeout: 250 * time.Millisecond,
  130. }
  131. client = &http.Client{Transport: transport}
  132. req3, _ := http.NewRequest("GET", "http://"+addr.String()+"/test", nil)
  133. resp, err = client.Do(req3)
  134. if err != nil {
  135. t.Fatal("3rd request should not have timed out")
  136. }
  137. resp.Body.Close()
  138. transport.Close()
  139. }
  140. func TestSlowServer(t *testing.T) {
  141. starter.Do(func() { setupMockServer(t) })
  142. transport := &Transport{
  143. ConnectTimeout: 25 * time.Millisecond,
  144. RequestTimeout: 500 * time.Millisecond,
  145. ReadWriteTimeout: 250 * time.Millisecond,
  146. }
  147. client := &http.Client{Transport: transport}
  148. req, _ := http.NewRequest("GET", "http://"+addr.String()+"/slow", nil)
  149. resp, err := client.Do(req)
  150. if err != nil {
  151. t.Fatalf("1st request failed - %s", err)
  152. }
  153. _, err = ioutil.ReadAll(resp.Body)
  154. if err != nil {
  155. t.Fatalf("1st failed to read body - %s", err)
  156. }
  157. resp.Body.Close()
  158. transport.Close()
  159. transport = &Transport{
  160. ConnectTimeout: 25 * time.Millisecond,
  161. RequestTimeout: 500 * time.Millisecond,
  162. ReadWriteTimeout: 100 * time.Millisecond,
  163. }
  164. client = &http.Client{Transport: transport}
  165. req, _ = http.NewRequest("GET", "http://"+addr.String()+"/slow", nil)
  166. resp, err = client.Do(req)
  167. if err != nil {
  168. t.Fatalf("2nd request failed - %s", err)
  169. }
  170. _, err = ioutil.ReadAll(resp.Body)
  171. netErr, ok := err.(net.Error)
  172. if !ok {
  173. t.Fatalf("2nd request dind't return a net.Error - %s", netErr)
  174. }
  175. if !netErr.Timeout() {
  176. t.Fatalf("2nd request should have timed out - %s", netErr)
  177. }
  178. resp.Body.Close()
  179. transport.Close()
  180. }
  181. func TestMultipleRequests(t *testing.T) {
  182. starter.Do(func() { setupMockServer(t) })
  183. transport := &Transport{
  184. ConnectTimeout: 1 * time.Second,
  185. RequestTimeout: 5 * time.Second,
  186. ReadWriteTimeout: 3 * time.Second,
  187. ResponseHeaderTimeout: 400 * time.Millisecond,
  188. }
  189. client := &http.Client{Transport: transport}
  190. req, _ := http.NewRequest("GET", "http://"+addr.String()+"/test", nil)
  191. for i := 0; i < 10; i++ {
  192. resp, err := client.Do(req)
  193. if err != nil {
  194. t.Fatalf("%d request failed - %s", i, err.Error())
  195. }
  196. _, err = ioutil.ReadAll(resp.Body)
  197. if err != nil {
  198. t.Fatalf("%d failed to read body - %s", i, err.Error())
  199. }
  200. resp.Body.Close()
  201. }
  202. transport.Close()
  203. }