ebpf_exporter
347 строк · 5.6 Кб
1package decoder
2
3import (
4"fmt"
5"sync"
6"testing"
7
8"github.com/cloudflare/ebpf_exporter/v2/config"
9)
10
11func TestDecodeLabels(t *testing.T) {
12cases := []struct {
13in []byte
14labels []config.Label
15out []string
16err bool
17}{
18{
19in: append([]byte{0x8, 0x0, 0x0, 0x0}, zeroPaddedString("potatoes", 16)...),
20labels: []config.Label{
21{
22Name: "number",
23Size: 4,
24Decoders: []config.Decoder{
25{
26Name: "uint",
27},
28},
29},
30},
31out: []string{"8"},
32err: true, // not all labels are decoded
33},
34{
35in: append([]byte{0x8, 0x0, 0x0, 0x0}, zeroPaddedString("bananas", 32)...),
36labels: []config.Label{
37{
38Name: "number",
39Size: 4,
40Decoders: []config.Decoder{
41{
42Name: "uint",
43},
44},
45},
46{
47Name: "fruit",
48Size: 32,
49Decoders: []config.Decoder{
50{
51Name: "string",
52},
53},
54},
55},
56out: []string{"8", "bananas"},
57err: false,
58},
59{
60in: append([]byte{0x8, 0x0, 0x0, 0x0}, zeroPaddedString("bananas", 32)...),
61labels: []config.Label{
62{
63Name: "number",
64Size: 4,
65Decoders: []config.Decoder{
66{
67Name: "uint",
68},
69},
70},
71{
72Name: "fruit",
73Size: 32,
74Decoders: []config.Decoder{
75{
76Name: "string",
77},
78{
79Name: "regexp",
80Regexps: []string{
81"^bananas$",
82"$is-banana-even-fruit$",
83},
84},
85},
86},
87},
88out: []string{"8", "bananas"},
89err: false,
90},
91{
92in: append([]byte{0x8, 0x0, 0x0, 0x0}, zeroPaddedString("bananas", 32)...),
93labels: []config.Label{
94{
95Name: "number",
96Size: 4,
97Decoders: []config.Decoder{
98{
99Name: "uint",
100},
101},
102},
103{
104Name: "fruit",
105Size: 32,
106Decoders: []config.Decoder{
107{
108Name: "string",
109},
110{
111Name: "regexp",
112Regexps: []string{
113"^tomato$",
114},
115},
116},
117},
118},
119out: []string{"8", "bananas"},
120err: true, // this label should be skipped, only tomatoes allowed
121},
122}
123
124for i, c := range cases {
125s, err := NewSet()
126if err != nil {
127t.Fatal(err)
128}
129
130out, err := s.DecodeLabels(c.in, fmt.Sprintf("test:%d", i), c.labels)
131if c.err {
132if err == nil {
133t.Errorf("Expected error for input %#v and labels %#v, but did not receive it", c.in, c.labels)
134}
135
136continue
137}
138
139if err != nil {
140t.Errorf("Error decoding %#v with labels set to %#v: %s", c.in, c.labels, err)
141}
142
143if len(c.out) != len(out) {
144t.Errorf("Expected %d outputs (%v), received %d (%v)", len(c.out), c.out, len(out), out)
145}
146
147for i := 0; i < len(c.out) && i < len(out); i++ {
148if c.out[i] != out[i] {
149t.Errorf("Output label %d for input %#v is wrong: expected %s, but received %s", i, c.in, c.out[i], out[i])
150}
151}
152}
153}
154
155func TestDecoderSetConcurrency(t *testing.T) {
156in := append([]byte{0x8, 0x0, 0x0, 0x0}, zeroPaddedString("bananas", 32)...)
157
158labels := []config.Label{
159{
160Name: "number",
161Size: 4,
162Decoders: []config.Decoder{
163{
164Name: "uint",
165},
166},
167},
168{
169Name: "fruit",
170Size: 32,
171Decoders: []config.Decoder{
172{
173Name: "string",
174},
175{
176Name: "regexp",
177Regexps: []string{
178"^bananas$",
179"$is-banana-even-fruit$",
180},
181},
182},
183},
184}
185
186s, err := NewSet()
187if err != nil {
188t.Fatal(err)
189}
190
191count := 1000
192
193wg := sync.WaitGroup{}
194wg.Add(count)
195
196for i := 0; i < count; i++ {
197go func() {
198defer wg.Done()
199
200_, err := s.DecodeLabels(in, "concurrency", labels)
201if err != nil {
202t.Error(err)
203}
204}()
205}
206
207wg.Wait()
208}
209
210func TestDecoderSetCache(t *testing.T) {
211in := []byte{0xba, 0xbe, 0xba, 0xbe, 0xde, 0xad, 0xbe, 0xef}
212
213one := []config.Label{
214{
215Name: "single_u64",
216Size: 8,
217Decoders: []config.Decoder{
218{
219Name: "uint",
220},
221},
222},
223}
224
225two := []config.Label{
226{
227Name: "u32_one",
228Size: 4,
229Decoders: []config.Decoder{
230{
231Name: "uint",
232},
233},
234},
235{
236Name: "u32_two",
237Size: 4,
238Decoders: []config.Decoder{
239{
240Name: "uint",
241},
242},
243},
244}
245
246s, err := NewSet()
247if err != nil {
248t.Fatal(err)
249}
250
251single, err := s.DecodeLabels(in, "one", one)
252if err != nil {
253t.Fatal(err)
254}
255
256if len(single) != 1 {
257t.Errorf("Expected one u64 from %#v, got %#v", one, single)
258}
259
260double, err := s.DecodeLabels(in, "two", two)
261if err != nil {
262t.Error(err)
263}
264
265if len(double) != 2 {
266t.Errorf("Expected two u32 from %#v, got %#v", two, double)
267}
268}
269
270func BenchmarkCache(b *testing.B) {
271in := []byte{
2720x8, 0xab, 0xce, 0xef,
2730xde, 0xad,
2740xbe, 0xef,
2750x8, 0xab, 0xce, 0xef, 0x8, 0xab, 0xce, 0xef,
276}
277
278labels := []config.Label{
279{
280Name: "number1",
281Size: 4,
282Decoders: []config.Decoder{
283{
284Name: "uint",
285},
286},
287},
288{
289Name: "number2",
290Size: 2,
291Decoders: []config.Decoder{
292{
293Name: "uint",
294},
295},
296},
297{
298Name: "number3",
299Size: 2,
300Decoders: []config.Decoder{
301{
302Name: "uint",
303},
304},
305},
306{
307Name: "number4",
308Size: 8,
309Decoders: []config.Decoder{
310{
311Name: "uint",
312},
313},
314},
315}
316
317s, err := NewSet()
318if err != nil {
319b.Fatal(err)
320}
321
322b.Run("direct", func(b *testing.B) {
323for i := 0; i < b.N; i++ {
324_, err := s.decodeLabels(in, labels)
325if err != nil {
326b.Fatal(err)
327}
328}
329})
330
331b.Run("cached", func(b *testing.B) {
332for i := 0; i < b.N; i++ {
333_, err := s.DecodeLabels(in, "test", labels)
334if err != nil {
335b.Fatal(err)
336}
337}
338})
339}
340
341func zeroPaddedString(in string, size int) []byte {
342if len(in) > size {
343panic(fmt.Sprintf("string %q is longer than requested size %d", in, size))
344}
345
346return append([]byte(in), make([]byte, size-len(in))...)
347}
348