1// Unless explicitly stated otherwise all files in this repository are licensed 2// under the Apache License Version 2.0. 3// This product includes software developed at Datadog (https://www.datadoghq.com/). 4// Copyright 2016 Datadog, Inc. 5 6package http 7 8import ( 9 "net/http" 10 "net/http/httptest" 11 "testing" 12 13 "github.com/stretchr/testify/assert" 14 "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" 15 "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/mocktracer" 16 "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" 17 "gopkg.in/DataDog/dd-trace-go.v1/internal/globalconfig" 18) 19 20func TestHttpTracer200(t *testing.T) { 21 mt := mocktracer.Start() 22 defer mt.Stop() 23 24 url := "/200" 25 r := httptest.NewRequest("GET", url, nil) 26 w := httptest.NewRecorder() 27 router().ServeHTTP(w, r) 28 29 assert := assert.New(t) 30 assert.Equal(200, w.Code) 31 assert.Equal("OK\n", w.Body.String()) 32 33 spans := mt.FinishedSpans() 34 assert.Equal(1, len(spans)) 35 36 s := spans[0] 37 assert.Equal("http.request", s.OperationName()) 38 assert.Equal("my-service", s.Tag(ext.ServiceName)) 39 assert.Equal("GET "+url, s.Tag(ext.ResourceName)) 40 assert.Equal("200", s.Tag(ext.HTTPCode)) 41 assert.Equal("GET", s.Tag(ext.HTTPMethod)) 42 assert.Equal(url, s.Tag(ext.HTTPURL)) 43 assert.Equal(nil, s.Tag(ext.Error)) 44 assert.Equal("bar", s.Tag("foo")) 45} 46 47func TestHttpTracer500(t *testing.T) { 48 mt := mocktracer.Start() 49 defer mt.Stop() 50 51 // Send and verify a 500 request 52 url := "/500" 53 r := httptest.NewRequest("GET", url, nil) 54 w := httptest.NewRecorder() 55 router().ServeHTTP(w, r) 56 57 assert := assert.New(t) 58 assert.Equal(500, w.Code) 59 assert.Equal("500!\n", w.Body.String()) 60 61 spans := mt.FinishedSpans() 62 assert.Equal(1, len(spans)) 63 64 s := spans[0] 65 assert.Equal("http.request", s.OperationName()) 66 assert.Equal("my-service", s.Tag(ext.ServiceName)) 67 assert.Equal("GET "+url, s.Tag(ext.ResourceName)) 68 assert.Equal("500", s.Tag(ext.HTTPCode)) 69 assert.Equal("GET", s.Tag(ext.HTTPMethod)) 70 assert.Equal(url, s.Tag(ext.HTTPURL)) 71 assert.Equal("500: Internal Server Error", s.Tag(ext.Error).(error).Error()) 72 assert.Equal("bar", s.Tag("foo")) 73} 74 75func TestWrapHandler200(t *testing.T) { 76 mt := mocktracer.Start() 77 defer mt.Stop() 78 assert := assert.New(t) 79 80 handler := WrapHandler(http.HandlerFunc(handler200), "my-service", "my-resource", 81 WithSpanOptions(tracer.Tag("foo", "bar")), 82 ) 83 84 url := "/" 85 r := httptest.NewRequest("GET", url, nil) 86 w := httptest.NewRecorder() 87 handler.ServeHTTP(w, r) 88 assert.Equal(200, w.Code) 89 assert.Equal("OK\n", w.Body.String()) 90 91 spans := mt.FinishedSpans() 92 assert.Equal(1, len(spans)) 93 94 s := spans[0] 95 assert.Equal("http.request", s.OperationName()) 96 assert.Equal("my-service", s.Tag(ext.ServiceName)) 97 assert.Equal("my-resource", s.Tag(ext.ResourceName)) 98 assert.Equal("200", s.Tag(ext.HTTPCode)) 99 assert.Equal("GET", s.Tag(ext.HTTPMethod)) 100 assert.Equal(url, s.Tag(ext.HTTPURL)) 101 assert.Equal(nil, s.Tag(ext.Error)) 102 assert.Equal("bar", s.Tag("foo")) 103} 104 105func TestNoStack(t *testing.T) { 106 mt := mocktracer.Start() 107 defer mt.Stop() 108 assert := assert.New(t) 109 110 handler := WrapHandler(http.HandlerFunc(handler500), "my-service", "my-resource", 111 NoDebugStack()) 112 113 r := httptest.NewRequest("GET", "/", nil) 114 w := httptest.NewRecorder() 115 handler.ServeHTTP(w, r) 116 assert.Equal(http.StatusInternalServerError, w.Code) 117 assert.Equal("500!\n", w.Body.String()) 118 119 spans := mt.FinishedSpans() 120 assert.Equal(1, len(spans)) 121 s := spans[0] 122 assert.EqualError(spans[0].Tags()[ext.Error].(error), "500: Internal Server Error") 123 assert.Equal("<debug stack disabled>", s.Tags()[ext.ErrorStack]) 124 125} 126 127func TestAnalyticsSettings(t *testing.T) { 128 tests := map[string]func(t *testing.T, mt mocktracer.Tracer, rate interface{}, opts ...Option){ 129 "ServeMux": func(t *testing.T, mt mocktracer.Tracer, rate interface{}, opts ...Option) { 130 mux := NewServeMux(opts...) 131 mux.HandleFunc("/200", handler200) 132 r := httptest.NewRequest("GET", "/200", nil) 133 w := httptest.NewRecorder() 134 mux.ServeHTTP(w, r) 135 136 spans := mt.FinishedSpans() 137 assert.Len(t, spans, 1) 138 s := spans[0] 139 assert.Equal(t, rate, s.Tag(ext.EventSampleRate)) 140 }, 141 "WrapHandler": func(t *testing.T, mt mocktracer.Tracer, rate interface{}, opts ...Option) { 142 f := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 143 message := "Hello \n" 144 w.Write([]byte(message)) 145 }) 146 handler := WrapHandler(f, "my-service", "my-resource", opts...) 147 r := httptest.NewRequest("GET", "/200", nil) 148 w := httptest.NewRecorder() 149 handler.ServeHTTP(w, r) 150 151 spans := mt.FinishedSpans() 152 assert.Len(t, spans, 1) 153 s := spans[0] 154 assert.Equal(t, rate, s.Tag(ext.EventSampleRate)) 155 }, 156 } 157 158 for name, test := range tests { 159 t.Run("defaults/"+name, func(t *testing.T) { 160 mt := mocktracer.Start() 161 defer mt.Stop() 162 163 test(t, mt, nil) 164 }) 165 166 t.Run("global/"+name, func(t *testing.T) { 167 mt := mocktracer.Start() 168 defer mt.Stop() 169 170 rate := globalconfig.AnalyticsRate() 171 defer globalconfig.SetAnalyticsRate(rate) 172 globalconfig.SetAnalyticsRate(0.4) 173 174 test(t, mt, 0.4) 175 }) 176 177 t.Run("enabled/"+name, func(t *testing.T) { 178 mt := mocktracer.Start() 179 defer mt.Stop() 180 181 test(t, mt, 1.0, WithAnalytics(true)) 182 }) 183 184 t.Run("disabled/"+name, func(t *testing.T) { 185 mt := mocktracer.Start() 186 defer mt.Stop() 187 188 test(t, mt, nil, WithAnalytics(false)) 189 }) 190 191 t.Run("override/"+name, func(t *testing.T) { 192 mt := mocktracer.Start() 193 defer mt.Stop() 194 195 rate := globalconfig.AnalyticsRate() 196 defer globalconfig.SetAnalyticsRate(rate) 197 globalconfig.SetAnalyticsRate(0.4) 198 199 test(t, mt, 0.23, WithAnalyticsRate(0.23)) 200 }) 201 } 202} 203 204func router() http.Handler { 205 mux := NewServeMux(WithServiceName("my-service"), WithSpanOptions(tracer.Tag("foo", "bar"))) 206 mux.HandleFunc("/200", handler200) 207 mux.HandleFunc("/500", handler500) 208 return mux 209} 210 211func handler200(w http.ResponseWriter, r *http.Request) { 212 w.Write([]byte("OK\n")) 213} 214 215func handler500(w http.ResponseWriter, r *http.Request) { 216 http.Error(w, "500!", http.StatusInternalServerError) 217} 218