1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package trace
16
17 import (
18 "context"
19 "fmt"
20 "reflect"
21 "sync/atomic"
22 "testing"
23 "time"
24
25 "go.opencensus.io/trace/tracestate"
26 )
27
28 var (
29 tid = TraceID{1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 4, 8, 16, 32, 64, 128}
30 sid = SpanID{1, 2, 4, 8, 16, 32, 64, 128}
31 testTracestate, _ = tracestate.New(nil, tracestate.Entry{Key: "foo", Value: "bar"})
32 )
33
34 func init() {
35
36 ApplyConfig(Config{DefaultSampler: ProbabilitySampler(0)})
37 }
38
39 func TestStrings(t *testing.T) {
40 if got, want := tid.String(), "01020304050607080102040810204080"; got != want {
41 t.Errorf("TraceID.String: got %q want %q", got, want)
42 }
43 if got, want := sid.String(), "0102040810204080"; got != want {
44 t.Errorf("SpanID.String: got %q want %q", got, want)
45 }
46 }
47
48 func TestFromContext(t *testing.T) {
49 want := &Span{}
50 ctx := NewContext(context.Background(), want)
51 got := FromContext(ctx)
52 if got != want {
53 t.Errorf("got Span pointer %p want %p", got, want)
54 }
55 }
56
57 type foo int
58
59 func (f foo) String() string {
60 return "foo"
61 }
62
63
64 func checkChild(p SpanContext, c *Span) error {
65 if c == nil {
66 return fmt.Errorf("got nil child span, want non-nil")
67 }
68 if got, want := c.SpanContext().TraceID, p.TraceID; got != want {
69 return fmt.Errorf("got child trace ID %s, want %s", got, want)
70 }
71 if childID, parentID := c.SpanContext().SpanID, p.SpanID; childID == parentID {
72 return fmt.Errorf("got child span ID %s, parent span ID %s; want unequal IDs", childID, parentID)
73 }
74 if got, want := c.SpanContext().TraceOptions, p.TraceOptions; got != want {
75 return fmt.Errorf("got child trace options %d, want %d", got, want)
76 }
77 if got, want := c.SpanContext().Tracestate, p.Tracestate; got != want {
78 return fmt.Errorf("got child tracestate %v, want %v", got, want)
79 }
80 return nil
81 }
82
83 func TestStartSpan(t *testing.T) {
84 ctx, _ := StartSpan(context.Background(), "StartSpan")
85 s := FromContext(ctx).internal.(*span)
86 if s.data != nil {
87 t.Error("StartSpan: new span is recording events")
88 }
89 }
90
91 func TestSampling(t *testing.T) {
92 for _, test := range []struct {
93 remoteParent bool
94 localParent bool
95 parentTraceOptions TraceOptions
96 sampler Sampler
97 wantTraceOptions TraceOptions
98 }{
99 {true, false, 0, nil, 0},
100 {true, false, 1, nil, 1},
101 {true, false, 0, NeverSample(), 0},
102 {true, false, 1, NeverSample(), 0},
103 {true, false, 0, AlwaysSample(), 1},
104 {true, false, 1, AlwaysSample(), 1},
105 {false, true, 0, NeverSample(), 0},
106 {false, true, 1, NeverSample(), 0},
107 {false, true, 0, AlwaysSample(), 1},
108 {false, true, 1, AlwaysSample(), 1},
109 {false, false, 0, nil, 0},
110 {false, false, 0, NeverSample(), 0},
111 {false, false, 0, AlwaysSample(), 1},
112 } {
113 var ctx context.Context
114 if test.remoteParent {
115 sc := SpanContext{
116 TraceID: tid,
117 SpanID: sid,
118 TraceOptions: test.parentTraceOptions,
119 }
120 ctx, _ = StartSpanWithRemoteParent(context.Background(), "foo", sc, WithSampler(test.sampler))
121 } else if test.localParent {
122 sampler := NeverSample()
123 if test.parentTraceOptions == 1 {
124 sampler = AlwaysSample()
125 }
126 ctx2, _ := StartSpan(context.Background(), "foo", WithSampler(sampler))
127 ctx, _ = StartSpan(ctx2, "foo", WithSampler(test.sampler))
128 } else {
129 ctx, _ = StartSpan(context.Background(), "foo", WithSampler(test.sampler))
130 }
131 sc := FromContext(ctx).SpanContext()
132 if (sc == SpanContext{}) {
133 t.Errorf("case %#v: starting new span: no span in context", test)
134 continue
135 }
136 if sc.SpanID == (SpanID{}) {
137 t.Errorf("case %#v: starting new span: got zero SpanID, want nonzero", test)
138 }
139 if sc.TraceOptions != test.wantTraceOptions {
140 t.Errorf("case %#v: starting new span: got TraceOptions %x, want %x", test, sc.TraceOptions, test.wantTraceOptions)
141 }
142 }
143
144
145 for _, test := range []struct {
146 parentTraceOptions TraceOptions
147 wantTraceOptions TraceOptions
148 }{
149 {0, 0},
150 {0, 0},
151 {1, 1},
152 {1, 1},
153 } {
154 for _, defaultSampler := range []Sampler{
155 NeverSample(),
156 AlwaysSample(),
157 ProbabilitySampler(0),
158 } {
159 ApplyConfig(Config{DefaultSampler: defaultSampler})
160 sampler := NeverSample()
161 if test.parentTraceOptions == 1 {
162 sampler = AlwaysSample()
163 }
164 ctx2, _ := StartSpan(context.Background(), "foo", WithSampler(sampler))
165 ctx, _ := StartSpan(ctx2, "foo")
166 sc := FromContext(ctx).SpanContext()
167 if (sc == SpanContext{}) {
168 t.Errorf("case %#v: starting new child of local span: no span in context", test)
169 continue
170 }
171 if sc.SpanID == (SpanID{}) {
172 t.Errorf("case %#v: starting new child of local span: got zero SpanID, want nonzero", test)
173 }
174 if sc.TraceOptions != test.wantTraceOptions {
175 t.Errorf("case %#v: starting new child of local span: got TraceOptions %x, want %x", test, sc.TraceOptions, test.wantTraceOptions)
176 }
177 }
178 }
179 ApplyConfig(Config{DefaultSampler: ProbabilitySampler(0)})
180 }
181
182 func TestProbabilitySampler(t *testing.T) {
183 exported := 0
184 for i := 0; i < 1000; i++ {
185 _, span := StartSpan(context.Background(), "foo", WithSampler(ProbabilitySampler(0.3)))
186 if span.SpanContext().IsSampled() {
187 exported++
188 }
189 }
190 if exported < 200 || exported > 400 {
191 t.Errorf("got %f%% exported spans, want approximately 30%%", float64(exported)*0.1)
192 }
193 }
194
195 func TestStartSpanWithRemoteParent(t *testing.T) {
196 sc := SpanContext{
197 TraceID: tid,
198 SpanID: sid,
199 TraceOptions: 0x0,
200 }
201 ctx, _ := StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
202 if err := checkChild(sc, FromContext(ctx)); err != nil {
203 t.Error(err)
204 }
205
206 ctx, _ = StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
207 if err := checkChild(sc, FromContext(ctx)); err != nil {
208 t.Error(err)
209 }
210
211 sc = SpanContext{
212 TraceID: tid,
213 SpanID: sid,
214 TraceOptions: 0x1,
215 Tracestate: testTracestate,
216 }
217 ctx, _ = StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
218 if err := checkChild(sc, FromContext(ctx)); err != nil {
219 t.Error(err)
220 }
221
222 ctx, _ = StartSpanWithRemoteParent(context.Background(), "startSpanWithRemoteParent", sc)
223 if err := checkChild(sc, FromContext(ctx)); err != nil {
224 t.Error(err)
225 }
226
227 ctx2, _ := StartSpan(ctx, "StartSpan")
228 parent := FromContext(ctx).SpanContext()
229 if err := checkChild(parent, FromContext(ctx2)); err != nil {
230 t.Error(err)
231 }
232 }
233
234
235 func startSpan(o StartOptions) *Span {
236 _, span := StartSpanWithRemoteParent(context.Background(), "span0",
237 SpanContext{
238 TraceID: tid,
239 SpanID: sid,
240 TraceOptions: 1,
241 },
242 WithSampler(o.Sampler),
243 WithSpanKind(o.SpanKind),
244 )
245 return span
246 }
247
248 type testExporter struct {
249 spans []*SpanData
250 }
251
252 func (t *testExporter) ExportSpan(s *SpanData) {
253 t.spans = append(t.spans, s)
254 }
255
256
257
258
259 func endSpan(span *Span) (*SpanData, error) {
260
261 if !span.IsRecordingEvents() {
262 return nil, fmt.Errorf("IsRecordingEvents: got false, want true")
263 }
264 if !span.SpanContext().IsSampled() {
265 return nil, fmt.Errorf("IsSampled: got false, want true")
266 }
267 var te testExporter
268 RegisterExporter(&te)
269 span.End()
270 UnregisterExporter(&te)
271 if len(te.spans) != 1 {
272 return nil, fmt.Errorf("got exported spans %#v, want one span", te.spans)
273 }
274 got := te.spans[0]
275 if got.SpanContext.SpanID == (SpanID{}) {
276 return nil, fmt.Errorf("exporting span: expected nonzero SpanID")
277 }
278 got.SpanContext.SpanID = SpanID{}
279 if !checkTime(&got.StartTime) {
280 return nil, fmt.Errorf("exporting span: expected nonzero StartTime")
281 }
282 if !checkTime(&got.EndTime) {
283 return nil, fmt.Errorf("exporting span: expected nonzero EndTime")
284 }
285 return got, nil
286 }
287
288
289 func checkTime(x *time.Time) bool {
290 if x.IsZero() {
291 return false
292 }
293 *x = time.Time{}
294 return true
295 }
296
297 func TestSpanKind(t *testing.T) {
298 tests := []struct {
299 name string
300 startOptions StartOptions
301 want *SpanData
302 }{
303 {
304 name: "zero StartOptions",
305 startOptions: StartOptions{},
306 want: &SpanData{
307 SpanContext: SpanContext{
308 TraceID: tid,
309 SpanID: SpanID{},
310 TraceOptions: 0x1,
311 },
312 ParentSpanID: sid,
313 Name: "span0",
314 SpanKind: SpanKindUnspecified,
315 HasRemoteParent: true,
316 },
317 },
318 {
319 name: "client span",
320 startOptions: StartOptions{
321 SpanKind: SpanKindClient,
322 },
323 want: &SpanData{
324 SpanContext: SpanContext{
325 TraceID: tid,
326 SpanID: SpanID{},
327 TraceOptions: 0x1,
328 },
329 ParentSpanID: sid,
330 Name: "span0",
331 SpanKind: SpanKindClient,
332 HasRemoteParent: true,
333 },
334 },
335 {
336 name: "server span",
337 startOptions: StartOptions{
338 SpanKind: SpanKindServer,
339 },
340 want: &SpanData{
341 SpanContext: SpanContext{
342 TraceID: tid,
343 SpanID: SpanID{},
344 TraceOptions: 0x1,
345 },
346 ParentSpanID: sid,
347 Name: "span0",
348 SpanKind: SpanKindServer,
349 HasRemoteParent: true,
350 },
351 },
352 }
353
354 for _, tt := range tests {
355 span := startSpan(tt.startOptions)
356 got, err := endSpan(span)
357 if err != nil {
358 t.Fatal(err)
359 }
360 if !reflect.DeepEqual(got, tt.want) {
361 t.Errorf("exporting span: got %#v want %#v", got, tt.want)
362 }
363 }
364 }
365
366 func TestSetSpanAttributes(t *testing.T) {
367 span := startSpan(StartOptions{})
368 span.AddAttributes(StringAttribute("key1", "value1"))
369 got, err := endSpan(span)
370 if err != nil {
371 t.Fatal(err)
372 }
373
374 want := &SpanData{
375 SpanContext: SpanContext{
376 TraceID: tid,
377 SpanID: SpanID{},
378 TraceOptions: 0x1,
379 },
380 ParentSpanID: sid,
381 Name: "span0",
382 Attributes: map[string]interface{}{"key1": "value1"},
383 HasRemoteParent: true,
384 }
385 if !reflect.DeepEqual(got, want) {
386 t.Errorf("exporting span: got %#v want %#v", got, want)
387 }
388 }
389
390 func TestSetSpanAttributesOverLimit(t *testing.T) {
391 cfg := Config{MaxAttributesPerSpan: 2}
392 ApplyConfig(cfg)
393
394 span := startSpan(StartOptions{})
395 span.AddAttributes(StringAttribute("key1", "value1"))
396 span.AddAttributes(StringAttribute("key2", "value2"))
397 span.AddAttributes(StringAttribute("key1", "value3"))
398 span.AddAttributes(StringAttribute("key4", "value4"))
399 got, err := endSpan(span)
400 if err != nil {
401 t.Fatal(err)
402 }
403
404 want := &SpanData{
405 SpanContext: SpanContext{
406 TraceID: tid,
407 SpanID: SpanID{},
408 TraceOptions: 0x1,
409 },
410 ParentSpanID: sid,
411 Name: "span0",
412 Attributes: map[string]interface{}{"key1": "value3", "key4": "value4"},
413 HasRemoteParent: true,
414 DroppedAttributeCount: 1,
415 }
416 if !reflect.DeepEqual(got, want) {
417 t.Errorf("exporting span: got %#v want %#v", got, want)
418 }
419 }
420
421 func TestAnnotations(t *testing.T) {
422 span := startSpan(StartOptions{})
423 span.Annotatef([]Attribute{StringAttribute("key1", "value1")}, "%f", 1.5)
424 span.Annotate([]Attribute{StringAttribute("key2", "value2")}, "Annotate")
425 got, err := endSpan(span)
426 if err != nil {
427 t.Fatal(err)
428 }
429
430 for i := range got.Annotations {
431 if !checkTime(&got.Annotations[i].Time) {
432 t.Error("exporting span: expected nonzero Annotation Time")
433 }
434 }
435
436 want := &SpanData{
437 SpanContext: SpanContext{
438 TraceID: tid,
439 SpanID: SpanID{},
440 TraceOptions: 0x1,
441 },
442 ParentSpanID: sid,
443 Name: "span0",
444 Annotations: []Annotation{
445 {Message: "1.500000", Attributes: map[string]interface{}{"key1": "value1"}},
446 {Message: "Annotate", Attributes: map[string]interface{}{"key2": "value2"}},
447 },
448 HasRemoteParent: true,
449 }
450 if !reflect.DeepEqual(got, want) {
451 t.Errorf("exporting span: got %#v want %#v", got, want)
452 }
453 }
454
455 func TestAnnotationsOverLimit(t *testing.T) {
456 cfg := Config{MaxAnnotationEventsPerSpan: 2}
457 ApplyConfig(cfg)
458 span := startSpan(StartOptions{})
459 span.Annotatef([]Attribute{StringAttribute("key4", "value4")}, "%d", 1)
460 span.Annotate([]Attribute{StringAttribute("key3", "value3")}, "Annotate oldest")
461 span.Annotatef([]Attribute{StringAttribute("key1", "value1")}, "%f", 1.5)
462 span.Annotate([]Attribute{StringAttribute("key2", "value2")}, "Annotate")
463 got, err := endSpan(span)
464 if err != nil {
465 t.Fatal(err)
466 }
467
468 for i := range got.Annotations {
469 if !checkTime(&got.Annotations[i].Time) {
470 t.Error("exporting span: expected nonzero Annotation Time")
471 }
472 }
473
474 want := &SpanData{
475 SpanContext: SpanContext{
476 TraceID: tid,
477 SpanID: SpanID{},
478 TraceOptions: 0x1,
479 },
480 ParentSpanID: sid,
481 Name: "span0",
482 Annotations: []Annotation{
483 {Message: "1.500000", Attributes: map[string]interface{}{"key1": "value1"}},
484 {Message: "Annotate", Attributes: map[string]interface{}{"key2": "value2"}},
485 },
486 DroppedAnnotationCount: 2,
487 HasRemoteParent: true,
488 }
489 if !reflect.DeepEqual(got, want) {
490 t.Errorf("exporting span: got %#v want %#v", got, want)
491 }
492 }
493
494 func TestMessageEvents(t *testing.T) {
495 span := startSpan(StartOptions{})
496 span.AddMessageReceiveEvent(3, 400, 300)
497 span.AddMessageSendEvent(1, 200, 100)
498 got, err := endSpan(span)
499 if err != nil {
500 t.Fatal(err)
501 }
502
503 for i := range got.MessageEvents {
504 if !checkTime(&got.MessageEvents[i].Time) {
505 t.Error("exporting span: expected nonzero MessageEvent Time")
506 }
507 }
508
509 want := &SpanData{
510 SpanContext: SpanContext{
511 TraceID: tid,
512 SpanID: SpanID{},
513 TraceOptions: 0x1,
514 },
515 ParentSpanID: sid,
516 Name: "span0",
517 MessageEvents: []MessageEvent{
518 {EventType: 2, MessageID: 0x3, UncompressedByteSize: 0x190, CompressedByteSize: 0x12c},
519 {EventType: 1, MessageID: 0x1, UncompressedByteSize: 0xc8, CompressedByteSize: 0x64},
520 },
521 HasRemoteParent: true,
522 }
523 if !reflect.DeepEqual(got, want) {
524 t.Errorf("exporting span: got %#v want %#v", got, want)
525 }
526 }
527
528 func TestMessageEventsOverLimit(t *testing.T) {
529 cfg := Config{MaxMessageEventsPerSpan: 2}
530 ApplyConfig(cfg)
531 span := startSpan(StartOptions{})
532 span.AddMessageReceiveEvent(5, 300, 120)
533 span.AddMessageSendEvent(4, 100, 50)
534 span.AddMessageReceiveEvent(3, 400, 300)
535 span.AddMessageSendEvent(1, 200, 100)
536 got, err := endSpan(span)
537 if err != nil {
538 t.Fatal(err)
539 }
540
541 for i := range got.MessageEvents {
542 if !checkTime(&got.MessageEvents[i].Time) {
543 t.Error("exporting span: expected nonzero MessageEvent Time")
544 }
545 }
546
547 want := &SpanData{
548 SpanContext: SpanContext{
549 TraceID: tid,
550 SpanID: SpanID{},
551 TraceOptions: 0x1,
552 },
553 ParentSpanID: sid,
554 Name: "span0",
555 MessageEvents: []MessageEvent{
556 {EventType: 2, MessageID: 0x3, UncompressedByteSize: 0x190, CompressedByteSize: 0x12c},
557 {EventType: 1, MessageID: 0x1, UncompressedByteSize: 0xc8, CompressedByteSize: 0x64},
558 },
559 DroppedMessageEventCount: 2,
560 HasRemoteParent: true,
561 }
562 if !reflect.DeepEqual(got, want) {
563 t.Errorf("exporting span: got %#v want %#v", got, want)
564 }
565 }
566
567 func TestSetSpanName(t *testing.T) {
568 want := "SpanName-1"
569 span := startSpan(StartOptions{})
570 span.SetName(want)
571 got, err := endSpan(span)
572 if err != nil {
573 t.Fatal(err)
574 }
575
576 if got.Name != want {
577 t.Errorf("span.Name=%q; want %q", got.Name, want)
578 }
579 }
580
581 func TestSetSpanNameUnsampledSpan(t *testing.T) {
582 var nilSpanData *SpanData
583 s := startSpan(StartOptions{Sampler: NeverSample()})
584 s.SetName("NoopName")
585 sp := s.internal.(*span)
586 if want, got := nilSpanData, sp.data; want != got {
587 t.Errorf("span.data=%+v; want %+v", got, want)
588 }
589 }
590
591 func TestSetSpanNameAfterSpanEnd(t *testing.T) {
592 want := "SpanName-2"
593 span := startSpan(StartOptions{})
594 span.SetName(want)
595 got, err := endSpan(span)
596 if err != nil {
597 t.Fatal(err)
598 }
599
600
601 span.SetName("NoopName")
602
603
604 if got.Name != want {
605 t.Errorf("span.Name=%q; want %q", got.Name, want)
606 }
607
608
609 var te testExporter
610 RegisterExporter(&te)
611 span.End()
612 UnregisterExporter(&te)
613 if len(te.spans) != 0 {
614 t.Errorf("got exported spans %#v, wanted no spans", te.spans)
615 }
616 }
617
618 func TestSetSpanStatus(t *testing.T) {
619 span := startSpan(StartOptions{})
620 span.SetStatus(Status{Code: int32(1), Message: "request failed"})
621 got, err := endSpan(span)
622 if err != nil {
623 t.Fatal(err)
624 }
625
626 want := &SpanData{
627 SpanContext: SpanContext{
628 TraceID: tid,
629 SpanID: SpanID{},
630 TraceOptions: 0x1,
631 },
632 ParentSpanID: sid,
633 Name: "span0",
634 Status: Status{Code: 1, Message: "request failed"},
635 HasRemoteParent: true,
636 }
637 if !reflect.DeepEqual(got, want) {
638 t.Errorf("exporting span: got %#v want %#v", got, want)
639 }
640 }
641
642 func TestAddLink(t *testing.T) {
643 span := startSpan(StartOptions{})
644 span.AddLink(Link{
645 TraceID: tid,
646 SpanID: sid,
647 Type: LinkTypeParent,
648 Attributes: map[string]interface{}{"key5": "value5"},
649 })
650 got, err := endSpan(span)
651 if err != nil {
652 t.Fatal(err)
653 }
654
655 want := &SpanData{
656 SpanContext: SpanContext{
657 TraceID: tid,
658 SpanID: SpanID{},
659 TraceOptions: 0x1,
660 },
661 ParentSpanID: sid,
662 Name: "span0",
663 Links: []Link{{
664 TraceID: tid,
665 SpanID: sid,
666 Type: 2,
667 Attributes: map[string]interface{}{"key5": "value5"},
668 }},
669 HasRemoteParent: true,
670 }
671 if !reflect.DeepEqual(got, want) {
672 t.Errorf("exporting span: got %#v want %#v", got, want)
673 }
674 }
675
676 func TestAddLinkOverLimit(t *testing.T) {
677 cfg := Config{MaxLinksPerSpan: 1}
678 ApplyConfig(cfg)
679 span := startSpan(StartOptions{})
680 span.AddLink(Link{
681 TraceID: tid,
682 SpanID: sid,
683 Type: LinkTypeParent,
684 Attributes: map[string]interface{}{"key4": "value4"},
685 })
686 span.AddLink(Link{
687 TraceID: tid,
688 SpanID: sid,
689 Type: LinkTypeParent,
690 Attributes: map[string]interface{}{"key5": "value5"},
691 })
692 got, err := endSpan(span)
693 if err != nil {
694 t.Fatal(err)
695 }
696
697 want := &SpanData{
698 SpanContext: SpanContext{
699 TraceID: tid,
700 SpanID: SpanID{},
701 TraceOptions: 0x1,
702 },
703 ParentSpanID: sid,
704 Name: "span0",
705 Links: []Link{{
706 TraceID: tid,
707 SpanID: sid,
708 Type: 2,
709 Attributes: map[string]interface{}{"key5": "value5"},
710 }},
711 DroppedLinkCount: 1,
712 HasRemoteParent: true,
713 }
714 if !reflect.DeepEqual(got, want) {
715 t.Errorf("exporting span: got %#v want %#v", got, want)
716 }
717 }
718
719 func TestUnregisterExporter(t *testing.T) {
720 var te testExporter
721 RegisterExporter(&te)
722 UnregisterExporter(&te)
723
724 ctx := startSpan(StartOptions{})
725 endSpan(ctx)
726 if len(te.spans) != 0 {
727 t.Error("unregistered Exporter was called")
728 }
729 }
730
731 func TestBucket(t *testing.T) {
732
733 b := makeBucket(5)
734 for i := 1; i <= 10; i++ {
735 b.nextTime = time.Time{}
736
737 b.add(&SpanData{SpanContext: SpanContext{TraceID: TraceID{byte(i)}}, EndTime: time.Now()})
738 if i <= 5 {
739 if b.size() != i {
740 t.Fatalf("got bucket size %d, want %d %#v\n", b.size(), i, b)
741 }
742 for j := 0; j < i; j++ {
743 if b.span(j).TraceID[0] != byte(j+1) {
744 t.Errorf("got span index %d, want %d\n", b.span(j).TraceID[0], j+1)
745 }
746 }
747 } else {
748 if b.size() != 5 {
749 t.Fatalf("got bucket size %d, want 5\n", b.size())
750 }
751 for j := 0; j < 5; j++ {
752 want := i - 4 + j
753 if b.span(j).TraceID[0] != byte(want) {
754 t.Errorf("got span index %d, want %d\n", b.span(j).TraceID[0], want)
755 }
756 }
757 }
758 }
759
760 b.resize(20)
761 if b.size() != 5 {
762 t.Fatalf("after resizing upwards: got bucket size %d, want 5\n", b.size())
763 }
764 for i := 0; i < 5; i++ {
765 want := 6 + i
766 if b.span(i).TraceID[0] != byte(want) {
767 t.Errorf("after resizing upwards: got span index %d, want %d\n", b.span(i).TraceID[0], want)
768 }
769 }
770
771 b.resize(3)
772 if b.size() != 3 {
773 t.Fatalf("after resizing downwards: got bucket size %d, want 3\n", b.size())
774 }
775 for i := 0; i < 3; i++ {
776 want := 8 + i
777 if b.span(i).TraceID[0] != byte(want) {
778 t.Errorf("after resizing downwards: got span index %d, want %d\n", b.span(i).TraceID[0], want)
779 }
780 }
781 }
782
783 type exporter map[string]*SpanData
784
785 func (e exporter) ExportSpan(s *SpanData) {
786 e[s.Name] = s
787 }
788
789 func Test_Issue328_EndSpanTwice(t *testing.T) {
790 spans := make(exporter)
791 RegisterExporter(&spans)
792 defer UnregisterExporter(&spans)
793 ctx := context.Background()
794 ctx, span := StartSpan(ctx, "span-1", WithSampler(AlwaysSample()))
795 span.End()
796 span.End()
797 UnregisterExporter(&spans)
798 if len(spans) != 1 {
799 t.Fatalf("expected only a single span, got %#v", spans)
800 }
801 }
802
803 func TestStartSpanAfterEnd(t *testing.T) {
804 spans := make(exporter)
805 RegisterExporter(&spans)
806 defer UnregisterExporter(&spans)
807 ctx, span0 := StartSpan(context.Background(), "parent", WithSampler(AlwaysSample()))
808 ctx1, span1 := StartSpan(ctx, "span-1", WithSampler(AlwaysSample()))
809 span1.End()
810
811
812 _, span2 := StartSpan(ctx1, "span-2", WithSampler(AlwaysSample()))
813 span2.End()
814 span0.End()
815 UnregisterExporter(&spans)
816 if got, want := len(spans), 3; got != want {
817 t.Fatalf("len(%#v) = %d; want %d", spans, got, want)
818 }
819 if got, want := spans["span-1"].TraceID, spans["parent"].TraceID; got != want {
820 t.Errorf("span-1.TraceID=%q; want %q", got, want)
821 }
822 if got, want := spans["span-2"].TraceID, spans["parent"].TraceID; got != want {
823 t.Errorf("span-2.TraceID=%q; want %q", got, want)
824 }
825 if got, want := spans["span-1"].ParentSpanID, spans["parent"].SpanID; got != want {
826 t.Errorf("span-1.ParentSpanID=%q; want %q (parent.SpanID)", got, want)
827 }
828 if got, want := spans["span-2"].ParentSpanID, spans["span-1"].SpanID; got != want {
829 t.Errorf("span-2.ParentSpanID=%q; want %q (span1.SpanID)", got, want)
830 }
831 }
832
833 func TestChildSpanCount(t *testing.T) {
834 spans := make(exporter)
835 RegisterExporter(&spans)
836 defer UnregisterExporter(&spans)
837 ctx, span0 := StartSpan(context.Background(), "parent", WithSampler(AlwaysSample()))
838 ctx1, span1 := StartSpan(ctx, "span-1", WithSampler(AlwaysSample()))
839 _, span2 := StartSpan(ctx1, "span-2", WithSampler(AlwaysSample()))
840 span2.End()
841 span1.End()
842
843 _, span3 := StartSpan(ctx, "span-3", WithSampler(AlwaysSample()))
844 span3.End()
845 span0.End()
846 UnregisterExporter(&spans)
847 if got, want := len(spans), 4; got != want {
848 t.Fatalf("len(%#v) = %d; want %d", spans, got, want)
849 }
850 if got, want := spans["span-3"].ChildSpanCount, 0; got != want {
851 t.Errorf("span-3.ChildSpanCount=%q; want %q", got, want)
852 }
853 if got, want := spans["span-2"].ChildSpanCount, 0; got != want {
854 t.Errorf("span-2.ChildSpanCount=%q; want %q", got, want)
855 }
856 if got, want := spans["span-1"].ChildSpanCount, 1; got != want {
857 t.Errorf("span-1.ChildSpanCount=%q; want %q", got, want)
858 }
859 if got, want := spans["parent"].ChildSpanCount, 2; got != want {
860 t.Errorf("parent.ChildSpanCount=%q; want %q", got, want)
861 }
862 }
863
864 func TestNilSpanEnd(t *testing.T) {
865 var span *Span
866 span.End()
867 }
868
869 func TestExecutionTracerTaskEnd(t *testing.T) {
870 var n uint64
871 executionTracerTaskEnd := func() {
872 atomic.AddUint64(&n, 1)
873 }
874
875 var spans []*span
876 _, s := StartSpan(context.Background(), "foo", WithSampler(NeverSample()))
877 sp := s.internal.(*span)
878 sp.executionTracerTaskEnd = executionTracerTaskEnd
879 spans = append(spans, sp)
880
881 _, s = StartSpanWithRemoteParent(context.Background(), "foo", SpanContext{
882 TraceID: TraceID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
883 SpanID: SpanID{0, 1, 2, 3, 4, 5, 6, 7},
884 TraceOptions: 0,
885 })
886 sp = s.internal.(*span)
887 sp.executionTracerTaskEnd = executionTracerTaskEnd
888 spans = append(spans, sp)
889
890 _, s = StartSpan(context.Background(), "foo", WithSampler(AlwaysSample()))
891 sp = s.internal.(*span)
892 sp.executionTracerTaskEnd = executionTracerTaskEnd
893 spans = append(spans, sp)
894
895 for _, span := range spans {
896 span.End()
897 }
898 if got, want := n, uint64(len(spans)); got != want {
899 t.Fatalf("Execution tracer task ended for %v spans; want %v", got, want)
900 }
901 }
902
View as plain text