1 package opentracing_test
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "reflect"
8 "testing"
9 "time"
10
11 "github.com/opentracing/opentracing-go"
12 otext "github.com/opentracing/opentracing-go/ext"
13 otlog "github.com/opentracing/opentracing-go/log"
14 "github.com/opentracing/opentracing-go/mocktracer"
15
16 "github.com/go-kit/kit/endpoint"
17 "github.com/go-kit/kit/sd"
18 "github.com/go-kit/kit/sd/lb"
19 kitot "github.com/go-kit/kit/tracing/opentracing"
20 )
21
22 const (
23 span1 = "SPAN-1"
24 span2 = "SPAN-2"
25 span3 = "SPAN-3"
26 span4 = "SPAN-4"
27 span5 = "SPAN-5"
28 span6 = "SPAN-6"
29 span7 = "SPAN-7"
30 span8 = "SPAN-8"
31 )
32
33 var (
34 err1 = errors.New("some error")
35 err2 = errors.New("some business error")
36 err3 = errors.New("other business error")
37 )
38
39
40 var _ endpoint.Failer = failedResponse{}
41
42 type failedResponse struct {
43 err error
44 }
45
46 func (r failedResponse) Failed() error {
47 return r.err
48 }
49
50 func TestTraceEndpoint(t *testing.T) {
51 tracer := mocktracer.New()
52
53
54 parentSpan := tracer.StartSpan("parent").(*mocktracer.MockSpan)
55 defer parentSpan.Finish()
56 ctx := opentracing.ContextWithSpan(context.Background(), parentSpan)
57
58 tracedEndpoint := kitot.TraceEndpoint(tracer, "testOp")(endpoint.Nop)
59 if _, err := tracedEndpoint(ctx, struct{}{}); err != nil {
60 t.Fatal(err)
61 }
62
63
64 finishedSpans := tracer.FinishedSpans()
65 if want, have := 1, len(finishedSpans); want != have {
66 t.Fatalf("Want %v span(s), found %v", want, have)
67 }
68
69 endpointSpan := finishedSpans[0]
70 if want, have := "testOp", endpointSpan.OperationName; want != have {
71 t.Fatalf("Want %q, have %q", want, have)
72 }
73
74 parentContext := parentSpan.Context().(mocktracer.MockSpanContext)
75 endpointContext := parentSpan.Context().(mocktracer.MockSpanContext)
76
77
78 if want, have := parentContext.SpanID, endpointContext.SpanID; want != have {
79 t.Errorf("Want ParentID %q, have %q", want, have)
80 }
81 }
82
83 func TestTraceEndpointNoContextSpan(t *testing.T) {
84 tracer := mocktracer.New()
85
86
87 tracedEndpoint := kitot.TraceEndpoint(tracer, "testOp")(endpoint.Nop)
88 if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
89 t.Fatal(err)
90 }
91
92
93 finishedSpans := tracer.FinishedSpans()
94 if want, have := 1, len(finishedSpans); want != have {
95 t.Fatalf("Want %v span(s), found %v", want, have)
96 }
97
98 endpointSpan := finishedSpans[0]
99
100 if want, have := "testOp", endpointSpan.OperationName; want != have {
101 t.Fatalf("Want %q, have %q", want, have)
102 }
103 }
104
105 func TestTraceEndpointWithOptions(t *testing.T) {
106 tracer := mocktracer.New()
107
108
109 mw := kitot.TraceEndpoint(tracer, span1)
110 tracedEndpoint := mw(endpoint.Nop)
111 _, _ = tracedEndpoint(context.Background(), struct{}{})
112
113
114 mw = kitot.TraceEndpoint(
115 tracer,
116 span2,
117 kitot.WithOptions(kitot.EndpointOptions{}),
118 )
119 tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
120 return nil, err1
121 })
122 _, _ = tracedEndpoint(context.Background(), struct{}{})
123
124
125 mw = kitot.TraceEndpoint(
126 tracer,
127 span3,
128 kitot.WithOptions(kitot.EndpointOptions{}),
129 )
130 tracedEndpoint = mw(
131 lb.Retry(
132 5,
133 1*time.Second,
134 lb.NewRoundRobin(
135 sd.FixedEndpointer{
136 func(context.Context, interface{}) (interface{}, error) {
137 return nil, err1
138 },
139 },
140 ),
141 ),
142 )
143 _, _ = tracedEndpoint(context.Background(), struct{}{})
144
145
146 mw = kitot.TraceEndpoint(
147 tracer,
148 span4,
149 kitot.WithIgnoreBusinessError(false),
150 )
151 tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
152 return failedResponse{
153 err: err2,
154 }, nil
155 })
156 _, _ = tracedEndpoint(context.Background(), struct{}{})
157
158
159 mw = kitot.TraceEndpoint(tracer, span5, kitot.WithIgnoreBusinessError(true))
160 tracedEndpoint = mw(func(context.Context, interface{}) (interface{}, error) {
161 return failedResponse{
162 err: err3,
163 }, nil
164 })
165 _, _ = tracedEndpoint(context.Background(), struct{}{})
166
167
168 mw = kitot.TraceEndpoint(
169 tracer,
170 span6,
171 kitot.WithOperationNameFunc(func(ctx context.Context, name string) string {
172 return fmt.Sprintf("%s-%s", "new", name)
173 }),
174 )
175 tracedEndpoint = mw(endpoint.Nop)
176 _, _ = tracedEndpoint(context.Background(), struct{}{})
177
178
179 mw = kitot.TraceEndpoint(
180 tracer,
181 span7,
182 kitot.WithTags(map[string]interface{}{
183 "tag1": "tag1",
184 "tag2": "tag2",
185 }),
186 kitot.WithTags(map[string]interface{}{
187 "tag3": "tag3",
188 }),
189 )
190 tracedEndpoint = mw(endpoint.Nop)
191 _, _ = tracedEndpoint(context.Background(), struct{}{})
192
193
194 mw = kitot.TraceEndpoint(
195 tracer,
196 span8,
197 kitot.WithTags(map[string]interface{}{
198 "tag1": "tag1",
199 "tag2": "tag2",
200 }),
201 kitot.WithTags(map[string]interface{}{
202 "tag3": "tag3",
203 }),
204 kitot.WithTagsFunc(func(ctx context.Context) opentracing.Tags {
205 return map[string]interface{}{
206 "tag4": "tag4",
207 }
208 }),
209 )
210 tracedEndpoint = mw(endpoint.Nop)
211 _, _ = tracedEndpoint(context.Background(), struct{}{})
212
213 finishedSpans := tracer.FinishedSpans()
214 if want, have := 8, len(finishedSpans); want != have {
215 t.Fatalf("Want %v span(s), found %v", want, have)
216 }
217
218
219 span := finishedSpans[0]
220
221 if want, have := span1, span.OperationName; want != have {
222 t.Fatalf("Want %q, have %q", want, have)
223 }
224
225
226 span = finishedSpans[1]
227
228 if want, have := span2, span.OperationName; want != have {
229 t.Fatalf("Want %q, have %q", want, have)
230 }
231
232 if want, have := true, span.Tag("error"); want != have {
233 t.Fatalf("Want %v, have %v", want, have)
234 }
235
236
237 span = finishedSpans[2]
238
239 if want, have := span3, span.OperationName; want != have {
240 t.Fatalf("Want %q, have %q", want, have)
241 }
242
243 if want, have := true, span.Tag("error"); want != have {
244 t.Fatalf("Want %v, have %v", want, have)
245 }
246
247 if want, have := 1, len(span.Logs()); want != have {
248 t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
249 }
250
251 if want, have := []otlog.Field{
252 otlog.String("event", "error"),
253 otlog.String("error.object", "some error (previously: some error; some error; some error; some error)"),
254 otlog.String("gokit.retry.error.1", "some error"),
255 otlog.String("gokit.retry.error.2", "some error"),
256 otlog.String("gokit.retry.error.3", "some error"),
257 otlog.String("gokit.retry.error.4", "some error"),
258 otlog.String("gokit.retry.error.5", "some error"),
259 }, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
260 t.Fatalf("Want %q, have %q", want, have)
261 }
262
263
264 span = finishedSpans[3]
265
266 if want, have := span4, span.OperationName; want != have {
267 t.Fatalf("Want %q, have %q", want, have)
268 }
269
270 if want, have := true, span.Tag("error"); want != have {
271 t.Fatalf("Want %v, have %v", want, have)
272 }
273
274 if want, have := 2, len(span.Logs()); want != have {
275 t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
276 }
277
278 if want, have := []otlog.Field{
279 otlog.String("gokit.business.error", "some business error"),
280 }, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
281 t.Fatalf("Want %q, have %q", want, have)
282 }
283
284 if want, have := []otlog.Field{
285 otlog.String("event", "error"),
286 otlog.String("error.object", "some business error"),
287 }, span.Logs()[1].Fields; reflect.DeepEqual(want, have) {
288 t.Fatalf("Want %q, have %q", want, have)
289 }
290
291
292 span = finishedSpans[4]
293
294 if want, have := span5, span.OperationName; want != have {
295 t.Fatalf("Want %q, have %q", want, have)
296 }
297
298 if want, have := (interface{})(nil), span.Tag("error"); want != have {
299 t.Fatalf("Want %q, have %q", want, have)
300 }
301
302 if want, have := 1, len(span.Logs()); want != have {
303 t.Fatalf("incorrect logs count, wanted %d, got %d", want, have)
304 }
305
306 if want, have := []otlog.Field{
307 otlog.String("gokit.business.error", "some business error"),
308 }, span.Logs()[0].Fields; reflect.DeepEqual(want, have) {
309 t.Fatalf("Want %q, have %q", want, have)
310 }
311
312
313 span = finishedSpans[5]
314
315 if want, have := fmt.Sprintf("%s-%s", "new", span6), span.OperationName; want != have {
316 t.Fatalf("Want %q, have %q", want, have)
317 }
318
319
320 span = finishedSpans[6]
321
322 if want, have := span7, span.OperationName; want != have {
323 t.Fatalf("Want %q, have %q", want, have)
324 }
325
326 if want, have := map[string]interface{}{
327 "tag1": "tag1",
328 "tag2": "tag2",
329 "tag3": "tag3",
330 }, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
331 t.Fatalf("Want %q, have %q", want, have)
332 }
333
334
335 span = finishedSpans[7]
336
337 if want, have := span8, span.OperationName; want != have {
338 t.Fatalf("Want %q, have %q", want, have)
339 }
340
341 if want, have := map[string]interface{}{
342 "tag1": "tag1",
343 "tag2": "tag2",
344 "tag3": "tag3",
345 "tag4": "tag4",
346 }, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
347 t.Fatalf("Want %q, have %q", want, have)
348 }
349 }
350
351 func TestTraceServer(t *testing.T) {
352 tracer := mocktracer.New()
353
354
355 tracedEndpoint := kitot.TraceServer(tracer, "testOp")(endpoint.Nop)
356 if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
357 t.Fatal(err)
358 }
359
360
361 finishedSpans := tracer.FinishedSpans()
362 if want, have := 1, len(finishedSpans); want != have {
363 t.Fatalf("Want %v span(s), found %v", want, have)
364 }
365
366 span := finishedSpans[0]
367
368 if want, have := "testOp", span.OperationName; want != have {
369 t.Fatalf("Want %q, have %q", want, have)
370 }
371
372 if want, have := map[string]interface{}{
373 otext.SpanKindRPCServer.Key: otext.SpanKindRPCServer.Value,
374 }, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
375 t.Fatalf("Want %q, have %q", want, have)
376 }
377 }
378
379 func TestTraceClient(t *testing.T) {
380 tracer := mocktracer.New()
381
382
383 tracedEndpoint := kitot.TraceClient(tracer, "testOp")(endpoint.Nop)
384 if _, err := tracedEndpoint(context.Background(), struct{}{}); err != nil {
385 t.Fatal(err)
386 }
387
388
389 finishedSpans := tracer.FinishedSpans()
390 if want, have := 1, len(finishedSpans); want != have {
391 t.Fatalf("Want %v span(s), found %v", want, have)
392 }
393
394 span := finishedSpans[0]
395
396 if want, have := "testOp", span.OperationName; want != have {
397 t.Fatalf("Want %q, have %q", want, have)
398 }
399
400 if want, have := map[string]interface{}{
401 otext.SpanKindRPCClient.Key: otext.SpanKindRPCClient.Value,
402 }, span.Tags(); fmt.Sprint(want) != fmt.Sprint(have) {
403 t.Fatalf("Want %q, have %q", want, have)
404 }
405 }
406
View as plain text