Browse Source

add opentelemetry test (#1002)

neosu 3 years ago
parent
commit
dec6309c55

+ 2 - 2
core/trace/opentelemetry/agent.go

@@ -18,12 +18,12 @@ var (
 	enabled syncx.AtomicBool
 )
 
-// Enabled returns if prometheus is enabled.
+// Enabled returns if opentelemetry is enabled.
 func Enabled() bool {
 	return enabled.True()
 }
 
-// StartAgent starts a prometheus agent.
+// StartAgent starts a opentelemetry agent.
 func StartAgent(c Config) {
 	once.Do(func() {
 		if len(c.Endpoint) == 0 {

+ 347 - 0
core/trace/opentelemetry/tracer_test.go

@@ -0,0 +1,347 @@
+package opentelemetry
+
+import (
+	"context"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"go.opentelemetry.io/otel"
+	"go.opentelemetry.io/otel/propagation"
+	"go.opentelemetry.io/otel/trace"
+	"google.golang.org/grpc/metadata"
+)
+
+const (
+	traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736"
+	spanIDStr  = "00f067aa0ba902b7"
+)
+
+var (
+	traceID = mustTraceIDFromHex(traceIDStr)
+	spanID  = mustSpanIDFromHex(spanIDStr)
+)
+
+func mustTraceIDFromHex(s string) (t trace.TraceID) {
+	var err error
+	t, err = trace.TraceIDFromHex(s)
+	if err != nil {
+		panic(err)
+	}
+	return
+}
+
+func mustSpanIDFromHex(s string) (t trace.SpanID) {
+	var err error
+	t, err = trace.SpanIDFromHex(s)
+	if err != nil {
+		panic(err)
+	}
+	return
+}
+
+func TestExtractValidTraceContext(t *testing.T) {
+	stateStr := "key1=value1,key2=value2"
+	state, err := trace.ParseTraceState(stateStr)
+	require.NoError(t, err)
+
+	tests := []struct {
+		name        string
+		traceparent string
+		tracestate  string
+		sc          trace.SpanContext
+	}{
+		{
+			name:        "not sampled",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "sampled",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceFlags: trace.FlagsSampled,
+				Remote:     true,
+			}),
+		},
+		{
+			name:        "valid tracestate",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
+			tracestate:  stateStr,
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceState: state,
+				Remote:     true,
+			}),
+		},
+		{
+			name:        "invalid tracestate perserves traceparent",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
+			tracestate:  "invalid$@#=invalid",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "future version not sampled",
+			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "future version sampled",
+			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceFlags: trace.FlagsSampled,
+				Remote:     true,
+			}),
+		},
+		{
+			name:        "future version sample bit set",
+			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceFlags: trace.FlagsSampled,
+				Remote:     true,
+			}),
+		},
+		{
+			name:        "future version sample bit not set",
+			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "future version additional data",
+			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-XYZxsf09",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "B3 format ending in dash",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "future version B3 format ending in dash",
+			traceparent: "03-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+	}
+	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
+	propagator := otel.GetTextMapPropagator()
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ctx := context.Background()
+			md := metadata.MD{}
+			md.Set("traceparent", tt.traceparent)
+			md.Set("tracestate", tt.tracestate)
+			_, spanCtx := Extract(ctx, propagator, &md)
+			assert.Equal(t, tt.sc, spanCtx)
+		})
+	}
+}
+
+func TestExtractInvalidTraceContext(t *testing.T) {
+
+	tests := []struct {
+		name   string
+		header string
+	}{
+		{
+			name:   "wrong version length",
+			header: "0000-00000000000000000000000000000000-0000000000000000-01",
+		},
+		{
+			name:   "wrong trace ID length",
+			header: "00-ab00000000000000000000000000000000-cd00000000000000-01",
+		},
+		{
+			name:   "wrong span ID length",
+			header: "00-ab000000000000000000000000000000-cd0000000000000000-01",
+		},
+		{
+			name:   "wrong trace flag length",
+			header: "00-ab000000000000000000000000000000-cd00000000000000-0100",
+		},
+		{
+			name:   "bogus version",
+			header: "qw-00000000000000000000000000000000-0000000000000000-01",
+		},
+		{
+			name:   "bogus trace ID",
+			header: "00-qw000000000000000000000000000000-cd00000000000000-01",
+		},
+		{
+			name:   "bogus span ID",
+			header: "00-ab000000000000000000000000000000-qw00000000000000-01",
+		},
+		{
+			name:   "bogus trace flag",
+			header: "00-ab000000000000000000000000000000-cd00000000000000-qw",
+		},
+		{
+			name:   "upper case version",
+			header: "A0-00000000000000000000000000000000-0000000000000000-01",
+		},
+		{
+			name:   "upper case trace ID",
+			header: "00-AB000000000000000000000000000000-cd00000000000000-01",
+		},
+		{
+			name:   "upper case span ID",
+			header: "00-ab000000000000000000000000000000-CD00000000000000-01",
+		},
+		{
+			name:   "upper case trace flag",
+			header: "00-ab000000000000000000000000000000-cd00000000000000-A1",
+		},
+		{
+			name:   "zero trace ID and span ID",
+			header: "00-00000000000000000000000000000000-0000000000000000-01",
+		},
+		{
+			name:   "trace-flag unused bits set",
+			header: "00-ab000000000000000000000000000000-cd00000000000000-09",
+		},
+		{
+			name:   "missing options",
+			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
+		},
+		{
+			name:   "empty options",
+			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
+		},
+	}
+	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
+	propagator := otel.GetTextMapPropagator()
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ctx := context.Background()
+			md := metadata.MD{}
+			md.Set("traceparent", tt.header)
+			_, spanCtx := Extract(ctx, propagator, &md)
+			assert.Equal(t, trace.SpanContext{}, spanCtx)
+		})
+	}
+}
+
+func TestInjectValidTraceContext(t *testing.T) {
+	stateStr := "key1=value1,key2=value2"
+	state, err := trace.ParseTraceState(stateStr)
+	require.NoError(t, err)
+
+	tests := []struct {
+		name        string
+		traceparent string
+		tracestate  string
+		sc          trace.SpanContext
+	}{
+		{
+			name:        "not sampled",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID: traceID,
+				SpanID:  spanID,
+				Remote:  true,
+			}),
+		},
+		{
+			name:        "sampled",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceFlags: trace.FlagsSampled,
+				Remote:     true,
+			}),
+		},
+		{
+			name:        "unsupported trace flag bits dropped",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceFlags: 0xff,
+				Remote:     true,
+			}),
+		},
+		{
+			name:        "with tracestate",
+			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
+			tracestate:  stateStr,
+			sc: trace.NewSpanContext(trace.SpanContextConfig{
+				TraceID:    traceID,
+				SpanID:     spanID,
+				TraceState: state,
+				Remote:     true,
+			}),
+		},
+	}
+	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
+	propagator := otel.GetTextMapPropagator()
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			ctx := context.Background()
+			ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
+
+			want := metadata.MD{}
+			want.Set("traceparent", tt.traceparent)
+			if len(tt.tracestate) > 0 {
+				want.Set("tracestate", tt.tracestate)
+			}
+
+			md := metadata.MD{}
+			Inject(ctx, propagator, &md)
+			assert.Equal(t, want, md)
+		})
+	}
+}
+
+func TestInvalidSpanContextDropped(t *testing.T) {
+	invalidSC := trace.SpanContext{}
+	require.False(t, invalidSC.IsValid())
+	ctx := trace.ContextWithRemoteSpanContext(context.Background(), invalidSC)
+
+	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
+	propagator := otel.GetTextMapPropagator()
+
+	md := metadata.MD{}
+	Inject(ctx, propagator, &md)
+	mm := &metadataSupplier{
+		metadata: &md,
+	}
+	assert.Equal(t, "", mm.Get("traceparent"), "injected invalid SpanContext")
+}

+ 70 - 0
core/trace/opentelemetry/utils_test.go

@@ -0,0 +1,70 @@
+package opentelemetry
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"go.opentelemetry.io/otel/attribute"
+	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
+)
+
+func TestParseFullMethod(t *testing.T) {
+	tests := []struct {
+		fullMethod string
+		name       string
+		attr       []attribute.KeyValue
+	}{
+		{
+			fullMethod: "/grpc.test.EchoService/Echo",
+			name:       "grpc.test.EchoService/Echo",
+			attr: []attribute.KeyValue{
+				semconv.RPCServiceKey.String("grpc.test.EchoService"),
+				semconv.RPCMethodKey.String("Echo"),
+			},
+		}, {
+			fullMethod: "/com.example.ExampleRmiService/exampleMethod",
+			name:       "com.example.ExampleRmiService/exampleMethod",
+			attr: []attribute.KeyValue{
+				semconv.RPCServiceKey.String("com.example.ExampleRmiService"),
+				semconv.RPCMethodKey.String("exampleMethod"),
+			},
+		}, {
+			fullMethod: "/MyCalcService.Calculator/Add",
+			name:       "MyCalcService.Calculator/Add",
+			attr: []attribute.KeyValue{
+				semconv.RPCServiceKey.String("MyCalcService.Calculator"),
+				semconv.RPCMethodKey.String("Add"),
+			},
+		}, {
+			fullMethod: "/MyServiceReference.ICalculator/Add",
+			name:       "MyServiceReference.ICalculator/Add",
+			attr: []attribute.KeyValue{
+				semconv.RPCServiceKey.String("MyServiceReference.ICalculator"),
+				semconv.RPCMethodKey.String("Add"),
+			},
+		}, {
+			fullMethod: "/MyServiceWithNoPackage/theMethod",
+			name:       "MyServiceWithNoPackage/theMethod",
+			attr: []attribute.KeyValue{
+				semconv.RPCServiceKey.String("MyServiceWithNoPackage"),
+				semconv.RPCMethodKey.String("theMethod"),
+			},
+		}, {
+			fullMethod: "/pkg.srv",
+			name:       "pkg.srv",
+			attr:       []attribute.KeyValue(nil),
+		}, {
+			fullMethod: "/pkg.srv/",
+			name:       "pkg.srv/",
+			attr: []attribute.KeyValue{
+				semconv.RPCServiceKey.String("pkg.srv"),
+			},
+		},
+	}
+
+	for _, test := range tests {
+		n, a := ParseFullMethod(test.fullMethod)
+		assert.Equal(t, test.name, n)
+		assert.Equal(t, test.attr, a)
+	}
+}