...

Source file src/go.opentelemetry.io/otel/propagation/baggage_test.go

Documentation: go.opentelemetry.io/otel/propagation

     1  // Copyright The OpenTelemetry 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 propagation_test
    16  
    17  import (
    18  	"context"
    19  	"net/http"
    20  	"net/url"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/stretchr/testify/assert"
    26  
    27  	"go.opentelemetry.io/otel/baggage"
    28  	"go.opentelemetry.io/otel/propagation"
    29  )
    30  
    31  type property struct {
    32  	Key, Value string
    33  }
    34  
    35  type member struct {
    36  	Key, Value string
    37  
    38  	Properties []property
    39  }
    40  
    41  func (m member) Member(t *testing.T) baggage.Member {
    42  	props := make([]baggage.Property, 0, len(m.Properties))
    43  	for _, p := range m.Properties {
    44  		p, err := baggage.NewKeyValueProperty(p.Key, p.Value)
    45  		if err != nil {
    46  			t.Fatal(err)
    47  		}
    48  		props = append(props, p)
    49  	}
    50  	bMember, err := baggage.NewMember(m.Key, url.QueryEscape(m.Value), props...)
    51  	if err != nil {
    52  		t.Fatal(err)
    53  	}
    54  	return bMember
    55  }
    56  
    57  type members []member
    58  
    59  func (m members) Baggage(t *testing.T) baggage.Baggage {
    60  	bMembers := make([]baggage.Member, 0, len(m))
    61  	for _, mem := range m {
    62  		bMembers = append(bMembers, mem.Member(t))
    63  	}
    64  	bag, err := baggage.New(bMembers...)
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	return bag
    69  }
    70  
    71  func TestExtractValidBaggageFromHTTPReq(t *testing.T) {
    72  	prop := propagation.TextMapPropagator(propagation.Baggage{})
    73  	tests := []struct {
    74  		name   string
    75  		header string
    76  		want   members
    77  	}{
    78  		{
    79  			name:   "valid w3cHeader",
    80  			header: "key1=val1,key2=val2",
    81  			want: members{
    82  				{Key: "key1", Value: "val1"},
    83  				{Key: "key2", Value: "val2"},
    84  			},
    85  		},
    86  		{
    87  			name:   "valid w3cHeader with spaces",
    88  			header: "key1 =   val1,  key2 =val2   ",
    89  			want: members{
    90  				{Key: "key1", Value: "val1"},
    91  				{Key: "key2", Value: "val2"},
    92  			},
    93  		},
    94  		{
    95  			name:   "valid w3cHeader with properties",
    96  			header: "key1=val1,key2=val2;prop=1",
    97  			want: members{
    98  				{Key: "key1", Value: "val1"},
    99  				{
   100  					Key:   "key2",
   101  					Value: "val2",
   102  					Properties: []property{
   103  						{Key: "prop", Value: "1"},
   104  					},
   105  				},
   106  			},
   107  		},
   108  		{
   109  			name:   "valid header with an invalid header",
   110  			header: "key1=val1,key2=val2,a,val3",
   111  			want:   members{},
   112  		},
   113  		{
   114  			name:   "valid header with no value",
   115  			header: "key1=,key2=val2",
   116  			want: members{
   117  				{Key: "key1", Value: ""},
   118  				{Key: "key2", Value: "val2"},
   119  			},
   120  		},
   121  		{
   122  			name:   "valid header with url encoded string",
   123  			header: "key1=val%252",
   124  			want: members{
   125  				{Key: "key1", Value: "val%2"},
   126  			},
   127  		},
   128  	}
   129  
   130  	for _, tt := range tests {
   131  		t.Run(tt.name, func(t *testing.T) {
   132  			req, _ := http.NewRequest("GET", "http://example.com", nil)
   133  			req.Header.Set("baggage", tt.header)
   134  
   135  			ctx := context.Background()
   136  			ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
   137  			expected := tt.want.Baggage(t)
   138  			assert.Equal(t, expected, baggage.FromContext(ctx))
   139  		})
   140  	}
   141  }
   142  
   143  func TestExtractInvalidDistributedContextFromHTTPReq(t *testing.T) {
   144  	prop := propagation.TextMapPropagator(propagation.Baggage{})
   145  	tests := []struct {
   146  		name   string
   147  		header string
   148  		has    members
   149  	}{
   150  		{
   151  			name:   "no key values",
   152  			header: "header1",
   153  		},
   154  		{
   155  			name:   "invalid header with existing context",
   156  			header: "header2",
   157  			has: members{
   158  				{Key: "key1", Value: "val1"},
   159  				{Key: "key2", Value: "val2"},
   160  			},
   161  		},
   162  		{
   163  			name:   "empty header value",
   164  			header: "",
   165  			has: members{
   166  				{Key: "key1", Value: "val1"},
   167  				{Key: "key2", Value: "val2"},
   168  			},
   169  		},
   170  		{
   171  			name:   "with properties",
   172  			header: "key1=val1,key2=val2;prop=1",
   173  			has: members{
   174  				{Key: "key1", Value: "val1"},
   175  				{
   176  					Key:   "key2",
   177  					Value: "val2",
   178  					Properties: []property{
   179  						{Key: "prop", Value: "1"},
   180  					},
   181  				},
   182  			},
   183  		},
   184  	}
   185  
   186  	for _, tt := range tests {
   187  		t.Run(tt.name, func(t *testing.T) {
   188  			req, _ := http.NewRequest("GET", "http://example.com", nil)
   189  			req.Header.Set("baggage", tt.header)
   190  
   191  			expected := tt.has.Baggage(t)
   192  			ctx := baggage.ContextWithBaggage(context.Background(), expected)
   193  			ctx = prop.Extract(ctx, propagation.HeaderCarrier(req.Header))
   194  			assert.Equal(t, expected, baggage.FromContext(ctx))
   195  		})
   196  	}
   197  }
   198  
   199  func TestInjectBaggageToHTTPReq(t *testing.T) {
   200  	propagator := propagation.Baggage{}
   201  	tests := []struct {
   202  		name         string
   203  		mems         members
   204  		wantInHeader []string
   205  	}{
   206  		{
   207  			name: "two simple values",
   208  			mems: members{
   209  				{Key: "key1", Value: "val1"},
   210  				{Key: "key2", Value: "val2"},
   211  			},
   212  			wantInHeader: []string{"key1=val1", "key2=val2"},
   213  		},
   214  		{
   215  			name: "values with escaped chars",
   216  			mems: members{
   217  				{Key: "key2", Value: "val3=4"},
   218  			},
   219  			wantInHeader: []string{"key2=val3%3D4"},
   220  		},
   221  		{
   222  			name: "with properties",
   223  			mems: members{
   224  				{Key: "key1", Value: "val1"},
   225  				{
   226  					Key:   "key2",
   227  					Value: "val2",
   228  					Properties: []property{
   229  						{Key: "prop", Value: "1"},
   230  					},
   231  				},
   232  			},
   233  			wantInHeader: []string{
   234  				"key1=val1",
   235  				"key2=val2;prop=1",
   236  			},
   237  		},
   238  	}
   239  	for _, tt := range tests {
   240  		t.Run(tt.name, func(t *testing.T) {
   241  			req, _ := http.NewRequest("GET", "http://example.com", nil)
   242  			ctx := baggage.ContextWithBaggage(context.Background(), tt.mems.Baggage(t))
   243  			propagator.Inject(ctx, propagation.HeaderCarrier(req.Header))
   244  
   245  			got := strings.Split(req.Header.Get("baggage"), ",")
   246  			assert.ElementsMatch(t, tt.wantInHeader, got)
   247  		})
   248  	}
   249  }
   250  
   251  func TestBaggagePropagatorGetAllKeys(t *testing.T) {
   252  	var propagator propagation.Baggage
   253  	want := []string{"baggage"}
   254  	got := propagator.Fields()
   255  	if diff := cmp.Diff(got, want); diff != "" {
   256  		t.Errorf("GetAllKeys: -got +want %s", diff)
   257  	}
   258  }
   259  

View as plain text