github.com/lingyao2333/mo-zero@v1.4.1/core/trace/tracer_test.go (about)

     1  package trace
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/stretchr/testify/require"
     9  	"go.opentelemetry.io/otel"
    10  	"go.opentelemetry.io/otel/propagation"
    11  	"go.opentelemetry.io/otel/trace"
    12  	"google.golang.org/grpc/metadata"
    13  )
    14  
    15  const (
    16  	traceIDStr = "4bf92f3577b34da6a3ce929d0e0e4736"
    17  	spanIDStr  = "00f067aa0ba902b7"
    18  )
    19  
    20  var (
    21  	traceID = mustTraceIDFromHex(traceIDStr)
    22  	spanID  = mustSpanIDFromHex(spanIDStr)
    23  )
    24  
    25  func mustTraceIDFromHex(s string) (t trace.TraceID) {
    26  	var err error
    27  	t, err = trace.TraceIDFromHex(s)
    28  	if err != nil {
    29  		panic(err)
    30  	}
    31  	return
    32  }
    33  
    34  func mustSpanIDFromHex(s string) (t trace.SpanID) {
    35  	var err error
    36  	t, err = trace.SpanIDFromHex(s)
    37  	if err != nil {
    38  		panic(err)
    39  	}
    40  	return
    41  }
    42  
    43  func TestExtractValidTraceContext(t *testing.T) {
    44  	stateStr := "key1=value1,key2=value2"
    45  	state, err := trace.ParseTraceState(stateStr)
    46  	require.NoError(t, err)
    47  
    48  	tests := []struct {
    49  		name        string
    50  		traceparent string
    51  		tracestate  string
    52  		sc          trace.SpanContext
    53  	}{
    54  		{
    55  			name:        "not sampled",
    56  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
    57  			sc: trace.NewSpanContext(trace.SpanContextConfig{
    58  				TraceID: traceID,
    59  				SpanID:  spanID,
    60  				Remote:  true,
    61  			}),
    62  		},
    63  		{
    64  			name:        "sampled",
    65  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
    66  			sc: trace.NewSpanContext(trace.SpanContextConfig{
    67  				TraceID:    traceID,
    68  				SpanID:     spanID,
    69  				TraceFlags: trace.FlagsSampled,
    70  				Remote:     true,
    71  			}),
    72  		},
    73  		{
    74  			name:        "valid tracestate",
    75  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
    76  			tracestate:  stateStr,
    77  			sc: trace.NewSpanContext(trace.SpanContextConfig{
    78  				TraceID:    traceID,
    79  				SpanID:     spanID,
    80  				TraceState: state,
    81  				Remote:     true,
    82  			}),
    83  		},
    84  		{
    85  			name:        "invalid tracestate perserves traceparent",
    86  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
    87  			tracestate:  "invalid$@#=invalid",
    88  			sc: trace.NewSpanContext(trace.SpanContextConfig{
    89  				TraceID: traceID,
    90  				SpanID:  spanID,
    91  				Remote:  true,
    92  			}),
    93  		},
    94  		{
    95  			name:        "future version not sampled",
    96  			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
    97  			sc: trace.NewSpanContext(trace.SpanContextConfig{
    98  				TraceID: traceID,
    99  				SpanID:  spanID,
   100  				Remote:  true,
   101  			}),
   102  		},
   103  		{
   104  			name:        "future version sampled",
   105  			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
   106  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   107  				TraceID:    traceID,
   108  				SpanID:     spanID,
   109  				TraceFlags: trace.FlagsSampled,
   110  				Remote:     true,
   111  			}),
   112  		},
   113  		{
   114  			name:        "future version sample bit set",
   115  			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-09",
   116  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   117  				TraceID:    traceID,
   118  				SpanID:     spanID,
   119  				TraceFlags: trace.FlagsSampled,
   120  				Remote:     true,
   121  			}),
   122  		},
   123  		{
   124  			name:        "future version sample bit not set",
   125  			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-08",
   126  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   127  				TraceID: traceID,
   128  				SpanID:  spanID,
   129  				Remote:  true,
   130  			}),
   131  		},
   132  		{
   133  			name:        "future version additional data",
   134  			traceparent: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-XYZxsf09",
   135  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   136  				TraceID: traceID,
   137  				SpanID:  spanID,
   138  				Remote:  true,
   139  			}),
   140  		},
   141  		{
   142  			name:        "B3 format ending in dash",
   143  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
   144  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   145  				TraceID: traceID,
   146  				SpanID:  spanID,
   147  				Remote:  true,
   148  			}),
   149  		},
   150  		{
   151  			name:        "future version B3 format ending in dash",
   152  			traceparent: "03-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00-",
   153  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   154  				TraceID: traceID,
   155  				SpanID:  spanID,
   156  				Remote:  true,
   157  			}),
   158  		},
   159  	}
   160  	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
   161  		propagation.TraceContext{}, propagation.Baggage{}))
   162  	propagator := otel.GetTextMapPropagator()
   163  
   164  	for _, tt := range tests {
   165  		t.Run(tt.name, func(t *testing.T) {
   166  			ctx := context.Background()
   167  			md := metadata.MD{}
   168  			md.Set("traceparent", tt.traceparent)
   169  			md.Set("tracestate", tt.tracestate)
   170  			_, spanCtx := Extract(ctx, propagator, &md)
   171  			assert.Equal(t, tt.sc, spanCtx)
   172  		})
   173  	}
   174  }
   175  
   176  func TestExtractInvalidTraceContext(t *testing.T) {
   177  	tests := []struct {
   178  		name   string
   179  		header string
   180  	}{
   181  		{
   182  			name:   "wrong version length",
   183  			header: "0000-00000000000000000000000000000000-0000000000000000-01",
   184  		},
   185  		{
   186  			name:   "wrong trace ID length",
   187  			header: "00-ab00000000000000000000000000000000-cd00000000000000-01",
   188  		},
   189  		{
   190  			name:   "wrong span ID length",
   191  			header: "00-ab000000000000000000000000000000-cd0000000000000000-01",
   192  		},
   193  		{
   194  			name:   "wrong trace flag length",
   195  			header: "00-ab000000000000000000000000000000-cd00000000000000-0100",
   196  		},
   197  		{
   198  			name:   "bogus version",
   199  			header: "qw-00000000000000000000000000000000-0000000000000000-01",
   200  		},
   201  		{
   202  			name:   "bogus trace ID",
   203  			header: "00-qw000000000000000000000000000000-cd00000000000000-01",
   204  		},
   205  		{
   206  			name:   "bogus span ID",
   207  			header: "00-ab000000000000000000000000000000-qw00000000000000-01",
   208  		},
   209  		{
   210  			name:   "bogus trace flag",
   211  			header: "00-ab000000000000000000000000000000-cd00000000000000-qw",
   212  		},
   213  		{
   214  			name:   "upper case version",
   215  			header: "A0-00000000000000000000000000000000-0000000000000000-01",
   216  		},
   217  		{
   218  			name:   "upper case trace ID",
   219  			header: "00-AB000000000000000000000000000000-cd00000000000000-01",
   220  		},
   221  		{
   222  			name:   "upper case span ID",
   223  			header: "00-ab000000000000000000000000000000-CD00000000000000-01",
   224  		},
   225  		{
   226  			name:   "upper case trace flag",
   227  			header: "00-ab000000000000000000000000000000-cd00000000000000-A1",
   228  		},
   229  		{
   230  			name:   "zero trace ID and span ID",
   231  			header: "00-00000000000000000000000000000000-0000000000000000-01",
   232  		},
   233  		{
   234  			name:   "trace-flag unused bits set",
   235  			header: "00-ab000000000000000000000000000000-cd00000000000000-09",
   236  		},
   237  		{
   238  			name:   "missing options",
   239  			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
   240  		},
   241  		{
   242  			name:   "empty options",
   243  			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
   244  		},
   245  	}
   246  	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
   247  		propagation.TraceContext{}, propagation.Baggage{}))
   248  	propagator := otel.GetTextMapPropagator()
   249  
   250  	for _, tt := range tests {
   251  		t.Run(tt.name, func(t *testing.T) {
   252  			ctx := context.Background()
   253  			md := metadata.MD{}
   254  			md.Set("traceparent", tt.header)
   255  			_, spanCtx := Extract(ctx, propagator, &md)
   256  			assert.Equal(t, trace.SpanContext{}, spanCtx)
   257  		})
   258  	}
   259  }
   260  
   261  func TestInjectValidTraceContext(t *testing.T) {
   262  	stateStr := "key1=value1,key2=value2"
   263  	state, err := trace.ParseTraceState(stateStr)
   264  	require.NoError(t, err)
   265  
   266  	tests := []struct {
   267  		name        string
   268  		traceparent string
   269  		tracestate  string
   270  		sc          trace.SpanContext
   271  	}{
   272  		{
   273  			name:        "not sampled",
   274  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
   275  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   276  				TraceID: traceID,
   277  				SpanID:  spanID,
   278  				Remote:  true,
   279  			}),
   280  		},
   281  		{
   282  			name:        "sampled",
   283  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
   284  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   285  				TraceID:    traceID,
   286  				SpanID:     spanID,
   287  				TraceFlags: trace.FlagsSampled,
   288  				Remote:     true,
   289  			}),
   290  		},
   291  		{
   292  			name:        "unsupported trace flag bits dropped",
   293  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
   294  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   295  				TraceID:    traceID,
   296  				SpanID:     spanID,
   297  				TraceFlags: 0xff,
   298  				Remote:     true,
   299  			}),
   300  		},
   301  		{
   302  			name:        "with tracestate",
   303  			traceparent: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-00",
   304  			tracestate:  stateStr,
   305  			sc: trace.NewSpanContext(trace.SpanContextConfig{
   306  				TraceID:    traceID,
   307  				SpanID:     spanID,
   308  				TraceState: state,
   309  				Remote:     true,
   310  			}),
   311  		},
   312  	}
   313  	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
   314  		propagation.TraceContext{}, propagation.Baggage{}))
   315  	propagator := otel.GetTextMapPropagator()
   316  
   317  	for _, tt := range tests {
   318  		t.Run(tt.name, func(t *testing.T) {
   319  			ctx := context.Background()
   320  			ctx = trace.ContextWithRemoteSpanContext(ctx, tt.sc)
   321  
   322  			want := metadata.MD{}
   323  			want.Set("traceparent", tt.traceparent)
   324  			if len(tt.tracestate) > 0 {
   325  				want.Set("tracestate", tt.tracestate)
   326  			}
   327  
   328  			md := metadata.MD{}
   329  			Inject(ctx, propagator, &md)
   330  			assert.Equal(t, want, md)
   331  
   332  			mm := &metadataSupplier{
   333  				metadata: &md,
   334  			}
   335  			assert.NotEmpty(t, mm.Keys())
   336  		})
   337  	}
   338  }
   339  
   340  func TestInvalidSpanContextDropped(t *testing.T) {
   341  	invalidSC := trace.SpanContext{}
   342  	require.False(t, invalidSC.IsValid())
   343  	ctx := trace.ContextWithRemoteSpanContext(context.Background(), invalidSC)
   344  
   345  	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
   346  		propagation.TraceContext{}, propagation.Baggage{}))
   347  	propagator := otel.GetTextMapPropagator()
   348  
   349  	md := metadata.MD{}
   350  	Inject(ctx, propagator, &md)
   351  	mm := &metadataSupplier{
   352  		metadata: &md,
   353  	}
   354  	assert.Empty(t, mm.Keys())
   355  	assert.Equal(t, "", mm.Get("traceparent"), "injected invalid SpanContext")
   356  }