github.com/blend/go-sdk@v1.20240719.1/tracing/webtrace/tracer_test.go (about) 1 /* 2 3 Copyright (c) 2024 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package webtrace 9 10 import ( 11 "bytes" 12 "fmt" 13 "net/http" 14 "testing" 15 16 opentracing "github.com/opentracing/opentracing-go" 17 opentracingExt "github.com/opentracing/opentracing-go/ext" 18 "github.com/opentracing/opentracing-go/mocktracer" 19 20 "github.com/blend/go-sdk/assert" 21 "github.com/blend/go-sdk/logger" 22 "github.com/blend/go-sdk/tracing" 23 "github.com/blend/go-sdk/web" 24 ) 25 26 func TestStart(t *testing.T) { 27 assert := assert.New(t) 28 mockTracer := mocktracer.New() 29 webTracer := Tracer(mockTracer) 30 31 ctx := web.MockCtx("GET", "/test-resource") 32 _ = webTracer.Start(ctx) 33 34 span := opentracing.SpanFromContext(ctx.Context()) 35 mockSpan := span.(*mocktracer.MockSpan) 36 assert.Equal(tracing.OperationHTTPRequest, mockSpan.OperationName) 37 38 assert.Len(mockSpan.Tags(), 9) 39 assert.Equal(opentracingExt.SpanKindRPCServerEnum, mockSpan.Tags()[string(opentracingExt.SpanKind)]) 40 assert.Equal("GET /test-resource", mockSpan.Tags()[tracing.TagKeyResourceName]) 41 assert.Equal(tracing.SpanTypeWeb, mockSpan.Tags()[tracing.TagKeySpanType]) 42 assert.Equal("GET", mockSpan.Tags()[tracing.TagKeyHTTPMethod]) 43 assert.Equal("/test-resource", mockSpan.Tags()[tracing.TagKeyHTTPURL]) 44 assert.Equal("127.0.0.1", mockSpan.Tags()["http.remote_addr"]) 45 assert.Equal("localhost", mockSpan.Tags()["http.host"]) 46 assert.Equal("go-sdk test", mockSpan.Tags()["http.user_agent"]) 47 assert.True(mockSpan.FinishTime.IsZero()) 48 } 49 50 func TestStartWithRoute(t *testing.T) { 51 assert := assert.New(t) 52 mockTracer := mocktracer.New() 53 webTracer := Tracer(mockTracer) 54 55 ctx := web.MockCtx( 56 "GET", "/test-resource/3", 57 web.OptCtxRoute(&web.Route{Path: "/test-resource/:id"}), 58 ) 59 _ = webTracer.Start(ctx) 60 61 span := opentracing.SpanFromContext(ctx.Context()) 62 mockSpan := span.(*mocktracer.MockSpan) 63 assert.Equal(tracing.OperationHTTPRequest, mockSpan.OperationName) 64 65 assert.Len(mockSpan.Tags(), 10) 66 assert.Equal("GET /test-resource/:id", mockSpan.Tags()[tracing.TagKeyResourceName]) 67 assert.Equal(tracing.SpanTypeWeb, mockSpan.Tags()[tracing.TagKeySpanType]) 68 assert.Equal(opentracingExt.SpanKindRPCServerEnum, mockSpan.Tags()[string(opentracingExt.SpanKind)]) 69 assert.Equal("GET", mockSpan.Tags()[tracing.TagKeyHTTPMethod]) 70 assert.Equal("/test-resource/3", mockSpan.Tags()[tracing.TagKeyHTTPURL]) 71 assert.Equal("127.0.0.1", mockSpan.Tags()["http.remote_addr"]) 72 assert.Equal("localhost", mockSpan.Tags()["http.host"]) 73 assert.Equal("go-sdk test", mockSpan.Tags()["http.user_agent"]) 74 assert.Equal("/test-resource/:id", mockSpan.Tags()["http.route"]) 75 assert.True(mockSpan.FinishTime.IsZero()) 76 } 77 78 func TestStartAndFinishWithRouteIncludingLabelsFalse(t *testing.T) { 79 assert := assert.New(t) 80 mockTracer := mocktracer.New() 81 webTracer := Tracer(mockTracer, OptIncludeCtxLabels(false)) 82 83 logBuffer := bytes.NewBuffer([]byte{}) 84 ctx := web.MockCtx( 85 "GET", "/test-resource/3", 86 web.OptCtxRoute(&web.Route{Path: "/test-resource/:id"}), 87 web.OptCtxLog(logger.Memory(logBuffer)), 88 ) 89 ctx.Response.WriteHeader(http.StatusOK) 90 91 ctx.WithContext(logger.WithLabel(ctx.Context(), "foo", "bar")) 92 labelValue, labelFound := logger.GetLabel(ctx.Context(), "foo") 93 assert.True(labelFound) 94 assert.Equal("bar", labelValue) 95 wt := webTracer.Start(ctx) 96 wt.Finish(ctx, nil) 97 span := opentracing.SpanFromContext(ctx.Context()) 98 mockSpan := span.(*mocktracer.MockSpan) 99 assert.Equal(tracing.OperationHTTPRequest, mockSpan.OperationName) 100 101 assert.Len(mockSpan.Tags(), 11) 102 assert.Equal("GET /test-resource/:id", mockSpan.Tags()[tracing.TagKeyResourceName]) 103 assert.Equal(tracing.SpanTypeWeb, mockSpan.Tags()[tracing.TagKeySpanType]) 104 assert.Equal(opentracingExt.SpanKindRPCServerEnum, mockSpan.Tags()[string(opentracingExt.SpanKind)]) 105 assert.Equal("GET", mockSpan.Tags()[tracing.TagKeyHTTPMethod]) 106 assert.Equal("/test-resource/3", mockSpan.Tags()[tracing.TagKeyHTTPURL]) 107 assert.Equal("127.0.0.1", mockSpan.Tags()["http.remote_addr"]) 108 assert.Equal("localhost", mockSpan.Tags()["http.host"]) 109 assert.Equal("go-sdk test", mockSpan.Tags()["http.user_agent"]) 110 assert.Equal("/test-resource/:id", mockSpan.Tags()["http.route"]) 111 assert.Equal("200", mockSpan.Tags()[tracing.TagKeyHTTPCode]) 112 assert.False(mockSpan.FinishTime.IsZero()) 113 } 114 115 func TestStartAndFinishWithRouteIncludingLabelsTrue(t *testing.T) { 116 assert := assert.New(t) 117 mockTracer := mocktracer.New() 118 webTracer := Tracer(mockTracer, OptIncludeCtxLabels(true)) 119 120 logBuffer := bytes.NewBuffer([]byte{}) 121 ctx := web.MockCtx( 122 "GET", "/test-resource/3", 123 web.OptCtxRoute(&web.Route{Path: "/test-resource/:id"}), 124 web.OptCtxLog(logger.Memory(logBuffer)), 125 ) 126 ctx.Response.WriteHeader(http.StatusOK) 127 128 ctx.WithContext(logger.WithLabel(ctx.Context(), "foo", "bar")) 129 labelValue, labelFound := logger.GetLabel(ctx.Context(), "foo") 130 assert.True(labelFound) 131 assert.Equal("bar", labelValue) 132 133 wt := webTracer.Start(ctx) 134 wt.Finish(ctx, nil) 135 span := opentracing.SpanFromContext(ctx.Context()) 136 mockSpan := span.(*mocktracer.MockSpan) 137 assert.Equal(tracing.OperationHTTPRequest, mockSpan.OperationName) 138 139 assert.Len(mockSpan.Tags(), 13) 140 assert.Equal("GET /test-resource/:id", mockSpan.Tags()[tracing.TagKeyResourceName]) 141 assert.Equal(tracing.SpanTypeWeb, mockSpan.Tags()[tracing.TagKeySpanType]) 142 assert.Equal(opentracingExt.SpanKindRPCServerEnum, mockSpan.Tags()[string(opentracingExt.SpanKind)]) 143 assert.Equal("GET", mockSpan.Tags()[tracing.TagKeyHTTPMethod]) 144 assert.Equal("/test-resource/3", mockSpan.Tags()[tracing.TagKeyHTTPURL]) 145 assert.Equal("127.0.0.1", mockSpan.Tags()["http.remote_addr"]) 146 assert.Equal("localhost", mockSpan.Tags()["http.host"]) 147 assert.Equal("go-sdk test", mockSpan.Tags()["http.user_agent"]) 148 assert.Equal("/test-resource/:id", mockSpan.Tags()["http.route"]) 149 assert.Equal("200", mockSpan.Tags()[tracing.TagKeyHTTPCode]) 150 assert.Equal("bar", mockSpan.Tags()[fmt.Sprintf("%s.foo", tracing.TagKeyCtx)]) 151 assert.Equal("/test-resource/:id", mockSpan.Tags()[fmt.Sprintf("%s.web.route", tracing.TagKeyCtx)]) 152 assert.False(mockSpan.FinishTime.IsZero()) 153 } 154 155 func optCtxIncomingSpan(t opentracing.Tracer, s opentracing.Span) web.CtxOption { 156 return func(c *web.Ctx) { 157 _ = t.Inject( 158 s.Context(), 159 opentracing.HTTPHeaders, 160 opentracing.HTTPHeadersCarrier(c.Request.Header), 161 ) 162 } 163 } 164 165 func TestStartWithParentSpan(t *testing.T) { 166 assert := assert.New(t) 167 mockTracer := mocktracer.New() 168 webTracer := Tracer(mockTracer) 169 170 parentSpan := mockTracer.StartSpan("test_op") 171 ctx := web.MockCtx( 172 "GET", "/test-resource", 173 optCtxIncomingSpan(mockTracer, parentSpan), 174 ) 175 _ = webTracer.Start(ctx) 176 177 span := opentracing.SpanFromContext(ctx.Context()) 178 mockSpan := span.(*mocktracer.MockSpan) 179 assert.Equal(tracing.OperationHTTPRequest, mockSpan.OperationName) 180 181 mockParentSpan := parentSpan.(*mocktracer.MockSpan) 182 assert.Equal(mockSpan.ParentID, mockParentSpan.SpanContext.SpanID) 183 } 184 185 func TestFinish(t *testing.T) { 186 assert := assert.New(t) 187 mockTracer := mocktracer.New() 188 webTracer := Tracer(mockTracer) 189 190 ctx := web.MockCtx("GET", "/test-resource") 191 tf := webTracer.Start(ctx) 192 193 result := web.Raw([]byte("success")) 194 assert.Nil(result.Render(ctx)) 195 196 tf.Finish(ctx, nil) 197 198 span := opentracing.SpanFromContext(ctx.Context()) 199 mockSpan := span.(*mocktracer.MockSpan) 200 assert.Equal("200", mockSpan.Tags()[tracing.TagKeyHTTPCode]) 201 assert.False(mockSpan.FinishTime.IsZero()) 202 } 203 204 func TestFinishError(t *testing.T) { 205 assert := assert.New(t) 206 mockTracer := mocktracer.New() 207 webTracer := Tracer(mockTracer) 208 209 ctx := web.MockCtx("GET", "/test-resource") 210 tf := webTracer.Start(ctx) 211 212 result := web.Raw([]byte("success")) 213 result.StatusCode = 500 214 assert.Nil(result.Render(ctx)) 215 216 tf.Finish(ctx, fmt.Errorf("error")) 217 218 span := opentracing.SpanFromContext(ctx.Context()) 219 mockSpan := span.(*mocktracer.MockSpan) 220 assert.Equal("500", mockSpan.Tags()[tracing.TagKeyHTTPCode]) 221 assert.Equal("error", mockSpan.Tags()[tracing.TagKeyError]) 222 assert.False(mockSpan.FinishTime.IsZero()) 223 } 224 225 func TestFinishNilSpan(t *testing.T) { 226 assert := assert.New(t) 227 228 ctx := web.MockCtx("GET", "/test-resource") 229 webTraceFinisher{}.Finish(ctx, nil) 230 assert.Nil(opentracing.SpanFromContext(ctx.Context())) 231 } 232 233 func TestStartView(t *testing.T) { 234 assert := assert.New(t) 235 mockTracer := mocktracer.New() 236 webViewTracer := Tracer(mockTracer).(web.ViewTracer) 237 238 ctx := web.MockCtx("GET", "/test-resource") 239 viewResult := &web.ViewResult{ 240 ViewName: "test_view", 241 StatusCode: 200, 242 } 243 wvtf := webViewTracer.StartView(ctx, viewResult) 244 span := wvtf.(*webViewTraceFinisher).span 245 mockSpan := span.(*mocktracer.MockSpan) 246 assert.Equal(tracing.OperationHTTPRender, mockSpan.OperationName) 247 248 assert.Len(mockSpan.Tags(), 4) 249 assert.Equal("test_view", mockSpan.Tags()[tracing.TagKeyResourceName]) 250 assert.Equal(tracing.SpanTypeWeb, mockSpan.Tags()[tracing.TagKeySpanType]) 251 assert.Equal(opentracingExt.SpanKindRPCServerEnum, mockSpan.Tags()[string(opentracingExt.SpanKind)]) 252 assert.True(mockSpan.FinishTime.IsZero()) 253 } 254 255 func TestStartViewWithParentSpan(t *testing.T) { 256 assert := assert.New(t) 257 mockTracer := mocktracer.New() 258 webViewTracer := Tracer(mockTracer).(web.ViewTracer) 259 260 parentSpan := mockTracer.StartSpan("test_op") 261 ctx := web.MockCtx("GET", "/test-resource") 262 ctx.WithContext(opentracing.ContextWithSpan(ctx.Context(), parentSpan)) 263 viewResult := &web.ViewResult{ 264 ViewName: "test_view", 265 StatusCode: 200, 266 } 267 wvtf := webViewTracer.StartView(ctx, viewResult) 268 span := wvtf.(*webViewTraceFinisher).span 269 mockSpan := span.(*mocktracer.MockSpan) 270 assert.Equal(tracing.OperationHTTPRender, mockSpan.OperationName) 271 272 mockParentSpan := parentSpan.(*mocktracer.MockSpan) 273 assert.Equal(mockSpan.ParentID, mockParentSpan.SpanContext.SpanID) 274 } 275 276 func TestFinishView(t *testing.T) { 277 assert := assert.New(t) 278 mockTracer := mocktracer.New() 279 webViewTracer := Tracer(mockTracer).(web.ViewTracer) 280 281 ctx := web.MockCtx("GET", "/test-resource") 282 viewResult := &web.ViewResult{ 283 ViewName: "test_view", 284 StatusCode: 200, 285 } 286 wvtf := webViewTracer.StartView(ctx, viewResult) 287 wvtf.FinishView(ctx, viewResult, nil) 288 289 span := wvtf.(*webViewTraceFinisher).span 290 mockSpan := span.(*mocktracer.MockSpan) 291 292 assert.Nil(mockSpan.Tags()[tracing.TagKeyError]) 293 assert.False(mockSpan.FinishTime.IsZero()) 294 } 295 296 func TestFinishViewNilSpan(t *testing.T) { 297 assert := assert.New(t) 298 299 ctx := web.MockCtx("GET", "/test-resource") 300 webViewTraceFinisher{}.FinishView(ctx, nil, nil) 301 assert.Nil(opentracing.SpanFromContext(ctx.Context())) 302 }