package mocktracer import ( "testing" "time" "gopkg.in/DataDog/dd-trace-go.v1/ddtrace" "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext" "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/internal" "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer" "github.com/stretchr/testify/assert" ) func TestStart(t *testing.T) { trc := Start() if tt, ok := internal.GetGlobalTracer().(Tracer); !ok || tt != trc { t.Fail() } } func TestTracerStop(t *testing.T) { Start().Stop() if _, ok := internal.GetGlobalTracer().(*internal.NoopTracer); !ok { t.Fail() } } func TestTracerStartSpan(t *testing.T) { parentTags := map[string]interface{}{ext.ServiceName: "root-service", ext.SamplingPriority: -1} startTime := time.Now() t.Run("with-service", func(t *testing.T) { var mt mocktracer parent := newSpan(&mt, "http.request", &ddtrace.StartSpanConfig{Tags: parentTags}) s, ok := mt.StartSpan( "db.query", tracer.ServiceName("my-service"), tracer.StartTime(startTime), tracer.ChildOf(parent.Context()), ).(*mockspan) assert := assert.New(t) assert.True(ok) assert.Equal("db.query", s.OperationName()) assert.Equal(startTime, s.StartTime()) assert.Equal("my-service", s.Tag(ext.ServiceName)) assert.Equal(parent.SpanID(), s.ParentID()) assert.Equal(parent.TraceID(), s.TraceID()) assert.True(parent.context.hasSamplingPriority()) assert.Equal(-1, parent.context.samplingPriority()) }) t.Run("inherit", func(t *testing.T) { var mt mocktracer parent := newSpan(&mt, "http.request", &ddtrace.StartSpanConfig{Tags: parentTags}) s, ok := mt.StartSpan("db.query", tracer.ChildOf(parent.Context())).(*mockspan) assert := assert.New(t) assert.True(ok) assert.Equal("db.query", s.OperationName()) assert.Equal("root-service", s.Tag(ext.ServiceName)) assert.Equal(parent.SpanID(), s.ParentID()) assert.Equal(parent.TraceID(), s.TraceID()) assert.True(s.context.hasSamplingPriority()) assert.Equal(-1, s.context.samplingPriority()) }) } func TestTracerFinishedSpans(t *testing.T) { var mt mocktracer parent := newSpan(&mt, "http.request", &ddtrace.StartSpanConfig{}) child := mt.StartSpan("db.query", tracer.ChildOf(parent.Context())) child.Finish() parent.Finish() found := 0 for _, s := range mt.FinishedSpans() { switch s.OperationName() { case "http.request": assert.Equal(t, parent, s) found++ case "db.query": assert.Equal(t, child, s) found++ } } assert.Equal(t, 2, found) } func TestTracerReset(t *testing.T) { var mt mocktracer mt.StartSpan("db.query").Finish() assert := assert.New(t) assert.Len(mt.finishedSpans, 1) mt.Reset() assert.Nil(mt.finishedSpans) } func TestTracerInject(t *testing.T) { t.Run("errors", func(t *testing.T) { var mt mocktracer assert := assert.New(t) err := mt.Inject(&spanContext{}, 2) assert.Equal(tracer.ErrInvalidCarrier, err) // 2 is not a carrier err = mt.Inject(&spanContext{}, tracer.TextMapCarrier(map[string]string{})) assert.Equal(tracer.ErrInvalidSpanContext, err) // no traceID and spanID err = mt.Inject(&spanContext{traceID: 2}, tracer.TextMapCarrier(map[string]string{})) assert.Equal(tracer.ErrInvalidSpanContext, err) // no spanID err = mt.Inject(&spanContext{traceID: 2, spanID: 1}, tracer.TextMapCarrier(map[string]string{})) assert.Nil(err) // ok }) t.Run("ok", func(t *testing.T) { sctx := &spanContext{ traceID: 1, spanID: 2, priority: -1, hasPriority: true, baggage: map[string]string{"A": "B", "C": "D"}, } carrier := make(map[string]string) err := (&mocktracer{}).Inject(sctx, tracer.TextMapCarrier(carrier)) assert := assert.New(t) assert.Nil(err) assert.Equal("1", carrier[traceHeader]) assert.Equal("2", carrier[spanHeader]) assert.Equal("-1", carrier[priorityHeader]) assert.Equal("B", carrier[baggagePrefix+"A"]) assert.Equal("D", carrier[baggagePrefix+"C"]) }) } func TestTracerExtract(t *testing.T) { // carry creates a tracer.TextMapCarrier containing the given sequence // of key/value pairs. carry := func(kv ...string) tracer.TextMapCarrier { var k string m := make(map[string]string) if n := len(kv); n%2 == 0 && n >= 2 { for i, v := range kv { if (i+1)%2 == 0 { m[k] = v } else { k = v } } } return tracer.TextMapCarrier(m) } // tests carry helper function. t.Run("carry", func(t *testing.T) { for _, tt := range []struct { in []string out tracer.TextMapCarrier }{ {in: []string{}, out: map[string]string{}}, {in: []string{"A"}, out: map[string]string{}}, {in: []string{"A", "B", "C"}, out: map[string]string{}}, {in: []string{"A", "B"}, out: map[string]string{"A": "B"}}, {in: []string{"A", "B", "C", "D"}, out: map[string]string{"A": "B", "C": "D"}}, } { assert.Equal(t, tt.out, carry(tt.in...)) } }) var mt mocktracer // tests error return values. t.Run("errors", func(t *testing.T) { assert := assert.New(t) _, err := mt.Extract(2) assert.Equal(tracer.ErrInvalidCarrier, err) _, err = mt.Extract(carry(traceHeader, "a")) assert.Equal(tracer.ErrSpanContextCorrupted, err) _, err = mt.Extract(carry(spanHeader, "a", traceHeader, "2", baggagePrefix+"x", "y")) assert.Equal(tracer.ErrSpanContextCorrupted, err) _, err = mt.Extract(carry(spanHeader, "1")) assert.Equal(tracer.ErrSpanContextNotFound, err) _, err = mt.Extract(carry()) assert.Equal(tracer.ErrSpanContextNotFound, err) }) t.Run("ok", func(t *testing.T) { assert := assert.New(t) ctx, err := mt.Extract(carry(traceHeader, "1", spanHeader, "2")) assert.Nil(err) sc, ok := ctx.(*spanContext) assert.True(ok) assert.Equal(uint64(1), sc.traceID) assert.Equal(uint64(2), sc.spanID) ctx, err = mt.Extract(carry(traceHeader, "1", spanHeader, "2", baggagePrefix+"A", "B", baggagePrefix+"C", "D")) assert.Nil(err) sc, ok = ctx.(*spanContext) assert.True(ok) assert.Equal("B", sc.baggageItem("a")) assert.Equal("D", sc.baggageItem("c")) ctx, err = mt.Extract(carry(traceHeader, "1", spanHeader, "2", priorityHeader, "-1")) assert.Nil(err) sc, ok = ctx.(*spanContext) assert.True(ok) assert.True(sc.hasSamplingPriority()) assert.Equal(-1, sc.samplingPriority()) }) t.Run("consistency", func(t *testing.T) { assert := assert.New(t) want := &spanContext{traceID: 1, spanID: 2, baggage: map[string]string{"a": "B", "C": "D"}} mc := tracer.TextMapCarrier(make(map[string]string)) err := mt.Inject(want, mc) assert.Nil(err) sc, err := mt.Extract(mc) assert.Nil(err) got, ok := sc.(*spanContext) assert.True(ok) assert.Equal(uint64(1), got.traceID) assert.Equal(uint64(2), got.spanID) assert.Equal("D", got.baggageItem("c")) assert.Equal("B", got.baggageItem("a")) }) }