...

Source file src/go.opencensus.io/plugin/ochttp/propagation/tracecontext/propagation_test.go

Documentation: go.opencensus.io/plugin/ochttp/propagation/tracecontext

     1  // Copyright 2018, OpenCensus Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package tracecontext
    16  
    17  import (
    18  	"fmt"
    19  	"net/http"
    20  	"reflect"
    21  	"strings"
    22  	"testing"
    23  
    24  	"go.opencensus.io/trace"
    25  	"go.opencensus.io/trace/tracestate"
    26  )
    27  
    28  var (
    29  	tpHeader        = "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
    30  	traceID         = trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54}
    31  	spanID          = trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183}
    32  	traceOpt        = trace.TraceOptions(1)
    33  	oversizeValue   = strings.Repeat("a", maxTracestateLen/2)
    34  	oversizeEntry1  = tracestate.Entry{Key: "foo", Value: oversizeValue}
    35  	oversizeEntry2  = tracestate.Entry{Key: "hello", Value: oversizeValue}
    36  	entry1          = tracestate.Entry{Key: "foo", Value: "bar"}
    37  	entry2          = tracestate.Entry{Key: "hello", Value: "world   example"}
    38  	oversizeTs, _   = tracestate.New(nil, oversizeEntry1, oversizeEntry2)
    39  	defaultTs, _    = tracestate.New(nil, nil...)
    40  	nonDefaultTs, _ = tracestate.New(nil, entry1, entry2)
    41  )
    42  
    43  func TestHTTPFormat_FromRequest(t *testing.T) {
    44  	tests := []struct {
    45  		name   string
    46  		header string
    47  		wantSc trace.SpanContext
    48  		wantOk bool
    49  	}{
    50  		{
    51  			name:   "future version",
    52  			header: "02-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
    53  			wantSc: trace.SpanContext{
    54  				TraceID:      trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
    55  				SpanID:       trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
    56  				TraceOptions: trace.TraceOptions(1),
    57  			},
    58  			wantOk: true,
    59  		},
    60  		{
    61  			name:   "zero trace ID and span ID",
    62  			header: "00-00000000000000000000000000000000-0000000000000000-01",
    63  			wantSc: trace.SpanContext{},
    64  			wantOk: false,
    65  		},
    66  		{
    67  			name:   "valid header",
    68  			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
    69  			wantSc: trace.SpanContext{
    70  				TraceID:      trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
    71  				SpanID:       trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
    72  				TraceOptions: trace.TraceOptions(1),
    73  			},
    74  			wantOk: true,
    75  		},
    76  		{
    77  			name:   "missing options",
    78  			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7",
    79  			wantSc: trace.SpanContext{},
    80  			wantOk: false,
    81  		},
    82  		{
    83  			name:   "empty options",
    84  			header: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-",
    85  			wantSc: trace.SpanContext{},
    86  			wantOk: false,
    87  		},
    88  	}
    89  
    90  	f := &HTTPFormat{}
    91  	for _, tt := range tests {
    92  		t.Run(tt.name, func(t *testing.T) {
    93  			req, _ := http.NewRequest("GET", "http://example.com", nil)
    94  			req.Header.Set("traceparent", tt.header)
    95  
    96  			gotSc, gotOk := f.SpanContextFromRequest(req)
    97  			if !reflect.DeepEqual(gotSc, tt.wantSc) {
    98  				t.Errorf("HTTPFormat.FromRequest() gotSc = %v, want %v", gotSc, tt.wantSc)
    99  			}
   100  			if gotOk != tt.wantOk {
   101  				t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
   102  			}
   103  
   104  			gotSc, gotOk = f.SpanContextFromHeaders(tt.header, "")
   105  			if !reflect.DeepEqual(gotSc, tt.wantSc) {
   106  				t.Errorf("HTTPFormat.SpanContextFromHeaders() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
   107  			}
   108  			if gotOk != tt.wantOk {
   109  				t.Errorf("HTTPFormat.SpanContextFromHeaders() gotOk = %v, want %v", gotOk, tt.wantOk)
   110  			}
   111  		})
   112  	}
   113  }
   114  
   115  func TestHTTPFormat_ToRequest(t *testing.T) {
   116  	tests := []struct {
   117  		sc         trace.SpanContext
   118  		wantHeader string
   119  	}{
   120  		{
   121  			sc: trace.SpanContext{
   122  				TraceID:      trace.TraceID{75, 249, 47, 53, 119, 179, 77, 166, 163, 206, 146, 157, 14, 14, 71, 54},
   123  				SpanID:       trace.SpanID{0, 240, 103, 170, 11, 169, 2, 183},
   124  				TraceOptions: trace.TraceOptions(1),
   125  			},
   126  			wantHeader: "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01",
   127  		},
   128  	}
   129  	for _, tt := range tests {
   130  		t.Run(tt.wantHeader, func(t *testing.T) {
   131  			f := &HTTPFormat{}
   132  			req, _ := http.NewRequest("GET", "http://example.com", nil)
   133  			f.SpanContextToRequest(tt.sc, req)
   134  
   135  			h := req.Header.Get("traceparent")
   136  			if got, want := h, tt.wantHeader; got != want {
   137  				t.Errorf("HTTPFormat.ToRequest() header = %v, want %v", got, want)
   138  			}
   139  
   140  			gotTp, _ := f.SpanContextToHeaders(tt.sc)
   141  			if gotTp != tt.wantHeader {
   142  				t.Errorf("HTTPFormat.SpanContextToHeaders() tracestate header = %v, want %v", gotTp, tt.wantHeader)
   143  			}
   144  		})
   145  	}
   146  }
   147  
   148  func TestHTTPFormatTracestate_FromRequest(t *testing.T) {
   149  	scWithNonDefaultTracestate := trace.SpanContext{
   150  		TraceID:      traceID,
   151  		SpanID:       spanID,
   152  		TraceOptions: traceOpt,
   153  		Tracestate:   nonDefaultTs,
   154  	}
   155  
   156  	scWithDefaultTracestate := trace.SpanContext{
   157  		TraceID:      traceID,
   158  		SpanID:       spanID,
   159  		TraceOptions: traceOpt,
   160  		Tracestate:   defaultTs,
   161  	}
   162  
   163  	tests := []struct {
   164  		name     string
   165  		tpHeader string
   166  		tsHeader string
   167  		wantSc   trace.SpanContext
   168  		wantOk   bool
   169  	}{
   170  		{
   171  			name:     "tracestate invalid entries delimiter",
   172  			tpHeader: tpHeader,
   173  			tsHeader: "foo=bar;hello=world",
   174  			wantSc:   scWithDefaultTracestate,
   175  			wantOk:   true,
   176  		},
   177  		{
   178  			name:     "tracestate invalid key-value delimiter",
   179  			tpHeader: tpHeader,
   180  			tsHeader: "foo=bar,hello-world",
   181  			wantSc:   scWithDefaultTracestate,
   182  			wantOk:   true,
   183  		},
   184  		{
   185  			name:     "tracestate invalid value character",
   186  			tpHeader: tpHeader,
   187  			tsHeader: "foo=bar,hello=world   example   \u00a0  ",
   188  			wantSc:   scWithDefaultTracestate,
   189  			wantOk:   true,
   190  		},
   191  		{
   192  			name:     "tracestate blank key-value",
   193  			tpHeader: tpHeader,
   194  			tsHeader: "foo=bar,    ",
   195  			wantSc:   scWithDefaultTracestate,
   196  			wantOk:   true,
   197  		},
   198  		{
   199  			name:     "tracestate oversize header",
   200  			tpHeader: tpHeader,
   201  			tsHeader: fmt.Sprintf("foo=%s,hello=%s", oversizeValue, oversizeValue),
   202  			wantSc:   scWithDefaultTracestate,
   203  			wantOk:   true,
   204  		},
   205  		{
   206  			name:     "tracestate valid",
   207  			tpHeader: tpHeader,
   208  			tsHeader: "foo=bar   ,   hello=world   example",
   209  			wantSc:   scWithNonDefaultTracestate,
   210  			wantOk:   true,
   211  		},
   212  	}
   213  
   214  	f := &HTTPFormat{}
   215  	for _, tt := range tests {
   216  		t.Run(tt.name, func(t *testing.T) {
   217  			req, _ := http.NewRequest("GET", "http://example.com", nil)
   218  			req.Header.Set("traceparent", tt.tpHeader)
   219  			req.Header.Set("tracestate", tt.tsHeader)
   220  
   221  			gotSc, gotOk := f.SpanContextFromRequest(req)
   222  			if !reflect.DeepEqual(gotSc, tt.wantSc) {
   223  				t.Errorf("HTTPFormat.FromRequest() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
   224  			}
   225  			if gotOk != tt.wantOk {
   226  				t.Errorf("HTTPFormat.FromRequest() gotOk = %v, want %v", gotOk, tt.wantOk)
   227  			}
   228  
   229  			gotSc, gotOk = f.SpanContextFromHeaders(tt.tpHeader, tt.tsHeader)
   230  			if !reflect.DeepEqual(gotSc, tt.wantSc) {
   231  				t.Errorf("HTTPFormat.SpanContextFromHeaders() gotTs = %v, want %v", gotSc.Tracestate, tt.wantSc.Tracestate)
   232  			}
   233  			if gotOk != tt.wantOk {
   234  				t.Errorf("HTTPFormat.SpanContextFromHeaders() gotOk = %v, want %v", gotOk, tt.wantOk)
   235  			}
   236  		})
   237  	}
   238  }
   239  
   240  func TestHTTPFormatTracestate_ToRequest(t *testing.T) {
   241  	tests := []struct {
   242  		name       string
   243  		sc         trace.SpanContext
   244  		wantHeader string
   245  	}{
   246  		{
   247  			name: "valid span context with default tracestate",
   248  			sc: trace.SpanContext{
   249  				TraceID:      traceID,
   250  				SpanID:       spanID,
   251  				TraceOptions: traceOpt,
   252  			},
   253  			wantHeader: "",
   254  		},
   255  		{
   256  			name: "valid span context with non default tracestate",
   257  			sc: trace.SpanContext{
   258  				TraceID:      traceID,
   259  				SpanID:       spanID,
   260  				TraceOptions: traceOpt,
   261  				Tracestate:   nonDefaultTs,
   262  			},
   263  			wantHeader: "foo=bar,hello=world   example",
   264  		},
   265  		{
   266  			name: "valid span context with oversize tracestate",
   267  			sc: trace.SpanContext{
   268  				TraceID:      traceID,
   269  				SpanID:       spanID,
   270  				TraceOptions: traceOpt,
   271  				Tracestate:   oversizeTs,
   272  			},
   273  			wantHeader: "",
   274  		},
   275  	}
   276  	for _, tt := range tests {
   277  		t.Run(tt.name, func(t *testing.T) {
   278  			f := &HTTPFormat{}
   279  			req, _ := http.NewRequest("GET", "http://example.com", nil)
   280  			f.SpanContextToRequest(tt.sc, req)
   281  
   282  			h := req.Header.Get("tracestate")
   283  			if got, want := h, tt.wantHeader; got != want {
   284  				t.Errorf("HTTPFormat.ToRequest() tracestate header = %v, want %v", got, want)
   285  			}
   286  
   287  			_, gotTs := f.SpanContextToHeaders(tt.sc)
   288  			if gotTs != tt.wantHeader {
   289  				t.Errorf("HTTPFormat.SpanContextToHeaders() tracestate header = %v, want %v", gotTs, tt.wantHeader)
   290  			}
   291  		})
   292  	}
   293  }
   294  

View as plain text