master
go 125 lines 2.84 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package selector
4
5 import (
6 "maps"
7 "sort"
8 "testing"
9
10 "github.com/netdata/netdata/go/plugins/pkg/metrix"
11 "github.com/stretchr/testify/assert"
12 "github.com/stretchr/testify/require"
13 )
14
15 type mapLabelView map[string]string
16
17 func (m mapLabelView) Len() int { return len(m) }
18
19 func (m mapLabelView) Get(key string) (string, bool) {
20 v, ok := m[key]
21 return v, ok
22 }
23
24 func (m mapLabelView) Range(fn func(key, value string) bool) {
25 keys := make([]string, 0, len(m))
26 for key := range m {
27 keys = append(keys, key)
28 }
29 sort.Strings(keys)
30 for _, key := range keys {
31 if !fn(key, m[key]) {
32 return
33 }
34 }
35 }
36
37 func (m mapLabelView) CloneMap() map[string]string {
38 out := make(map[string]string, len(m))
39 maps.Copy(out, m)
40 return out
41 }
42
43 var _ metrix.LabelView = mapLabelView{}
44
45 func TestParseScenarios(t *testing.T) {
46 tests := map[string]struct {
47 expr string
48 metric string
49 labels mapLabelView
50 wantMatch bool
51 wantErr bool
52 }{
53 "metric only": {
54 expr: "http_requests_total",
55 metric: "http_requests_total",
56 wantMatch: true,
57 },
58 "metric plus label": {
59 expr: `http_requests_total{job="api"}`,
60 metric: "http_requests_total",
61 labels: mapLabelView{"job": "api"},
62 wantMatch: true,
63 },
64 "invalid": {
65 expr: `metric{job="api",}`,
66 wantErr: true,
67 },
68 }
69
70 for name, tc := range tests {
71 t.Run(name, func(t *testing.T) {
72 sel, err := Parse(tc.expr)
73 if tc.wantErr {
74 require.Error(t, err)
75 return
76 }
77 require.NoError(t, err)
78 require.NotNil(t, sel)
79 assert.Equal(t, tc.wantMatch, sel.Matches(tc.metric, tc.labels))
80 })
81 }
82 }
83
84 func TestParseEmptyExpressionReturnsNil(t *testing.T) {
85 tests := map[string]struct {
86 expr string
87 }{
88 "empty": {expr: ""},
89 "whitespace": {expr: " \t\n"},
90 }
91
92 for name, tc := range tests {
93 t.Run(name, func(t *testing.T) {
94 sel, err := Parse(tc.expr)
95 require.NoError(t, err)
96 assert.Nil(t, sel)
97 })
98 }
99 }
100
101 func TestExprScenarios(t *testing.T) {
102 expr := Expr{
103 Allow: []string{"go_*"},
104 Deny: []string{"go_gc_*"},
105 }
106 sel, err := expr.Parse()
107 require.NoError(t, err)
108 require.NotNil(t, sel)
109
110 assert.True(t, sel.Matches("go_memstats_alloc_bytes", nil))
111 assert.False(t, sel.Matches("go_gc_duration_seconds", nil))
112 assert.False(t, sel.Matches("node_cpu_seconds_total", nil))
113 }
114
115 func TestParseCompiledScenarios(t *testing.T) {
116 compiled, err := ParseCompiled(`http_requests_total{job="api",instance="a"}`)
117 require.NoError(t, err)
118 require.NotNil(t, compiled)
119
120 meta := compiled.Meta()
121 assert.Equal(t, []string{"http_requests_total"}, meta.MetricNames)
122 assert.Equal(t, []string{"instance", "job"}, meta.ConstrainedLabelKeys)
123 assert.True(t, compiled.Matches("http_requests_total", mapLabelView{"job": "api", "instance": "a"}))
124 assert.False(t, compiled.Matches("http_requests_total", mapLabelView{"job": "api", "instance": "b"}))
125 }