tracinghandler_test.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. package handler
  2. import (
  3. "context"
  4. "io"
  5. "net/http"
  6. "net/http/httptest"
  7. "strconv"
  8. "testing"
  9. "github.com/stretchr/testify/assert"
  10. ztrace "github.com/zeromicro/go-zero/core/trace"
  11. "github.com/zeromicro/go-zero/rest/chain"
  12. "go.opentelemetry.io/otel"
  13. "go.opentelemetry.io/otel/propagation"
  14. "go.opentelemetry.io/otel/trace"
  15. )
  16. func TestOtelHandler(t *testing.T) {
  17. ztrace.StartAgent(ztrace.Config{
  18. Name: "go-zero-test",
  19. Endpoint: "http://localhost:14268/api/traces",
  20. Batcher: "jaeger",
  21. Sampler: 1.0,
  22. })
  23. defer ztrace.StopAgent()
  24. for _, test := range []string{"", "bar"} {
  25. t.Run(test, func(t *testing.T) {
  26. h := chain.New(TracingHandler("foo", test)).Then(
  27. http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  28. span := trace.SpanFromContext(r.Context())
  29. assert.True(t, span.SpanContext().IsValid())
  30. assert.True(t, span.IsRecording())
  31. }))
  32. ts := httptest.NewServer(h)
  33. defer ts.Close()
  34. client := ts.Client()
  35. err := func(ctx context.Context) error {
  36. ctx, span := otel.Tracer("httptrace/client").Start(ctx, "test")
  37. defer span.End()
  38. req, _ := http.NewRequest("GET", ts.URL, nil)
  39. otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
  40. res, err := client.Do(req)
  41. assert.Nil(t, err)
  42. return res.Body.Close()
  43. }(context.Background())
  44. assert.Nil(t, err)
  45. })
  46. }
  47. }
  48. func TestDontTracingSpan(t *testing.T) {
  49. ztrace.StartAgent(ztrace.Config{
  50. Name: "go-zero-test",
  51. Endpoint: "http://localhost:14268/api/traces",
  52. Batcher: "jaeger",
  53. Sampler: 1.0,
  54. })
  55. defer ztrace.StopAgent()
  56. DontTraceSpan("bar")
  57. defer notTracingSpans.Delete("bar")
  58. for _, test := range []string{"", "bar", "foo"} {
  59. t.Run(test, func(t *testing.T) {
  60. h := chain.New(TracingHandler("foo", test)).Then(
  61. http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  62. span := trace.SpanFromContext(r.Context())
  63. spanCtx := span.SpanContext()
  64. if test == "bar" {
  65. assert.False(t, spanCtx.IsValid())
  66. assert.False(t, span.IsRecording())
  67. return
  68. }
  69. assert.True(t, span.IsRecording())
  70. assert.True(t, spanCtx.IsValid())
  71. }))
  72. ts := httptest.NewServer(h)
  73. defer ts.Close()
  74. client := ts.Client()
  75. err := func(ctx context.Context) error {
  76. ctx, span := otel.Tracer("httptrace/client").Start(ctx, "test")
  77. defer span.End()
  78. req, _ := http.NewRequest("GET", ts.URL, nil)
  79. otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
  80. res, err := client.Do(req)
  81. assert.Nil(t, err)
  82. return res.Body.Close()
  83. }(context.Background())
  84. assert.Nil(t, err)
  85. })
  86. }
  87. }
  88. func TestTraceResponseWriter(t *testing.T) {
  89. ztrace.StartAgent(ztrace.Config{
  90. Name: "go-zero-test",
  91. Endpoint: "http://localhost:14268/api/traces",
  92. Batcher: "jaeger",
  93. Sampler: 1.0,
  94. })
  95. defer ztrace.StopAgent()
  96. for _, test := range []int{0, 200, 300, 400, 401, 500, 503} {
  97. t.Run(strconv.Itoa(test), func(t *testing.T) {
  98. h := chain.New(TracingHandler("foo", "bar")).Then(
  99. http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  100. span := trace.SpanFromContext(r.Context())
  101. spanCtx := span.SpanContext()
  102. assert.True(t, span.IsRecording())
  103. assert.True(t, spanCtx.IsValid())
  104. if test != 0 {
  105. w.WriteHeader(test)
  106. }
  107. w.Write([]byte("hello"))
  108. }))
  109. ts := httptest.NewServer(h)
  110. defer ts.Close()
  111. client := ts.Client()
  112. err := func(ctx context.Context) error {
  113. ctx, span := otel.Tracer("httptrace/client").Start(ctx, "test")
  114. defer span.End()
  115. req, _ := http.NewRequest("GET", ts.URL, nil)
  116. otel.GetTextMapPropagator().Inject(ctx, propagation.HeaderCarrier(req.Header))
  117. res, err := client.Do(req)
  118. assert.Nil(t, err)
  119. resBody := make([]byte, 5)
  120. _, err = res.Body.Read(resBody)
  121. assert.Equal(t, io.EOF, err)
  122. assert.Equal(t, []byte("hello"), resBody, "response body fail")
  123. return res.Body.Close()
  124. }(context.Background())
  125. assert.Nil(t, err)
  126. })
  127. }
  128. }
  129. func TestTraceHandler_traceResponseWriter(t *testing.T) {
  130. writer := &traceResponseWriter{
  131. w: httptest.NewRecorder(),
  132. }
  133. assert.NotPanics(t, func() {
  134. writer.Hijack()
  135. })
  136. writer = &traceResponseWriter{
  137. w: mockedHijackable{httptest.NewRecorder()},
  138. }
  139. assert.NotPanics(t, func() {
  140. writer.Hijack()
  141. })
  142. writer = &traceResponseWriter{
  143. w: httptest.NewRecorder(),
  144. }
  145. writer.WriteHeader(http.StatusBadRequest)
  146. assert.NotNil(t, writer.Header())
  147. writer = &traceResponseWriter{
  148. w: httptest.NewRecorder(),
  149. }
  150. assert.NotPanics(t, func() {
  151. writer.Flush()
  152. })
  153. writer = &traceResponseWriter{
  154. w: mockedFlusher{httptest.NewRecorder()},
  155. }
  156. assert.NotPanics(t, func() {
  157. writer.Flush()
  158. })
  159. }
  160. type mockedFlusher struct {
  161. *httptest.ResponseRecorder
  162. }
  163. func (m mockedFlusher) Flush() {
  164. }