cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.77.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/parser/utils/source_test.go

499lines · modeblame

b4490cabLukasz Mierzwa1 years ago1package utils_test
2
3import (
c7bb4cbfLukasz Mierzwa1 years ago4"fmt"
ee682eb6Lukasz Mierzwa1 years ago5"os"
a693f2e1Lukasz Mierzwa1 years ago6"path/filepath"
7"runtime"
ee682eb6Lukasz Mierzwa1 years ago8"strconv"
0fff8c1eLukasz Mierzwa1 years ago9"strings"
b4490cabLukasz Mierzwa1 years ago10"testing"
11
ee682eb6Lukasz Mierzwa1 years ago12"github.com/gkampitakis/go-snaps/snaps"
b4490cabLukasz Mierzwa1 years ago13"github.com/stretchr/testify/require"
77425611Lukasz Mierzwa10 months ago14"go.yaml.in/yaml/v3"
b4490cabLukasz Mierzwa1 years ago15
16"github.com/cloudflare/pint/internal/parser"
17"github.com/cloudflare/pint/internal/parser/utils"
18
19promParser "github.com/prometheus/prometheus/promql/parser"
20)
21
ee682eb6Lukasz Mierzwa1 years ago22func TestMain(t *testing.M) {
23v := t.Run()
c7bb4cbfLukasz Mierzwa1 years ago24if _, err := snaps.Clean(t, snaps.CleanOpts{Sort: true}); err != nil {
25fmt.Printf("snaps.Clean() returned an error: %s", err)
26os.Exit(100)
27}
ee682eb6Lukasz Mierzwa1 years ago28os.Exit(v)
17fb6517Lukasz Mierzwa1 years ago29}
30
5e086569Lukasz Mierzwa9 months ago31var testCases = []string{
32"1",
33"1 / 5",
34"(2 ^ 5) == bool 5",
35"(2 ^ 5 + 11) % 5 <= bool 2",
36"(2 ^ 5 + 11) % 5 >= bool 20",
37"(2 ^ 5 + 11) % 5 <= bool 3",
38"(2 ^ 5 + 11) % 5 < bool 1",
39"20 - 15 < bool 1",
40"2 * 5",
41"(foo or bar) * 5",
42"(foo or vector(2)) * 5",
43"(foo or vector(5)) * (vector(2) or bar)",
44`1 > bool 0`,
45`20 > bool 10`,
46`"test"`,
47"foo",
48"(foo > 1) > bool 1",
49"foo > bool 5",
50"foo > bool 5 == 1",
51"foo > bool bar",
52"(foo > bool bar) == 0",
53"foo > bool on(instance) bar",
54"(foo > bool on(instance) bar) == 1",
55"foo > bool on(instance) group_left(version) bar",
56"bar > bool on(instance) group_right(version) foo",
57"foo and bar > bool 0",
58"foo offset 5m",
59`foo{job="bar"}`,
60`foo{job=""}`,
61`foo{job="bar"} or bar{job="foo"}`,
62`foo{a="bar"} or bar{b="foo"}`,
63"foo[5m]",
64"prometheus_build_info[2m:1m]",
65"deriv(rate(distance_covered_meters_total[1m])[5m:1m])",
66"foo - 1",
67"foo / 5",
68"-foo",
69`sum(foo{job="myjob"})`,
70`sum(count(foo{job="myjob"}) by(instance))`,
71`sum(foo{job="myjob"}) > 20`,
72`sum(foo{job="myjob"}) without(job)`,
73`sum(foo) by(job)`,
74`sum(foo{job="myjob"}) by(job)`,
75`abs(foo{job="myjob"} offset 5m)`,
76`abs(foo{job="myjob"} or bar{cluster="dev"})`,
77`sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
78`sum(foo{job="myjob"}) without(instance)`,
79`min(foo{job="myjob"}) / max(foo{job="myjob"})`,
80`max(foo{job="myjob"}) / min(foo{job="myjob"})`,
81`avg(foo{job="myjob"}) by(job)`,
82`group(foo) by(job)`,
83`stddev(rate(foo[5m]))`,
84`stdvar(rate(foo[5m]))`,
85`stddev_over_time(foo[5m])`,
86`stdvar_over_time(foo[5m])`,
87`quantile(0.9, rate(foo[5m]))`,
88`count_values("version", build_version)`,
89`count_values("version", build_version) without(job)`,
90`count_values("version", build_version{job="foo"}) without(job)`,
91`count_values("version", build_version) by(job)`,
92`topk(10, foo{job="myjob"}) > 10`,
93`topk(10, foo or bar)`,
94`rate(foo[10m])`,
95`sum(rate(foo[10m])) without(instance)`,
96`foo{job="foo"} / bar`,
97`foo{job="foo"} * on(instance) bar`,
98`foo{job="foo"} * on(instance) group_left(bar) bar`,
99`foo{job="foo"} * on(instance) group_left(cluster) bar{cluster="bar", ignored="true"}`,
100`foo{job="foo", ignored="true"} * on(instance) group_right(job) bar{cluster="bar"}`,
101`count(foo / bar)`,
102`count(up{job="a"} / on () up{job="b"})`,
103`count(up{job="a"} / on (env) up{job="b"})`,
104`foo{job="foo", instance="1"} and bar`,
105`foo{job="foo", instance="1"} and on(cluster) bar`,
106`topk(10, foo)`,
107`topk(10, foo) without(cluster)`,
108`topk(10, foo) by(cluster)`,
109`bottomk(10, sum(rate(foo[5m])) without(job))`,
110`foo or bar`,
111`foo or bar or baz`,
112`(foo or bar) or baz`,
113`foo unless bar`,
114`foo unless bar > 5`,
115`foo unless bar unless baz`,
116`count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
117"year()",
118"year(foo)",
119`label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")`,
120`
2bc6b9e5Lukasz Mierzwa1 years ago121(
122sum(foo:sum > 0) without(notify)
123* on(job) group_left(notify)
124job:notify
125)
126and on(job)
127sum(foo:count) by(job) > 20`,
5e086569Lukasz Mierzwa9 months ago128`container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`,
129`container_file_descriptors / on (instance, app_name) group_left() container_ulimits_soft{ulimit="max_open_files"}`,
130`absent(foo{job="bar"})`,
131`absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`,
132`absent(sum(foo) by(job, instance))`,
133`absent(foo{job="prometheus", xxx="1"}) AND on(job) prometheus_build_info`,
134`1 + sum(foo) by(notjob)`,
135`count(node_exporter_build_info) by (instance, version) != ignoring(package,version) group_left(foo) count(deb_package_version) by (instance, version, package)`,
136`absent(foo) or absent(bar)`,
137`absent_over_time(foo[5m]) or absent(bar)`,
138`bar * on() group_right(cluster, env) absent(foo{job="xxx"})`,
139`bar * on() group_right() absent(foo{job="xxx"})`,
140"vector(1)",
141"vector(scalar(foo))",
142"vector(0.0 >= bool 0.5) == 1",
143`sum_over_time(foo{job="myjob"}[5m])`,
144`days_in_month()`,
145`days_in_month(foo{job="foo"})`,
146`label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`,
147`label_replace(sum by (pod) (pod_status) > 0, "cluster", "$1", "pod", "(.*)")`,
148`(time() - my_metric) > 5*3600`,
149`up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`,
150`
1331c38cLukasz Mierzwa1 years ago151avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})
152< 0.5 > 0
153or sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})
154< on() count(colo_router_tier:disabled_pops:max{tier="1",router=~"edge.*"}) * 0.4 > 0
155or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})
156< 0.1 > 0
157`,
5e086569Lukasz Mierzwa9 months ago158`label_replace(sum(foo) without(instance), "instance", "none", "", "")`,
159`
1887ad0aLukasz Mierzwa1 years ago160sum by (region, target, colo_name) (
161sum_over_time(probe_success{job="abc"}[5m])
162or
163vector(1)
164) == 0`,
5e086569Lukasz Mierzwa9 months ago165`vector(1) or foo`,
166`vector(0) > 0`,
167`vector(0) > vector(1)`,
168`sum(foo or vector(0)) > 0`,
169`(sum(foo or vector(1)) > 0) == 2`,
170`(sum(foo or vector(1)) > 0) != 2`,
171`(sum(foo or vector(2)) > 0) != 2`,
172`(sum(sometimes{foo!="bar"} or vector(0)))
17fb6517Lukasz Mierzwa1 years ago173or
174((bob > 10) or sum(foo) or vector(1))`,
5e086569Lukasz Mierzwa9 months ago175`
17fb6517Lukasz Mierzwa1 years ago176(
177sum(sometimes{foo!="bar"})
178or
179vector(1)
180) and (
181((bob > 10) or sum(bar))
182or
183notfound > 0
184)`,
5e086569Lukasz Mierzwa9 months ago185"foo offset 5m > 5",
186`
e718edd9Lukasz Mierzwa1 years ago187(rate(metric2[5m]) or vector(0)) +
188(rate(metric1[5m]) or vector(1)) +
189(rate(metric3{log_name="samplerd"}[5m]) or vector(2)) > 0
190`,
5e086569Lukasz Mierzwa9 months ago191`label_replace(vector(1), "nexthop_tag", "$1", "nexthop", "(.+)")`,
192`(sum(foo{job="myjob"}))`,
193`(-foo{job="myjob"})`,
194"\n((( group(vector(0)) ))) > 0",
195"1 > bool 5",
196`prometheus_ready{job="prometheus"} unless vector(0)`,
197`prometheus_ready{job="prometheus"} unless on() vector(0)`,
198`prometheus_ready{job="prometheus"} unless on(job) vector(0)`,
199`
c269e3b9Lukasz Mierzwa1 years ago200max by (instance, cluster) (cf_node_role{kubernetes_role="master",role="kubernetes"})
201unless
202sum by (instance, cluster) (time() - node_systemd_timer_last_trigger_seconds{name=~"etcd-defrag-.*.timer"})
203* on (instance) group_left (cluster)
204cf_node_role{kubernetes_role="master",role="kubernetes"}
205`,
5e086569Lukasz Mierzwa9 months ago206`foo{a="1"} * on() bar{b="2"}`,
207`foo{a="1"} * on(instance) group_left(c,d) bar{b="2"}`,
208`foo{a="1"} * on(instance) group_right(c,d) bar{b="2"}`,
209`foo{a="1"} * on(instance) sum(bar{b="2"})`,
210`foo{a="1"} * on(instance) group_left(c,d) sum(bar{b="2"})`,
211`sum(foo{a="1"}) * on(instance) group_right(c,d) bar{b="2"}`,
212`foo{a="1"} * on(instance) group_left(c,d) sum(bar{b="2"}) without(instance)`,
213`sum(foo{a="1"}) without(instance) * on(instance) group_right(c,d) bar{b="2"}`,
214`
c269e3b9Lukasz Mierzwa1 years ago215max without (source_instance) (
216increase(kernel_device_io_errors_total{device!~"loop.+"}[120m]) > 3 unless on(instance, device) (
217increase(kernel_device_io_soft_errors_total{device!~"loop.+"}[125m])*2 > increase(kernel_device_io_errors_total[120m])
218)
219and on(device, instance) absent(node_disk_info)
220) * on(instance) group_left(group) label_replace(salt_highstate_runner_configured_minions, "instance", "$1", "minion", "(.+)")
221`,
5e086569Lukasz Mierzwa9 months ago222`sum(foo{a="1"}) by(job) * on() bar{b="2"}`,
223`sum(sum(foo) without(job)) by(job)`,
224`
6144bc7bLukasz Mierzwa1 years ago225prometheus:scrape_series_added:since_gc:sum
226* on(prometheus) group_left()
227label_replace(
228max(max_over_time(go_memstats_alloc_bytes{job="prometheus"}[2h])) by(instance)
229/
230max(max_over_time(prometheus_tsdb_head_series[2h])) by(instance),
231"prometheus", "$1",
232"instance", "(.+)"
233)
234`,
5e086569Lukasz Mierzwa9 months ago235`(day_of_week() == 6 and hour() < 1) or vector(1)`,
236`
45b5cf5eLukasz Mierzwa1 years ago237sum by (foo, bar) (
238rate(errors_total[5m])
239* on (instance) group_left (bob, alice)
240server_errors_total
241)`,
5e086569Lukasz Mierzwa9 months ago242`1 - (foo or vector(0)) < 0.999`,
243`
bf45639fLukasz Mierzwa1 years ago244(
245vector(1) and month() == 2
246) or vector(0)
247`,
5e086569Lukasz Mierzwa9 months ago248`count by (region) (stddev by (colo_name, region) (error_total))`,
249`
5854c4cfLukasz Mierzwa1 years ago250(
251avg(
252rate(foo_rejections[6h])
253or
254vector(0)
255) by (colo_name)
256/
257(
258avg(
259rate(foo_total[6h])
260or
261vector(1)
262) by (colo_name)
263)
264) > 5
265*
266(
267avg(
268rate(foo_rejections[6h] offset 1d)
269or
270vector(0)
271) by (colo_name)
272/
273avg(
274rate(foo_total[6h] offset 1d)
275or
276vector(1)
277) by (colo_name)
278) and on (colo_name) (colo_job:foo_total:rate2m or vector(0)) > 80
279and on (colo_name) (colo_job:foo_total:rate2m offset 1d or vector(0)) > 80
280`,
5e086569Lukasz Mierzwa9 months ago281`sum(selector) / sum(selector offset 30m) > 5`,
282`
c9dddb8eLukasz Mierzwa1 years ago283count by (dc) (
284max(0 < (token_expiration - time()) < (6*60*60)) by (instance)
285* on (instance) group_right label_replace(
286configured_minions, "instance", "$1", "minion", "(.+)")
287) > 5`,
5e086569Lukasz Mierzwa9 months ago288`topk(10, prometheus_build_info*prometheus_ready)`,
289`bottomk(10, prometheus_build_info*prometheus_ready)`,
290`histogram_fraction(0, 0.1, metric)`,
ccd9c320Lukasz Mierzwa9 months ago291`foo * foo `,
292`foo + on(__name__, job) foo `,
293`foo + on(__name__, job) group_left foo `,
294`foo + on(__name__, job) group_right foo `,
125b211eLukasz Mierzwa9 months ago295`group by (env, cluster) (
296up{env="prod", job="foo"} and on (instance) (services_enabled == 999)
297)`,
298`group by (env, cluster) (
299up{env="prod", job="foo"} * on (instance) (services_enabled == 999)
300)`,
301`foo / on(instance) sum(bar)`,
302`foo / on(instance) group_left(cluster) sum(bar)`,
303`sum(bar) / on(instance) group_right(cluster) foo`,
304`sum(bar) * on(cluster) sum(foo)`,
1dcbf12bLukasz Mierzwa8 months ago305`
306group by (colo_name, instance, tier, animal, brand, sliver, pop_name) (
307up{node_status="v", job="node_exporter"}
308and on (instance) (metal_services_enabled == 999)
309* on (colo_name) group_left(tier, animal, brand, pop_name) colo_metadata{colo_status="v"}
310* on (instance) group_left (sliver) sliver_metadata{node_status="v"}
311)`,
312`
313up{node_status="v", job="node_exporter"}
314* on (colo_name) group_left(tier) colo_metadata{colo_status="v"}
315* on (instance) group_left (sliver) sliver_metadata{node_status="v"}
316`, // all group_left() labels are joined to the left
317`
318up{node_status="v", job="node_exporter"}
319and on (colo_name) colo_metadata{colo_status="v"}
320* on (instance) group_left (sliver) sliver_metadata{node_status="v"}
321`, // all group_left() labels are NOT joined to the left
322`
323colo_metadata{colo_status="v"} * on (colo_name) group_right(tier, animal, brand, pop_name)
324sliver_metadata{node_status="v"} * on (instance) group_right (sliver)
325(metal_services_enabled == 999) * on (instance)
326up{node_status="v", job="node_exporter"}
327`, // only instance label will be present
328`
329colo_metadata{colo_status="v"} * on (colo_name) group_right(tier, animal, brand, pop_name)
330sliver_metadata{node_status="v"} * on (instance) group_right (sliver)
331(metal_services_enabled == 999) * on (instance) group_right()
332up{node_status="v", job="node_exporter"}
333`, // no labels are joined to the right
334`
335sliver_metadata{node_status="v"} * on (instance) group_right (sliver)
336(metal_services_enabled == 999) * on (colo_name) group_left(tier, animal, brand, pop_name)
337colo_metadata{colo_status="v"}
338`, // labels from both group_left and group_right are joined
339`
340colo_metadata * on (colo_name) group_right(tier, animal, brand, pop_name)
341sliver_metadata * on (instance) group_right (sliver)
342metal_services_enabled
343`, // only sliver and tier are joined to the right
344`
345colo_metadata * on (colo_name) group_right(tier, animal, brand, pop_name)
346(
347sliver_metadata * on (instance) group_right (sliver)
348metal_services_enabled
349)
350`, // all labels are joined to the right
351`
352up{node_status="v", job="node_exporter"}
353* on(instance) group_left(node_status) sliver_metadata
354`, // group_left on a label already guaranteed on the left
355`services_enabled{job=""}`,
5e086569Lukasz Mierzwa9 months ago356}
b4490cabLukasz Mierzwa1 years ago357
5e086569Lukasz Mierzwa9 months ago358func TestLabelsSource(t *testing.T) {
ee682eb6Lukasz Mierzwa1 years ago359type Snapshot struct {
360Expr string
361Output []utils.Source
362}
363
a693f2e1Lukasz Mierzwa1 years ago364_, file, _, ok := runtime.Caller(0)
365require.True(t, ok, "can't get caller function")
366file = strings.TrimSuffix(filepath.Base(file), ".go")
367
ee682eb6Lukasz Mierzwa1 years ago368done := map[string]struct{}{}
369for i, expr := range testCases {
370t.Run(strconv.Itoa(i+1), func(t *testing.T) {
371if _, ok := done[expr]; ok {
372t.Fatalf("Duplicated query: %s", expr)
373}
374done[expr] = struct{}{}
375
376n, err := parser.DecodeExpr(expr)
b4490cabLukasz Mierzwa1 years ago377if err != nil {
378t.Error(err)
379t.FailNow()
380}
ee682eb6Lukasz Mierzwa1 years ago381output := utils.LabelsSource(expr, n.Expr)
800fda88Lukasz Mierzwa1 years ago382
383for _, src := range output {
3f137db9Lukasz Mierzwa1 years ago384src.WalkSources(func(s utils.Source, _ *utils.Join, _ *utils.Unless) {
800fda88Lukasz Mierzwa1 years ago385require.Positive(t, s.Position.End, "empty position %+v", s)
6af661ebLukasz Mierzwa1 years ago386if s.DeadInfo != nil {
387require.Positive(t, s.DeadInfo.Fragment.End, "empty dead position %+v", s)
800fda88Lukasz Mierzwa1 years ago388}
389})
390}
ee682eb6Lukasz Mierzwa1 years ago391
392snap := Snapshot{
393Expr: expr,
394Output: output,
395}
396d, err := yaml.Marshal(snap)
397require.NoError(t, err, "failed to YAML encode snapshots")
a693f2e1Lukasz Mierzwa1 years ago398snaps.WithConfig(snaps.Dir("."), snaps.Filename(file)).MatchSnapshot(t, string(d))
b4490cabLukasz Mierzwa1 years ago399})
400}
401}
0fff8c1eLukasz Mierzwa1 years ago402
403func TestLabelsSourceCallCoverage(t *testing.T) {
404for name, def := range promParser.Functions {
405t.Run(name, func(t *testing.T) {
406if def.Experimental {
407t.SkipNow()
408}
409
410var b strings.Builder
411b.WriteString(name)
412b.WriteRune('(')
413for i, at := range def.ArgTypes {
414if i > 0 {
415b.WriteString(", ")
416}
417switch at {
418case promParser.ValueTypeNone:
419case promParser.ValueTypeScalar:
420b.WriteRune('1')
421case promParser.ValueTypeVector:
422b.WriteString("http_requests_total")
423case promParser.ValueTypeMatrix:
424b.WriteString("http_requests_total[2m]")
425case promParser.ValueTypeString:
426b.WriteString(`"foo"`)
427}
428}
429b.WriteRune(')')
430
431n, err := parser.DecodeExpr(b.String())
432if err != nil {
433t.Error(err)
434t.FailNow()
435}
120dc119Lukasz Mierzwa1 years ago436output := utils.LabelsSource(b.String(), n.Expr)
4b70d4afLukasz Mierzwa1 years ago437require.Len(t, output, 1)
87e76148Lukasz Mierzwa1 years ago438require.NotEmpty(t, output[0].Operations)
439call, ok := utils.MostOuterOperation[*promParser.Call](output[0])
440require.True(t, ok, "no call found in operations for: %q ~> %+v", b.String(), output)
441require.NotNil(t, call, "no call detected in: %q ~> %+v", b.String(), output)
a708e693Lukasz Mierzwa1 years ago442require.Equal(t, name, output[0].Operation())
4b70d4afLukasz Mierzwa1 years ago443require.Equal(t, def.ReturnType, output[0].Returns, "incorrect return type on Source{}")
0fff8c1eLukasz Mierzwa1 years ago444})
445}
446}
447
448func TestLabelsSourceCallCoverageFail(t *testing.T) {
449n := &parser.PromQLNode{
450Expr: &promParser.Call{
451Func: &promParser.Function{
452Name: "fake_call",
453},
454},
455}
120dc119Lukasz Mierzwa1 years ago456output := utils.LabelsSource("fake_call()", n.Expr)
4b70d4afLukasz Mierzwa1 years ago457require.Len(t, output, 1)
87e76148Lukasz Mierzwa1 years ago458call, ok := utils.MostOuterOperation[*promParser.Call](output[0])
459require.False(t, ok, "no call should have been detected in fake function, got: %v", ok)
460require.Nil(t, call, "no call should have been detected in fake function, got: %+v", call)
0fff8c1eLukasz Mierzwa1 years ago461}
a708e693Lukasz Mierzwa1 years ago462
463func TestVectorOperation(t *testing.T) {
464n := &parser.PromQLNode{
465Expr: &promParser.NumberLiteral{
466Val: 1,
467},
468}
469output := utils.LabelsSource("1", n.Expr)
470require.Len(t, output, 1)
471require.Empty(t, output[0].Operation())
472}
5e086569Lukasz Mierzwa9 months ago473
1dcbf12bLukasz Mierzwa8 months ago474func TestDeadLabelKindUnknownString(t *testing.T) {
475var dl utils.DeadLabelKind = 100
476require.Equal(t, "unknown", dl.String())
477}
478
5e086569Lukasz Mierzwa9 months ago479func BenchmarkLabelsSource(b *testing.B) {
480type testCase struct {
481node promParser.Node
482expr string
483}
484queries := make([]testCase, 0, len(testCases))
485for _, expr := range testCases {
486n, err := parser.DecodeExpr(expr)
487require.NoError(b, err)
488queries = append(queries, testCase{
489expr: expr,
490node: n.Expr,
491})
492}
493
494for b.Loop() {
495for _, tc := range queries {
496utils.LabelsSource(tc.expr, tc.node)
497}
498}
499}