...

Source file src/go.opentelemetry.io/otel/attribute/set_test.go

Documentation: go.opentelemetry.io/otel/attribute

     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 attribute_test
    16  
    17  import (
    18  	"reflect"
    19  	"regexp"
    20  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  
    25  	"go.opentelemetry.io/otel/attribute"
    26  )
    27  
    28  type testCase struct {
    29  	kvs []attribute.KeyValue
    30  
    31  	keyRe *regexp.Regexp
    32  
    33  	encoding string
    34  	fullEnc  string
    35  }
    36  
    37  func expect(enc string, kvs ...attribute.KeyValue) testCase {
    38  	return testCase{
    39  		kvs:      kvs,
    40  		encoding: enc,
    41  	}
    42  }
    43  
    44  func expectFiltered(enc, filter, fullEnc string, kvs ...attribute.KeyValue) testCase {
    45  	return testCase{
    46  		kvs:      kvs,
    47  		keyRe:    regexp.MustCompile(filter),
    48  		encoding: enc,
    49  		fullEnc:  fullEnc,
    50  	}
    51  }
    52  
    53  func TestSetDedup(t *testing.T) {
    54  	cases := []testCase{
    55  		expect("A=B", attribute.String("A", "2"), attribute.String("A", "B")),
    56  		expect("A=B", attribute.String("A", "2"), attribute.Int("A", 1), attribute.String("A", "B")),
    57  		expect("A=B", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
    58  
    59  		expect("A=B,C=D", attribute.String("A", "1"), attribute.String("C", "D"), attribute.String("A", "B")),
    60  		expect("A=B,C=D", attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
    61  		expect("A=B,C=D", attribute.Float64("C", 1.2), attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
    62  		expect("A=B,C=D", attribute.String("C", "D"), attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
    63  		expect("A=B,C=D", attribute.String("A", "B"), attribute.String("C", "D"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
    64  		expect("A=B,C=D", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B"), attribute.String("C", "D")),
    65  	}
    66  	enc := attribute.DefaultEncoder()
    67  
    68  	s2d := map[string][]attribute.Distinct{}
    69  	d2s := map[attribute.Distinct][]string{}
    70  
    71  	for _, tc := range cases {
    72  		cpy := make([]attribute.KeyValue, len(tc.kvs))
    73  		copy(cpy, tc.kvs)
    74  		sl := attribute.NewSet(cpy...)
    75  
    76  		// Ensure that the input was reordered but no elements went missing.
    77  		require.ElementsMatch(t, tc.kvs, cpy)
    78  
    79  		str := sl.Encoded(enc)
    80  		equ := sl.Equivalent()
    81  
    82  		s2d[str] = append(s2d[str], equ)
    83  		d2s[equ] = append(d2s[equ], str)
    84  
    85  		require.Equal(t, tc.encoding, str)
    86  	}
    87  
    88  	for s, d := range s2d {
    89  		// No other Distinct values are equal to this.
    90  		for s2, d2 := range s2d {
    91  			if s2 == s {
    92  				continue
    93  			}
    94  			for _, elt := range d {
    95  				for _, otherDistinct := range d2 {
    96  					require.NotEqual(t, otherDistinct, elt)
    97  				}
    98  			}
    99  		}
   100  		for _, strings := range d2s {
   101  			if strings[0] == s {
   102  				continue
   103  			}
   104  			for _, otherString := range strings {
   105  				require.NotEqual(t, otherString, s)
   106  			}
   107  		}
   108  	}
   109  
   110  	for d, s := range d2s {
   111  		// No other Distinct values are equal to this.
   112  		for d2, s2 := range d2s {
   113  			if d2 == d {
   114  				continue
   115  			}
   116  			for _, elt := range s {
   117  				for _, otherDistinct := range s2 {
   118  					require.NotEqual(t, otherDistinct, elt)
   119  				}
   120  			}
   121  		}
   122  		for _, distincts := range s2d {
   123  			if distincts[0] == d {
   124  				continue
   125  			}
   126  			for _, otherDistinct := range distincts {
   127  				require.NotEqual(t, otherDistinct, d)
   128  			}
   129  		}
   130  	}
   131  }
   132  
   133  func TestUniqueness(t *testing.T) {
   134  	short := []attribute.KeyValue{
   135  		attribute.String("A", "0"),
   136  		attribute.String("B", "2"),
   137  		attribute.String("A", "1"),
   138  	}
   139  	long := []attribute.KeyValue{
   140  		attribute.String("B", "2"),
   141  		attribute.String("C", "5"),
   142  		attribute.String("B", "2"),
   143  		attribute.String("C", "1"),
   144  		attribute.String("A", "4"),
   145  		attribute.String("C", "3"),
   146  		attribute.String("A", "1"),
   147  	}
   148  	cases := []testCase{
   149  		expectFiltered("A=1", "^A$", "B=2", short...),
   150  		expectFiltered("B=2", "^B$", "A=1", short...),
   151  		expectFiltered("A=1,B=2", "^A|B$", "", short...),
   152  		expectFiltered("", "^C", "A=1,B=2", short...),
   153  
   154  		expectFiltered("A=1,C=3", "A|C", "B=2", long...),
   155  		expectFiltered("B=2,C=3", "C|B", "A=1", long...),
   156  		expectFiltered("C=3", "C", "A=1,B=2", long...),
   157  		expectFiltered("", "D", "A=1,B=2,C=3", long...),
   158  	}
   159  	enc := attribute.DefaultEncoder()
   160  
   161  	for _, tc := range cases {
   162  		cpy := make([]attribute.KeyValue, len(tc.kvs))
   163  		copy(cpy, tc.kvs)
   164  		distinct, uniq := attribute.NewSetWithFiltered(cpy, func(attr attribute.KeyValue) bool {
   165  			return tc.keyRe.MatchString(string(attr.Key))
   166  		})
   167  
   168  		full := attribute.NewSet(uniq...)
   169  
   170  		require.Equal(t, tc.encoding, distinct.Encoded(enc))
   171  		require.Equal(t, tc.fullEnc, full.Encoded(enc))
   172  	}
   173  }
   174  
   175  func TestLookup(t *testing.T) {
   176  	set := attribute.NewSet(attribute.Int("C", 3), attribute.Int("A", 1), attribute.Int("B", 2))
   177  
   178  	value, has := set.Value("C")
   179  	require.True(t, has)
   180  	require.Equal(t, int64(3), value.AsInt64())
   181  
   182  	value, has = set.Value("B")
   183  	require.True(t, has)
   184  	require.Equal(t, int64(2), value.AsInt64())
   185  
   186  	value, has = set.Value("A")
   187  	require.True(t, has)
   188  	require.Equal(t, int64(1), value.AsInt64())
   189  
   190  	_, has = set.Value("D")
   191  	require.False(t, has)
   192  }
   193  
   194  func TestZeroSetExportedMethodsNoPanic(t *testing.T) {
   195  	rType := reflect.TypeOf((*attribute.Set)(nil))
   196  	rVal := reflect.ValueOf(&attribute.Set{})
   197  	for n := 0; n < rType.NumMethod(); n++ {
   198  		mType := rType.Method(n)
   199  		if !mType.IsExported() {
   200  			t.Logf("ignoring unexported %s", mType.Name)
   201  			continue
   202  		}
   203  		t.Run(mType.Name, func(t *testing.T) {
   204  			m := rVal.MethodByName(mType.Name)
   205  			if !m.IsValid() {
   206  				t.Errorf("unknown method: %s", mType.Name)
   207  			}
   208  			assert.NotPanics(t, func() { _ = m.Call(args(mType)) })
   209  		})
   210  	}
   211  }
   212  
   213  func args(m reflect.Method) []reflect.Value {
   214  	numIn := m.Type.NumIn() - 1 // Do not include the receiver arg.
   215  	if numIn <= 0 {
   216  		return nil
   217  	}
   218  	if m.Type.IsVariadic() {
   219  		numIn--
   220  	}
   221  	out := make([]reflect.Value, numIn)
   222  	for i := range out {
   223  		aType := m.Type.In(i + 1) // Skip receiver arg.
   224  		out[i] = reflect.New(aType).Elem()
   225  	}
   226  	return out
   227  }
   228  

View as plain text