| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- // Copyright The OpenTelemetry Authors
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package attribute_test
- import (
- "reflect"
- "regexp"
- "testing"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- "go.opentelemetry.io/otel/attribute"
- )
- type testCase struct {
- kvs []attribute.KeyValue
- keyRe *regexp.Regexp
- encoding string
- fullEnc string
- }
- func expect(enc string, kvs ...attribute.KeyValue) testCase {
- return testCase{
- kvs: kvs,
- encoding: enc,
- }
- }
- func expectFiltered(enc, filter, fullEnc string, kvs ...attribute.KeyValue) testCase {
- return testCase{
- kvs: kvs,
- keyRe: regexp.MustCompile(filter),
- encoding: enc,
- fullEnc: fullEnc,
- }
- }
- func TestSetDedup(t *testing.T) {
- cases := []testCase{
- expect("A=B", attribute.String("A", "2"), attribute.String("A", "B")),
- expect("A=B", attribute.String("A", "2"), attribute.Int("A", 1), attribute.String("A", "B")),
- expect("A=B", attribute.String("A", "B"), attribute.String("A", "C"), attribute.String("A", "D"), attribute.String("A", "B")),
- expect("A=B,C=D", attribute.String("A", "1"), attribute.String("C", "D"), attribute.String("A", "B")),
- expect("A=B,C=D", attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
- expect("A=B,C=D", attribute.Float64("C", 1.2), attribute.String("A", "2"), attribute.String("A", "B"), attribute.String("C", "D")),
- 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")),
- 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")),
- 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")),
- }
- enc := attribute.DefaultEncoder()
- s2d := map[string][]attribute.Distinct{}
- d2s := map[attribute.Distinct][]string{}
- for _, tc := range cases {
- cpy := make([]attribute.KeyValue, len(tc.kvs))
- copy(cpy, tc.kvs)
- sl := attribute.NewSet(cpy...)
- // Ensure that the input was reordered but no elements went missing.
- require.ElementsMatch(t, tc.kvs, cpy)
- str := sl.Encoded(enc)
- equ := sl.Equivalent()
- s2d[str] = append(s2d[str], equ)
- d2s[equ] = append(d2s[equ], str)
- require.Equal(t, tc.encoding, str)
- }
- for s, d := range s2d {
- // No other Distinct values are equal to this.
- for s2, d2 := range s2d {
- if s2 == s {
- continue
- }
- for _, elt := range d {
- for _, otherDistinct := range d2 {
- require.NotEqual(t, otherDistinct, elt)
- }
- }
- }
- for _, strings := range d2s {
- if strings[0] == s {
- continue
- }
- for _, otherString := range strings {
- require.NotEqual(t, otherString, s)
- }
- }
- }
- for d, s := range d2s {
- // No other Distinct values are equal to this.
- for d2, s2 := range d2s {
- if d2 == d {
- continue
- }
- for _, elt := range s {
- for _, otherDistinct := range s2 {
- require.NotEqual(t, otherDistinct, elt)
- }
- }
- }
- for _, distincts := range s2d {
- if distincts[0] == d {
- continue
- }
- for _, otherDistinct := range distincts {
- require.NotEqual(t, otherDistinct, d)
- }
- }
- }
- }
- func TestUniqueness(t *testing.T) {
- short := []attribute.KeyValue{
- attribute.String("A", "0"),
- attribute.String("B", "2"),
- attribute.String("A", "1"),
- }
- long := []attribute.KeyValue{
- attribute.String("B", "2"),
- attribute.String("C", "5"),
- attribute.String("B", "2"),
- attribute.String("C", "1"),
- attribute.String("A", "4"),
- attribute.String("C", "3"),
- attribute.String("A", "1"),
- }
- cases := []testCase{
- expectFiltered("A=1", "^A$", "B=2", short...),
- expectFiltered("B=2", "^B$", "A=1", short...),
- expectFiltered("A=1,B=2", "^A|B$", "", short...),
- expectFiltered("", "^C", "A=1,B=2", short...),
- expectFiltered("A=1,C=3", "A|C", "B=2", long...),
- expectFiltered("B=2,C=3", "C|B", "A=1", long...),
- expectFiltered("C=3", "C", "A=1,B=2", long...),
- expectFiltered("", "D", "A=1,B=2,C=3", long...),
- }
- enc := attribute.DefaultEncoder()
- for _, tc := range cases {
- cpy := make([]attribute.KeyValue, len(tc.kvs))
- copy(cpy, tc.kvs)
- distinct, uniq := attribute.NewSetWithFiltered(cpy, func(attr attribute.KeyValue) bool {
- return tc.keyRe.MatchString(string(attr.Key))
- })
- full := attribute.NewSet(uniq...)
- require.Equal(t, tc.encoding, distinct.Encoded(enc))
- require.Equal(t, tc.fullEnc, full.Encoded(enc))
- }
- }
- func TestLookup(t *testing.T) {
- set := attribute.NewSet(attribute.Int("C", 3), attribute.Int("A", 1), attribute.Int("B", 2))
- value, has := set.Value("C")
- require.True(t, has)
- require.Equal(t, int64(3), value.AsInt64())
- value, has = set.Value("B")
- require.True(t, has)
- require.Equal(t, int64(2), value.AsInt64())
- value, has = set.Value("A")
- require.True(t, has)
- require.Equal(t, int64(1), value.AsInt64())
- _, has = set.Value("D")
- require.False(t, has)
- }
- func TestZeroSetExportedMethodsNoPanic(t *testing.T) {
- rType := reflect.TypeOf((*attribute.Set)(nil))
- rVal := reflect.ValueOf(&attribute.Set{})
- for n := 0; n < rType.NumMethod(); n++ {
- mType := rType.Method(n)
- if !mType.IsExported() {
- t.Logf("ignoring unexported %s", mType.Name)
- continue
- }
- t.Run(mType.Name, func(t *testing.T) {
- m := rVal.MethodByName(mType.Name)
- if !m.IsValid() {
- t.Errorf("unknown method: %s", mType.Name)
- }
- assert.NotPanics(t, func() { _ = m.Call(args(mType)) })
- })
- }
- }
- func args(m reflect.Method) []reflect.Value {
- numIn := m.Type.NumIn() - 1 // Do not include the receiver arg.
- if numIn <= 0 {
- return nil
- }
- if m.Type.IsVariadic() {
- numIn--
- }
- out := make([]reflect.Value, numIn)
- for i := range out {
- aType := m.Type.In(i + 1) // Skip receiver arg.
- out[i] = reflect.New(aType).Elem()
- }
- return out
- }
|