...

Source file src/go.opentelemetry.io/otel/trace/tracestate_test.go

Documentation: go.opentelemetry.io/otel/trace

     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 trace
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  // Taken from the W3C tests:
    27  // https://github.com/w3c/trace-context/blob/dcd3ad9b7d6ac36f70ff3739874b73c11b0302a1/test/test_data.json
    28  var testcases = []struct {
    29  	name       string
    30  	in         string
    31  	tracestate TraceState
    32  	out        string
    33  	err        error
    34  }{
    35  	{
    36  		name: "duplicate with the same value",
    37  		in:   "foo=1,foo=1",
    38  		err:  errDuplicate,
    39  	},
    40  	{
    41  		name: "duplicate with different values",
    42  		in:   "foo=1,foo=2",
    43  		err:  errDuplicate,
    44  	},
    45  	{
    46  		name: "improperly formatted key/value pair",
    47  		in:   "foo =1",
    48  		err:  errInvalidMember,
    49  	},
    50  	{
    51  		name: "upper case key",
    52  		in:   "FOO=1",
    53  		err:  errInvalidMember,
    54  	},
    55  	{
    56  		name: "key with invalid character",
    57  		in:   "foo.bar=1",
    58  		err:  errInvalidMember,
    59  	},
    60  	{
    61  		name: "multiple keys, one with empty tenant key",
    62  		in:   "foo@=1,bar=2",
    63  		err:  errInvalidMember,
    64  	},
    65  	{
    66  		name: "multiple keys, one with only tenant",
    67  		in:   "@foo=1,bar=2",
    68  		err:  errInvalidMember,
    69  	},
    70  	{
    71  		name: "multiple keys, one with double tenant separator",
    72  		in:   "foo@@bar=1,bar=2",
    73  		err:  errInvalidMember,
    74  	},
    75  	{
    76  		name: "multiple keys, one with multiple tenants",
    77  		in:   "foo@bar@baz=1,bar=2",
    78  		err:  errInvalidMember,
    79  	},
    80  	{
    81  		name: "key too long",
    82  		in:   "foo=1,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=1",
    83  		err:  errInvalidMember,
    84  	},
    85  	{
    86  		name: "key too long, with tenant",
    87  		in:   "foo=1,tttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt@v=1",
    88  		err:  errInvalidMember,
    89  	},
    90  	{
    91  		name: "tenant too long",
    92  		in:   "foo=1,t@vvvvvvvvvvvvvvv=1",
    93  		err:  errInvalidMember,
    94  	},
    95  	{
    96  		name: "multiple values for a single key",
    97  		in:   "foo=bar=baz",
    98  		err:  errInvalidMember,
    99  	},
   100  	{
   101  		name: "no value",
   102  		in:   "foo=,bar=3",
   103  		err:  errInvalidMember,
   104  	},
   105  	{
   106  		name: "too many members",
   107  		in:   "bar01=01,bar02=02,bar03=03,bar04=04,bar05=05,bar06=06,bar07=07,bar08=08,bar09=09,bar10=10,bar11=11,bar12=12,bar13=13,bar14=14,bar15=15,bar16=16,bar17=17,bar18=18,bar19=19,bar20=20,bar21=21,bar22=22,bar23=23,bar24=24,bar25=25,bar26=26,bar27=27,bar28=28,bar29=29,bar30=30,bar31=31,bar32=32,bar33=33",
   108  		err:  errMemberNumber,
   109  	},
   110  	{
   111  		name: "valid key/value list",
   112  		in:   "abcdefghijklmnopqrstuvwxyz0123456789_-*/= !\"#$%&'()*+-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
   113  		out:  "abcdefghijklmnopqrstuvwxyz0123456789_-*/= !\"#$%&'()*+-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
   114  		tracestate: TraceState{list: []member{
   115  			{
   116  				Key:   "abcdefghijklmnopqrstuvwxyz0123456789_-*/",
   117  				Value: " !\"#$%&'()*+-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
   118  			},
   119  		}},
   120  	},
   121  	{
   122  		name: "valid key/value list with tenant",
   123  		in:   "abcdefghijklmnopqrstuvwxyz0123456789_-*/@a-z0-9_-*/= !\"#$%&'()*+-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
   124  		out:  "abcdefghijklmnopqrstuvwxyz0123456789_-*/@a-z0-9_-*/= !\"#$%&'()*+-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
   125  		tracestate: TraceState{list: []member{
   126  			{
   127  				Key:   "abcdefghijklmnopqrstuvwxyz0123456789_-*/@a-z0-9_-*/",
   128  				Value: " !\"#$%&'()*+-./0123456789:;<>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~",
   129  			},
   130  		}},
   131  	},
   132  	{
   133  		name: "empty input",
   134  		// Empty input should result in no error and a zero value
   135  		// TraceState being returned, that TraceState should be encoded as an
   136  		// empty string.
   137  	},
   138  	{
   139  		name: "single key and value",
   140  		in:   "foo=1",
   141  		out:  "foo=1",
   142  		tracestate: TraceState{list: []member{
   143  			{Key: "foo", Value: "1"},
   144  		}},
   145  	},
   146  	{
   147  		name: "single key and value with empty separator",
   148  		in:   "foo=1,",
   149  		out:  "foo=1",
   150  		tracestate: TraceState{list: []member{
   151  			{Key: "foo", Value: "1"},
   152  		}},
   153  	},
   154  	{
   155  		name: "multiple keys and values",
   156  		in:   "foo=1,bar=2",
   157  		out:  "foo=1,bar=2",
   158  		tracestate: TraceState{list: []member{
   159  			{Key: "foo", Value: "1"},
   160  			{Key: "bar", Value: "2"},
   161  		}},
   162  	},
   163  	{
   164  		name: "with a key at maximum length",
   165  		in:   "foo=1,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=1",
   166  		out:  "foo=1,zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz=1",
   167  		tracestate: TraceState{list: []member{
   168  			{
   169  				Key:   "foo",
   170  				Value: "1",
   171  			},
   172  			{
   173  				Key:   "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
   174  				Value: "1",
   175  			},
   176  		}},
   177  	},
   178  	{
   179  		name: "with a key and tenant at maximum length",
   180  		in:   "foo=1,ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt@vvvvvvvvvvvvvv=1",
   181  		out:  "foo=1,ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt@vvvvvvvvvvvvvv=1",
   182  		tracestate: TraceState{list: []member{
   183  			{
   184  				Key:   "foo",
   185  				Value: "1",
   186  			},
   187  			{
   188  				Key:   "ttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttttt@vvvvvvvvvvvvvv",
   189  				Value: "1",
   190  			},
   191  		}},
   192  	},
   193  	{
   194  		name: "with maximum members",
   195  		in:   "bar01=01,bar02=02,bar03=03,bar04=04,bar05=05,bar06=06,bar07=07,bar08=08,bar09=09,bar10=10,bar11=11,bar12=12,bar13=13,bar14=14,bar15=15,bar16=16,bar17=17,bar18=18,bar19=19,bar20=20,bar21=21,bar22=22,bar23=23,bar24=24,bar25=25,bar26=26,bar27=27,bar28=28,bar29=29,bar30=30,bar31=31,bar32=32",
   196  		out:  "bar01=01,bar02=02,bar03=03,bar04=04,bar05=05,bar06=06,bar07=07,bar08=08,bar09=09,bar10=10,bar11=11,bar12=12,bar13=13,bar14=14,bar15=15,bar16=16,bar17=17,bar18=18,bar19=19,bar20=20,bar21=21,bar22=22,bar23=23,bar24=24,bar25=25,bar26=26,bar27=27,bar28=28,bar29=29,bar30=30,bar31=31,bar32=32",
   197  		tracestate: TraceState{list: []member{
   198  			{Key: "bar01", Value: "01"},
   199  			{Key: "bar02", Value: "02"},
   200  			{Key: "bar03", Value: "03"},
   201  			{Key: "bar04", Value: "04"},
   202  			{Key: "bar05", Value: "05"},
   203  			{Key: "bar06", Value: "06"},
   204  			{Key: "bar07", Value: "07"},
   205  			{Key: "bar08", Value: "08"},
   206  			{Key: "bar09", Value: "09"},
   207  			{Key: "bar10", Value: "10"},
   208  			{Key: "bar11", Value: "11"},
   209  			{Key: "bar12", Value: "12"},
   210  			{Key: "bar13", Value: "13"},
   211  			{Key: "bar14", Value: "14"},
   212  			{Key: "bar15", Value: "15"},
   213  			{Key: "bar16", Value: "16"},
   214  			{Key: "bar17", Value: "17"},
   215  			{Key: "bar18", Value: "18"},
   216  			{Key: "bar19", Value: "19"},
   217  			{Key: "bar20", Value: "20"},
   218  			{Key: "bar21", Value: "21"},
   219  			{Key: "bar22", Value: "22"},
   220  			{Key: "bar23", Value: "23"},
   221  			{Key: "bar24", Value: "24"},
   222  			{Key: "bar25", Value: "25"},
   223  			{Key: "bar26", Value: "26"},
   224  			{Key: "bar27", Value: "27"},
   225  			{Key: "bar28", Value: "28"},
   226  			{Key: "bar29", Value: "29"},
   227  			{Key: "bar30", Value: "30"},
   228  			{Key: "bar31", Value: "31"},
   229  			{Key: "bar32", Value: "32"},
   230  		}},
   231  	},
   232  	{
   233  		name: "with several members",
   234  		in:   "foo=1,bar=2,rojo=1,congo=2,baz=3",
   235  		out:  "foo=1,bar=2,rojo=1,congo=2,baz=3",
   236  		tracestate: TraceState{list: []member{
   237  			{Key: "foo", Value: "1"},
   238  			{Key: "bar", Value: "2"},
   239  			{Key: "rojo", Value: "1"},
   240  			{Key: "congo", Value: "2"},
   241  			{Key: "baz", Value: "3"},
   242  		}},
   243  	},
   244  	{
   245  		name: "with tabs between members",
   246  		in:   "foo=1 \t , \t bar=2, \t baz=3",
   247  		out:  "foo=1,bar=2,baz=3",
   248  		tracestate: TraceState{list: []member{
   249  			{Key: "foo", Value: "1"},
   250  			{Key: "bar", Value: "2"},
   251  			{Key: "baz", Value: "3"},
   252  		}},
   253  	},
   254  	{
   255  		name: "with multiple tabs between members",
   256  		in:   "foo=1\t \t,\t \tbar=2,\t \tbaz=3",
   257  		out:  "foo=1,bar=2,baz=3",
   258  		tracestate: TraceState{list: []member{
   259  			{Key: "foo", Value: "1"},
   260  			{Key: "bar", Value: "2"},
   261  			{Key: "baz", Value: "3"},
   262  		}},
   263  	},
   264  	{
   265  		name: "with space at the end of the member",
   266  		in:   "foo=1 ",
   267  		out:  "foo=1",
   268  		tracestate: TraceState{list: []member{
   269  			{Key: "foo", Value: "1"},
   270  		}},
   271  	},
   272  	{
   273  		name: "with tab at the end of the member",
   274  		in:   "foo=1\t",
   275  		out:  "foo=1",
   276  		tracestate: TraceState{list: []member{
   277  			{Key: "foo", Value: "1"},
   278  		}},
   279  	},
   280  	{
   281  		name: "with tab and space at the end of the member",
   282  		in:   "foo=1 \t",
   283  		out:  "foo=1",
   284  		tracestate: TraceState{list: []member{
   285  			{Key: "foo", Value: "1"},
   286  		}},
   287  	},
   288  }
   289  
   290  var maxMembers = func() TraceState {
   291  	members := make([]member, maxListMembers)
   292  	for i := 0; i < maxListMembers; i++ {
   293  		members[i] = member{
   294  			Key:   fmt.Sprintf("key%d", i+1),
   295  			Value: fmt.Sprintf("value%d", i+1),
   296  		}
   297  	}
   298  	return TraceState{list: members}
   299  }()
   300  
   301  func TestParseTraceState(t *testing.T) {
   302  	for _, tc := range testcases {
   303  		t.Run(tc.name, func(t *testing.T) {
   304  			got, err := ParseTraceState(tc.in)
   305  			assert.Equal(t, tc.tracestate, got)
   306  			if tc.err != nil {
   307  				assert.ErrorIs(t, err, tc.err, tc.in)
   308  			} else {
   309  				assert.NoError(t, err, tc.in)
   310  			}
   311  		})
   312  	}
   313  }
   314  
   315  func TestTraceStateString(t *testing.T) {
   316  	for _, tc := range testcases {
   317  		if tc.err != nil {
   318  			// Only test non-zero value TraceState.
   319  			continue
   320  		}
   321  		t.Run(tc.name, func(t *testing.T) {
   322  			assert.Equal(t, tc.out, tc.tracestate.String())
   323  		})
   324  	}
   325  }
   326  
   327  func TestTraceStateMarshalJSON(t *testing.T) {
   328  	for _, tc := range testcases {
   329  		if tc.err != nil {
   330  			// Only test non-zero value TraceState.
   331  			continue
   332  		}
   333  		t.Run(tc.name, func(t *testing.T) {
   334  			// Encode UTF-8.
   335  			expected, err := json.Marshal(tc.out)
   336  			require.NoError(t, err)
   337  
   338  			actual, err := json.Marshal(tc.tracestate)
   339  			require.NoError(t, err)
   340  
   341  			assert.Equal(t, expected, actual)
   342  		})
   343  	}
   344  }
   345  
   346  func TestTraceStateGet(t *testing.T) {
   347  	testCases := []struct {
   348  		name     string
   349  		key      string
   350  		expected string
   351  	}{
   352  		{
   353  			name:     "OK case",
   354  			key:      "key16",
   355  			expected: "value16",
   356  		},
   357  		{
   358  			name:     "not found",
   359  			key:      "keyxx",
   360  			expected: "",
   361  		},
   362  		{
   363  			name:     "invalid W3C key",
   364  			key:      "key!",
   365  			expected: "",
   366  		},
   367  	}
   368  
   369  	for _, tc := range testCases {
   370  		t.Run(tc.name, func(t *testing.T) {
   371  			assert.Equal(t, tc.expected, maxMembers.Get(tc.key))
   372  		})
   373  	}
   374  }
   375  
   376  func TestTraceStateDelete(t *testing.T) {
   377  	ts := TraceState{list: []member{
   378  		{Key: "key1", Value: "val1"},
   379  		{Key: "key2", Value: "val2"},
   380  		{Key: "key3", Value: "val3"},
   381  	}}
   382  
   383  	testCases := []struct {
   384  		name     string
   385  		key      string
   386  		expected TraceState
   387  	}{
   388  		{
   389  			name: "OK case",
   390  			key:  "key2",
   391  			expected: TraceState{list: []member{
   392  				{Key: "key1", Value: "val1"},
   393  				{Key: "key3", Value: "val3"},
   394  			}},
   395  		},
   396  		{
   397  			name: "Non-existing key",
   398  			key:  "keyx",
   399  			expected: TraceState{list: []member{
   400  				{Key: "key1", Value: "val1"},
   401  				{Key: "key2", Value: "val2"},
   402  				{Key: "key3", Value: "val3"},
   403  			}},
   404  		},
   405  		{
   406  			name: "Invalid key",
   407  			key:  "in va lid",
   408  			expected: TraceState{list: []member{
   409  				{Key: "key1", Value: "val1"},
   410  				{Key: "key2", Value: "val2"},
   411  				{Key: "key3", Value: "val3"},
   412  			}},
   413  		},
   414  	}
   415  
   416  	for _, tc := range testCases {
   417  		t.Run(tc.name, func(t *testing.T) {
   418  			assert.Equal(t, tc.expected, ts.Delete(tc.key))
   419  		})
   420  	}
   421  }
   422  
   423  func TestTraceStateInsert(t *testing.T) {
   424  	ts := TraceState{list: []member{
   425  		{Key: "key1", Value: "val1"},
   426  		{Key: "key2", Value: "val2"},
   427  		{Key: "key3", Value: "val3"},
   428  	}}
   429  
   430  	testCases := []struct {
   431  		name       string
   432  		tracestate TraceState
   433  		key, value string
   434  		expected   TraceState
   435  		err        error
   436  	}{
   437  		{
   438  			name:       "add new",
   439  			tracestate: ts,
   440  			key:        "key4@vendor",
   441  			value:      "val4",
   442  			expected: TraceState{list: []member{
   443  				{Key: "key4@vendor", Value: "val4"},
   444  				{Key: "key1", Value: "val1"},
   445  				{Key: "key2", Value: "val2"},
   446  				{Key: "key3", Value: "val3"},
   447  			}},
   448  		},
   449  		{
   450  			name:       "replace",
   451  			tracestate: ts,
   452  			key:        "key2",
   453  			value:      "valX",
   454  			expected: TraceState{list: []member{
   455  				{Key: "key2", Value: "valX"},
   456  				{Key: "key1", Value: "val1"},
   457  				{Key: "key3", Value: "val3"},
   458  			}},
   459  		},
   460  		{
   461  			name:       "invalid key",
   462  			tracestate: ts,
   463  			key:        "key!",
   464  			value:      "val",
   465  			expected:   ts,
   466  			err:        errInvalidKey,
   467  		},
   468  		{
   469  			name:       "invalid value",
   470  			tracestate: ts,
   471  			key:        "key",
   472  			value:      "v=l",
   473  			expected:   ts,
   474  			err:        errInvalidValue,
   475  		},
   476  		{
   477  			name:       "invalid key/value",
   478  			tracestate: ts,
   479  			key:        "key!",
   480  			value:      "v=l",
   481  			expected:   ts,
   482  			err:        errInvalidKey,
   483  		},
   484  		{
   485  			name:       "drop the right-most member(oldest) in queue",
   486  			tracestate: maxMembers,
   487  			key:        "keyx",
   488  			value:      "valx",
   489  			expected: func() TraceState {
   490  				// Prepend the new element and remove the oldest one, which is over capacity.
   491  				return TraceState{
   492  					list: append(
   493  						[]member{{Key: "keyx", Value: "valx"}},
   494  						maxMembers.list[:len(maxMembers.list)-1]...,
   495  					),
   496  				}
   497  			}(),
   498  		},
   499  	}
   500  
   501  	for _, tc := range testCases {
   502  		t.Run(tc.name, func(t *testing.T) {
   503  			actual, err := tc.tracestate.Insert(tc.key, tc.value)
   504  			assert.ErrorIs(t, err, tc.err, tc.name)
   505  			if tc.err != nil {
   506  				assert.Equal(t, tc.tracestate, actual)
   507  			} else {
   508  				assert.Equal(t, tc.expected, actual)
   509  			}
   510  		})
   511  	}
   512  }
   513  
   514  func TestTraceStateLen(t *testing.T) {
   515  	ts := TraceState{}
   516  	assert.Equal(t, 0, ts.Len(), "zero value TraceState is empty")
   517  
   518  	key := "key"
   519  	ts = TraceState{list: []member{{key, "value"}}}
   520  	assert.Equal(t, 1, ts.Len(), "TraceState with one value")
   521  }
   522  
   523  func TestTraceStateImmutable(t *testing.T) {
   524  	k0, v0 := "k0", "v0"
   525  	ts0 := TraceState{list: []member{{k0, v0}}}
   526  	assert.Equal(t, v0, ts0.Get(k0))
   527  
   528  	// Insert should not modify the original.
   529  	k1, v1 := "k1", "v1"
   530  	ts1, err := ts0.Insert(k1, v1)
   531  	require.NoError(t, err)
   532  	assert.Equal(t, v0, ts0.Get(k0))
   533  	assert.Equal(t, "", ts0.Get(k1))
   534  	assert.Equal(t, v0, ts1.Get(k0))
   535  	assert.Equal(t, v1, ts1.Get(k1))
   536  
   537  	// Update should not modify the original.
   538  	v2 := "v2"
   539  	ts2, err := ts1.Insert(k1, v2)
   540  	require.NoError(t, err)
   541  	assert.Equal(t, v0, ts0.Get(k0))
   542  	assert.Equal(t, "", ts0.Get(k1))
   543  	assert.Equal(t, v0, ts1.Get(k0))
   544  	assert.Equal(t, v1, ts1.Get(k1))
   545  	assert.Equal(t, v0, ts2.Get(k0))
   546  	assert.Equal(t, v2, ts2.Get(k1))
   547  
   548  	// Delete should not modify the original.
   549  	ts3 := ts2.Delete(k0)
   550  	assert.Equal(t, v0, ts0.Get(k0))
   551  	assert.Equal(t, v0, ts1.Get(k0))
   552  	assert.Equal(t, v0, ts2.Get(k0))
   553  	assert.Equal(t, "", ts3.Get(k0))
   554  }
   555  
   556  func BenchmarkParseTraceState(b *testing.B) {
   557  	benches := []struct {
   558  		name string
   559  		in   string
   560  	}{
   561  		{
   562  			name: "single key",
   563  			in:   "somewhatRealisticKeyLength=someValueAbcdefgh1234567890",
   564  		},
   565  		{
   566  			name: "tenant single key",
   567  			in:   "somewhatRealisticKeyLength@someTenant=someValueAbcdefgh1234567890",
   568  		},
   569  		{
   570  			name: "three keys",
   571  			in:   "someKeyName.One=someValue1,someKeyName.Two=someValue2,someKeyName.Three=someValue3",
   572  		},
   573  		{
   574  			name: "tenant three keys",
   575  			in:   "someKeyName.One@tenant=someValue1,someKeyName.Two@tenant=someValue2,someKeyName.Three@tenant=someValue3",
   576  		},
   577  	}
   578  	for _, bench := range benches {
   579  		b.Run(bench.name, func(b *testing.B) {
   580  			b.ReportAllocs()
   581  			b.ResetTimer()
   582  
   583  			for i := 0; i < b.N; i++ {
   584  				_, _ = ParseTraceState(bench.in)
   585  			}
   586  		})
   587  	}
   588  }
   589  

View as plain text