requests_test.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. package httpc
  2. import (
  3. "context"
  4. "net/http"
  5. "net/http/httptest"
  6. "net/http/httptrace"
  7. "strings"
  8. "testing"
  9. "github.com/stretchr/testify/assert"
  10. ztrace "github.com/wuntsong-org/go-zero-plus/core/trace"
  11. "github.com/wuntsong-org/go-zero-plus/core/trace/tracetest"
  12. "github.com/wuntsong-org/go-zero-plus/rest/httpx"
  13. "github.com/wuntsong-org/go-zero-plus/rest/internal/header"
  14. "github.com/wuntsong-org/go-zero-plus/rest/router"
  15. tcodes "go.opentelemetry.io/otel/codes"
  16. sdktrace "go.opentelemetry.io/otel/sdk/trace"
  17. "go.opentelemetry.io/otel/trace"
  18. )
  19. func TestDoRequest(t *testing.T) {
  20. ztrace.StartAgent(ztrace.Config{
  21. Name: "go-zero-test",
  22. Endpoint: "http://localhost:14268/api/traces",
  23. Batcher: "jaeger",
  24. Sampler: 1.0,
  25. })
  26. defer ztrace.StopAgent()
  27. svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  28. }))
  29. defer svr.Close()
  30. req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
  31. assert.Nil(t, err)
  32. resp, err := DoRequest(req)
  33. assert.Nil(t, err)
  34. assert.Equal(t, http.StatusOK, resp.StatusCode)
  35. spanContext := trace.SpanContextFromContext(resp.Request.Context())
  36. assert.True(t, spanContext.IsValid())
  37. }
  38. func TestDoRequest_NotFound(t *testing.T) {
  39. svr := httptest.NewServer(http.NotFoundHandler())
  40. defer svr.Close()
  41. req, err := http.NewRequest(http.MethodPost, svr.URL, nil)
  42. assert.Nil(t, err)
  43. req.Header.Set(header.ContentType, header.JsonContentType)
  44. resp, err := DoRequest(req)
  45. assert.Nil(t, err)
  46. assert.Equal(t, http.StatusNotFound, resp.StatusCode)
  47. }
  48. func TestDoRequest_Moved(t *testing.T) {
  49. svr := httptest.NewServer(http.RedirectHandler("/foo", http.StatusMovedPermanently))
  50. defer svr.Close()
  51. req, err := http.NewRequest(http.MethodGet, svr.URL, nil)
  52. assert.Nil(t, err)
  53. _, err = DoRequest(req)
  54. // too many redirects
  55. assert.NotNil(t, err)
  56. }
  57. func TestDo(t *testing.T) {
  58. me := tracetest.NewInMemoryExporter(t)
  59. type Data struct {
  60. Key string `path:"key"`
  61. Value int `form:"value"`
  62. Header string `header:"X-Header"`
  63. Body string `json:"body"`
  64. }
  65. rt := router.NewRouter()
  66. err := rt.Handle(http.MethodPost, "/nodes/:key",
  67. http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  68. var req Data
  69. assert.Nil(t, httpx.Parse(r, &req))
  70. }))
  71. assert.Nil(t, err)
  72. svr := httptest.NewServer(http.HandlerFunc(rt.ServeHTTP))
  73. defer svr.Close()
  74. data := Data{
  75. Key: "foo",
  76. Value: 10,
  77. Header: "my-header",
  78. Body: "my body",
  79. }
  80. resp, err := Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
  81. assert.Nil(t, err)
  82. assert.Equal(t, http.StatusOK, resp.StatusCode)
  83. assert.Equal(t, 1, len(me.GetSpans()))
  84. span := me.GetSpans()[0].Snapshot()
  85. assert.Equal(t, sdktrace.Status{
  86. Code: tcodes.Unset,
  87. }, span.Status())
  88. assert.Equal(t, 0, len(span.Events()))
  89. assert.Equal(t, 7, len(span.Attributes()))
  90. }
  91. func TestDo_Ptr(t *testing.T) {
  92. type Data struct {
  93. Key string `path:"key"`
  94. Value int `form:"value"`
  95. Header string `header:"X-Header"`
  96. Body string `json:"body"`
  97. }
  98. rt := router.NewRouter()
  99. err := rt.Handle(http.MethodPost, "/nodes/:key",
  100. http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  101. var req Data
  102. assert.Nil(t, httpx.Parse(r, &req))
  103. assert.Equal(t, "foo", req.Key)
  104. assert.Equal(t, 10, req.Value)
  105. assert.Equal(t, "my-header", req.Header)
  106. assert.Equal(t, "my body", req.Body)
  107. }))
  108. assert.Nil(t, err)
  109. svr := httptest.NewServer(http.HandlerFunc(rt.ServeHTTP))
  110. defer svr.Close()
  111. data := &Data{
  112. Key: "foo",
  113. Value: 10,
  114. Header: "my-header",
  115. Body: "my body",
  116. }
  117. resp, err := Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
  118. assert.Nil(t, err)
  119. assert.Equal(t, http.StatusOK, resp.StatusCode)
  120. }
  121. func TestDo_BadRequest(t *testing.T) {
  122. _, err := Do(context.Background(), http.MethodPost, ":/nodes/:key", nil)
  123. assert.NotNil(t, err)
  124. val1 := struct {
  125. Value string `json:"value,options=[a,b]"`
  126. }{
  127. Value: "c",
  128. }
  129. _, err = Do(context.Background(), http.MethodPost, "/nodes/:key", val1)
  130. assert.NotNil(t, err)
  131. val2 := struct {
  132. Value string `path:"val"`
  133. }{
  134. Value: "",
  135. }
  136. _, err = Do(context.Background(), http.MethodPost, "/nodes/:key", val2)
  137. assert.NotNil(t, err)
  138. val3 := struct {
  139. Value string `path:"key"`
  140. Body string `json:"body"`
  141. }{
  142. Value: "foo",
  143. }
  144. _, err = Do(context.Background(), http.MethodGet, "/nodes/:key", val3)
  145. assert.NotNil(t, err)
  146. _, err = Do(context.Background(), "\n", "rtmp://nodes", nil)
  147. assert.NotNil(t, err)
  148. val4 := struct {
  149. Value string `path:"val"`
  150. }{
  151. Value: "",
  152. }
  153. _, err = Do(context.Background(), http.MethodPost, "/nodes/:val", val4)
  154. assert.NotNil(t, err)
  155. val5 := struct {
  156. Value string `path:"val"`
  157. Another int `path:"foo"`
  158. }{
  159. Value: "1",
  160. Another: 2,
  161. }
  162. _, err = Do(context.Background(), http.MethodPost, "/nodes/:val", val5)
  163. assert.NotNil(t, err)
  164. }
  165. func TestDo_Json(t *testing.T) {
  166. type Data struct {
  167. Key string `path:"key"`
  168. Value int `form:"value"`
  169. Header string `header:"X-Header"`
  170. Body chan int `json:"body"`
  171. }
  172. rt := router.NewRouter()
  173. err := rt.Handle(http.MethodPost, "/nodes/:key",
  174. http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  175. var req Data
  176. assert.Nil(t, httpx.Parse(r, &req))
  177. }))
  178. assert.Nil(t, err)
  179. svr := httptest.NewServer(http.HandlerFunc(rt.ServeHTTP))
  180. defer svr.Close()
  181. data := Data{
  182. Key: "foo",
  183. Value: 10,
  184. Header: "my-header",
  185. Body: make(chan int),
  186. }
  187. _, err = Do(context.Background(), http.MethodPost, svr.URL+"/nodes/:key", data)
  188. assert.NotNil(t, err)
  189. }
  190. func TestDo_WithClientHttpTrace(t *testing.T) {
  191. svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
  192. defer svr.Close()
  193. enter := false
  194. _, err := Do(httptrace.WithClientTrace(context.Background(),
  195. &httptrace.ClientTrace{
  196. GetConn: func(hostPort string) {
  197. assert.Equal(t, "127.0.0.1", strings.Split(hostPort, ":")[0])
  198. enter = true
  199. },
  200. }), http.MethodGet, svr.URL, nil)
  201. assert.Nil(t, err)
  202. assert.True(t, enter)
  203. }