1
2
3
4
5
6
7
8
9
10
11
12
13
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
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
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
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
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)
224 out[i] = reflect.New(aType).Elem()
225 }
226 return out
227 }
228
View as plain text