cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.84.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/source/source_test.go

846lines · modeblame

66868a3eLukasz Mierzwa9 months ago1package source_test
b4490cabLukasz Mierzwa1 years ago2
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 Mierzwa11 months ago14"go.yaml.in/yaml/v3"
b4490cabLukasz Mierzwa1 years ago15
16"github.com/cloudflare/pint/internal/parser"
66868a3eLukasz Mierzwa9 months ago17"github.com/cloudflare/pint/internal/parser/source"
b4490cabLukasz Mierzwa1 years ago18
19promParser "github.com/prometheus/prometheus/promql/parser"
2d7871b1Lukasz Mierzwa8 months ago20"github.com/prometheus/prometheus/promql/parser/posrange"
b4490cabLukasz Mierzwa1 years ago21)
22
ee682eb6Lukasz Mierzwa1 years ago23func TestMain(t *testing.M) {
24v := t.Run()
c7bb4cbfLukasz Mierzwa1 years ago25if _, err := snaps.Clean(t, snaps.CleanOpts{Sort: true}); err != nil {
26fmt.Printf("snaps.Clean() returned an error: %s", err)
27os.Exit(100)
28}
ee682eb6Lukasz Mierzwa1 years ago29os.Exit(v)
17fb6517Lukasz Mierzwa1 years ago30}
31
5e086569Lukasz Mierzwa10 months ago32var testCases = []string{
33"1",
34"1 / 5",
35"(2 ^ 5) == bool 5",
36"(2 ^ 5 + 11) % 5 <= bool 2",
37"(2 ^ 5 + 11) % 5 >= bool 20",
38"(2 ^ 5 + 11) % 5 <= bool 3",
39"(2 ^ 5 + 11) % 5 < bool 1",
40"20 - 15 < bool 1",
41"2 * 5",
42"(foo or bar) * 5",
43"(foo or vector(2)) * 5",
44"(foo or vector(5)) * (vector(2) or bar)",
45`1 > bool 0`,
46`20 > bool 10`,
47`"test"`,
48"foo",
49"(foo > 1) > bool 1",
50"foo > bool 5",
51"foo > bool 5 == 1",
52"foo > bool bar",
53"(foo > bool bar) == 0",
54"foo > bool on(instance) bar",
55"(foo > bool on(instance) bar) == 1",
56"foo > bool on(instance) group_left(version) bar",
57"bar > bool on(instance) group_right(version) foo",
58"foo and bar > bool 0",
59"foo offset 5m",
60`foo{job="bar"}`,
61`foo{job=""}`,
62`foo{job="bar"} or bar{job="foo"}`,
63`foo{a="bar"} or bar{b="foo"}`,
64"foo[5m]",
65"prometheus_build_info[2m:1m]",
66"deriv(rate(distance_covered_meters_total[1m])[5m:1m])",
67"foo - 1",
68"foo / 5",
69"-foo",
70`sum(foo{job="myjob"})`,
71`sum(count(foo{job="myjob"}) by(instance))`,
72`sum(foo{job="myjob"}) > 20`,
73`sum(foo{job="myjob"}) without(job)`,
74`sum(foo) by(job)`,
75`sum(foo{job="myjob"}) by(job)`,
76`abs(foo{job="myjob"} offset 5m)`,
77`abs(foo{job="myjob"} or bar{cluster="dev"})`,
78`sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
79`sum(foo{job="myjob"}) without(instance)`,
80`min(foo{job="myjob"}) / max(foo{job="myjob"})`,
81`max(foo{job="myjob"}) / min(foo{job="myjob"})`,
82`avg(foo{job="myjob"}) by(job)`,
83`group(foo) by(job)`,
84`stddev(rate(foo[5m]))`,
85`stdvar(rate(foo[5m]))`,
86`stddev_over_time(foo[5m])`,
87`stdvar_over_time(foo[5m])`,
88`quantile(0.9, rate(foo[5m]))`,
89`count_values("version", build_version)`,
90`count_values("version", build_version) without(job)`,
91`count_values("version", build_version{job="foo"}) without(job)`,
92`count_values("version", build_version) by(job)`,
93`topk(10, foo{job="myjob"}) > 10`,
94`topk(10, foo or bar)`,
95`rate(foo[10m])`,
96`sum(rate(foo[10m])) without(instance)`,
97`foo{job="foo"} / bar`,
98`foo{job="foo"} * on(instance) bar`,
99`foo{job="foo"} * on(instance) group_left(bar) bar`,
100`foo{job="foo"} * on(instance) group_left(cluster) bar{cluster="bar", ignored="true"}`,
101`foo{job="foo", ignored="true"} * on(instance) group_right(job) bar{cluster="bar"}`,
102`count(foo / bar)`,
103`count(up{job="a"} / on () up{job="b"})`,
104`count(up{job="a"} / on (env) up{job="b"})`,
105`foo{job="foo", instance="1"} and bar`,
106`foo{job="foo", instance="1"} and on(cluster) bar`,
107`topk(10, foo)`,
108`topk(10, foo) without(cluster)`,
109`topk(10, foo) by(cluster)`,
110`bottomk(10, sum(rate(foo[5m])) without(job))`,
111`foo or bar`,
112`foo or bar or baz`,
113`(foo or bar) or baz`,
114`foo unless bar`,
115`foo unless bar > 5`,
116`foo unless bar unless baz`,
117`count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
118"year()",
119"year(foo)",
120`label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")`,
121`
2bc6b9e5Lukasz Mierzwa1 years ago122(
123sum(foo:sum > 0) without(notify)
124* on(job) group_left(notify)
125job:notify
126)
127and on(job)
128sum(foo:count) by(job) > 20`,
5e086569Lukasz Mierzwa10 months ago129`container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`,
130`container_file_descriptors / on (instance, app_name) group_left() container_ulimits_soft{ulimit="max_open_files"}`,
131`absent(foo{job="bar"})`,
132`absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`,
133`absent(sum(foo) by(job, instance))`,
134`absent(foo{job="prometheus", xxx="1"}) AND on(job) prometheus_build_info`,
135`1 + sum(foo) by(notjob)`,
136`count(node_exporter_build_info) by (instance, version) != ignoring(package,version) group_left(foo) count(deb_package_version) by (instance, version, package)`,
137`absent(foo) or absent(bar)`,
2d7871b1Lukasz Mierzwa8 months ago138`absent(vector(1))`,
5e086569Lukasz Mierzwa10 months ago139`absent_over_time(foo[5m]) or absent(bar)`,
140`bar * on() group_right(cluster, env) absent(foo{job="xxx"})`,
141`bar * on() group_right() absent(foo{job="xxx"})`,
142"vector(1)",
143"vector(scalar(foo))",
144"vector(0.0 >= bool 0.5) == 1",
145`sum_over_time(foo{job="myjob"}[5m])`,
146`days_in_month()`,
147`days_in_month(foo{job="foo"})`,
148`label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`,
149`label_replace(sum by (pod) (pod_status) > 0, "cluster", "$1", "pod", "(.*)")`,
150`(time() - my_metric) > 5*3600`,
151`up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`,
152`
1331c38cLukasz Mierzwa1 years ago153avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})
154< 0.5 > 0
155or sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})
156< on() count(colo_router_tier:disabled_pops:max{tier="1",router=~"edge.*"}) * 0.4 > 0
157or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})
158< 0.1 > 0
159`,
5e086569Lukasz Mierzwa10 months ago160`label_replace(sum(foo) without(instance), "instance", "none", "", "")`,
161`
1887ad0aLukasz Mierzwa1 years ago162sum by (region, target, colo_name) (
163sum_over_time(probe_success{job="abc"}[5m])
164or
165vector(1)
166) == 0`,
5e086569Lukasz Mierzwa10 months ago167`vector(1) or foo`,
168`vector(0) > 0`,
169`vector(0) > vector(1)`,
170`sum(foo or vector(0)) > 0`,
171`(sum(foo or vector(1)) > 0) == 2`,
172`(sum(foo or vector(1)) > 0) != 2`,
173`(sum(foo or vector(2)) > 0) != 2`,
174`(sum(sometimes{foo!="bar"} or vector(0)))
17fb6517Lukasz Mierzwa1 years ago175or
176((bob > 10) or sum(foo) or vector(1))`,
5e086569Lukasz Mierzwa10 months ago177`
17fb6517Lukasz Mierzwa1 years ago178(
179sum(sometimes{foo!="bar"})
180or
181vector(1)
182) and (
183((bob > 10) or sum(bar))
184or
185notfound > 0
186)`,
5e086569Lukasz Mierzwa10 months ago187"foo offset 5m > 5",
188`
e718edd9Lukasz Mierzwa1 years ago189(rate(metric2[5m]) or vector(0)) +
190(rate(metric1[5m]) or vector(1)) +
191(rate(metric3{log_name="samplerd"}[5m]) or vector(2)) > 0
192`,
5e086569Lukasz Mierzwa10 months ago193`label_replace(vector(1), "nexthop_tag", "$1", "nexthop", "(.+)")`,
194`(sum(foo{job="myjob"}))`,
195`(-foo{job="myjob"})`,
196"\n((( group(vector(0)) ))) > 0",
197"1 > bool 5",
198`prometheus_ready{job="prometheus"} unless vector(0)`,
199`prometheus_ready{job="prometheus"} unless on() vector(0)`,
200`prometheus_ready{job="prometheus"} unless on(job) vector(0)`,
201`
c269e3b9Lukasz Mierzwa1 years ago202max by (instance, cluster) (cf_node_role{kubernetes_role="master",role="kubernetes"})
203unless
204sum by (instance, cluster) (time() - node_systemd_timer_last_trigger_seconds{name=~"etcd-defrag-.*.timer"})
205* on (instance) group_left (cluster)
206cf_node_role{kubernetes_role="master",role="kubernetes"}
207`,
5e086569Lukasz Mierzwa10 months ago208`foo{a="1"} * on() bar{b="2"}`,
209`foo{a="1"} * on(instance) group_left(c,d) bar{b="2"}`,
210`foo{a="1"} * on(instance) group_right(c,d) bar{b="2"}`,
211`foo{a="1"} * on(instance) sum(bar{b="2"})`,
212`foo{a="1"} * on(instance) group_left(c,d) sum(bar{b="2"})`,
213`sum(foo{a="1"}) * on(instance) group_right(c,d) bar{b="2"}`,
214`foo{a="1"} * on(instance) group_left(c,d) sum(bar{b="2"}) without(instance)`,
215`sum(foo{a="1"}) without(instance) * on(instance) group_right(c,d) bar{b="2"}`,
216`
c269e3b9Lukasz Mierzwa1 years ago217max without (source_instance) (
218increase(kernel_device_io_errors_total{device!~"loop.+"}[120m]) > 3 unless on(instance, device) (
219increase(kernel_device_io_soft_errors_total{device!~"loop.+"}[125m])*2 > increase(kernel_device_io_errors_total[120m])
220)
221and on(device, instance) absent(node_disk_info)
222) * on(instance) group_left(group) label_replace(salt_highstate_runner_configured_minions, "instance", "$1", "minion", "(.+)")
223`,
5e086569Lukasz Mierzwa10 months ago224`sum(foo{a="1"}) by(job) * on() bar{b="2"}`,
225`sum(sum(foo) without(job)) by(job)`,
226`
6144bc7bLukasz Mierzwa1 years ago227prometheus:scrape_series_added:since_gc:sum
228* on(prometheus) group_left()
229label_replace(
230max(max_over_time(go_memstats_alloc_bytes{job="prometheus"}[2h])) by(instance)
231/
232max(max_over_time(prometheus_tsdb_head_series[2h])) by(instance),
233"prometheus", "$1",
234"instance", "(.+)"
235)
236`,
5e086569Lukasz Mierzwa10 months ago237`(day_of_week() == 6 and hour() < 1) or vector(1)`,
238`
45b5cf5eLukasz Mierzwa1 years ago239sum by (foo, bar) (
240rate(errors_total[5m])
241* on (instance) group_left (bob, alice)
242server_errors_total
243)`,
5e086569Lukasz Mierzwa10 months ago244`1 - (foo or vector(0)) < 0.999`,
245`
bf45639fLukasz Mierzwa1 years ago246(
247vector(1) and month() == 2
248) or vector(0)
249`,
5e086569Lukasz Mierzwa10 months ago250`count by (region) (stddev by (colo_name, region) (error_total))`,
251`
5854c4cfLukasz Mierzwa1 years ago252(
253avg(
254rate(foo_rejections[6h])
255or
256vector(0)
257) by (colo_name)
258/
259(
260avg(
261rate(foo_total[6h])
262or
263vector(1)
264) by (colo_name)
265)
266) > 5
267*
268(
269avg(
270rate(foo_rejections[6h] offset 1d)
271or
272vector(0)
273) by (colo_name)
274/
275avg(
276rate(foo_total[6h] offset 1d)
277or
278vector(1)
279) by (colo_name)
280) and on (colo_name) (colo_job:foo_total:rate2m or vector(0)) > 80
281and on (colo_name) (colo_job:foo_total:rate2m offset 1d or vector(0)) > 80
282`,
5e086569Lukasz Mierzwa10 months ago283`sum(selector) / sum(selector offset 30m) > 5`,
284`
c9dddb8eLukasz Mierzwa1 years ago285count by (dc) (
286max(0 < (token_expiration - time()) < (6*60*60)) by (instance)
287* on (instance) group_right label_replace(
288configured_minions, "instance", "$1", "minion", "(.+)")
289) > 5`,
5e086569Lukasz Mierzwa10 months ago290`topk(10, prometheus_build_info*prometheus_ready)`,
291`bottomk(10, prometheus_build_info*prometheus_ready)`,
292`histogram_fraction(0, 0.1, metric)`,
ccd9c320Lukasz Mierzwa9 months ago293`foo * foo `,
294`foo + on(__name__, job) foo `,
295`foo + on(__name__, job) group_left foo `,
296`foo + on(__name__, job) group_right foo `,
125b211eLukasz Mierzwa9 months ago297`group by (env, cluster) (
298up{env="prod", job="foo"} and on (instance) (services_enabled == 999)
299)`,
300`group by (env, cluster) (
301up{env="prod", job="foo"} * on (instance) (services_enabled == 999)
302)`,
303`foo / on(instance) sum(bar)`,
304`foo / on(instance) group_left(cluster) sum(bar)`,
305`sum(bar) / on(instance) group_right(cluster) foo`,
306`sum(bar) * on(cluster) sum(foo)`,
1dcbf12bLukasz Mierzwa9 months ago307`
308group by (colo_name, instance, tier, animal, brand, sliver, pop_name) (
309up{node_status="v", job="node_exporter"}
310and on (instance) (metal_services_enabled == 999)
311* on (colo_name) group_left(tier, animal, brand, pop_name) colo_metadata{colo_status="v"}
312* on (instance) group_left (sliver) sliver_metadata{node_status="v"}
313)`,
314`
315up{node_status="v", job="node_exporter"}
316* on (colo_name) group_left(tier) colo_metadata{colo_status="v"}
317* on (instance) group_left (sliver) sliver_metadata{node_status="v"}
318`, // all group_left() labels are joined to the left
319`
320up{node_status="v", job="node_exporter"}
321and on (colo_name) colo_metadata{colo_status="v"}
322* on (instance) group_left (sliver) sliver_metadata{node_status="v"}
323`, // all group_left() labels are NOT joined to the left
324`
325colo_metadata{colo_status="v"} * on (colo_name) group_right(tier, animal, brand, pop_name)
326sliver_metadata{node_status="v"} * on (instance) group_right (sliver)
327(metal_services_enabled == 999) * on (instance)
328up{node_status="v", job="node_exporter"}
329`, // only instance label will be present
330`
331colo_metadata{colo_status="v"} * on (colo_name) group_right(tier, animal, brand, pop_name)
332sliver_metadata{node_status="v"} * on (instance) group_right (sliver)
333(metal_services_enabled == 999) * on (instance) group_right()
334up{node_status="v", job="node_exporter"}
335`, // no labels are joined to the right
336`
337sliver_metadata{node_status="v"} * on (instance) group_right (sliver)
338(metal_services_enabled == 999) * on (colo_name) group_left(tier, animal, brand, pop_name)
339colo_metadata{colo_status="v"}
340`, // labels from both group_left and group_right are joined
341`
342colo_metadata * on (colo_name) group_right(tier, animal, brand, pop_name)
343sliver_metadata * on (instance) group_right (sliver)
344metal_services_enabled
345`, // only sliver and tier are joined to the right
346`
347colo_metadata * on (colo_name) group_right(tier, animal, brand, pop_name)
348(
349sliver_metadata * on (instance) group_right (sliver)
350metal_services_enabled
351)
352`, // all labels are joined to the right
353`
354up{node_status="v", job="node_exporter"}
355* on(instance) group_left(node_status) sliver_metadata
356`, // group_left on a label already guaranteed on the left
357`services_enabled{job=""}`,
27e89b3bLukasz Mierzwa8 months ago358`
359group by (cluster, namespace, workload, workload_type, pod) (
360label_join(
361label_join(
362group by (cluster, namespace, job_name, pod) (
363label_join(
364kube_pod_owner{job="kube-state-metrics", owner_kind="Job"}
365, "job_name", "", "owner_name")
366)
367* on (cluster, namespace, job_name) group_left(owner_kind, owner_name)
368group by (cluster, namespace, job_name, owner_kind, owner_name) (
369kube_job_owner{job="kube-state-metrics", owner_kind!="Pod", owner_kind!=""}
370)
371, "workload", "", "owner_name")
372, "workload_type", "", "owner_kind")
373)
374`,
34d2a1f9Lukasz Mierzwa8 months ago375`foo{job="xxx"} + on(job) group_right(instance) bar{}`,
376`foo{job="xxx"} + ignoring(job) group_right(instance) bar{job="zzz"}`,
d14ce457Lukasz Mierzwa8 months ago377`foo or ignoring(job) bar`,
378`foo or on(job) bar`,
90ed0823Lukasz Mierzwa6 months ago379`
380(
381sum(rate(panics_total{module_name=~".+"}[5m])) by (colo_name, module_name)
382/
383ignoring(module_name) group_left
384sum(colo:requests:rate5m) by (colo_name)
385) > 0.01
386`,
d6f07bd4Lukasz Mierzwa4 months ago387`foo atan2 bar`,
388`foo offset -5m`,
389`foo @ 1609459200`,
390`foo @ start()`,
391`foo @ end()`,
392`foo[5m] @ 1609459200`,
393`rate(foo[5m] @ start())`,
394`histogram_quantile(0.9, rate(foo[5m]))`,
395`predict_linear(foo[5m], 3600)`,
396`clamp(foo, 0, 100)`,
397`irate(foo[5m])`,
398`delta(foo[5m])`,
399`idelta(foo[5m])`,
400`increase(foo[5m])`,
401`changes(foo[5m])`,
402`resets(foo[5m])`,
403`timestamp(foo)`,
404`sort(foo)`,
405`sort_desc(foo)`,
406`pi()`,
407`sgn(foo)`,
408`clamp_min(foo, 0)`,
409`clamp_max(foo, 100)`,
410`round(foo, 0.1)`,
411`exp(foo)`,
412`ln(foo)`,
413`log2(foo)`,
414`log10(foo)`,
415`sqrt(foo)`,
416`ceil(foo)`,
417`floor(foo)`,
418`avg_over_time(foo[5m])`,
419`min_over_time(foo[5m])`,
420`max_over_time(foo[5m])`,
421`count_over_time(foo[5m])`,
422`last_over_time(foo[5m])`,
423`present_over_time(foo[5m])`,
424`quantile_over_time(0.9, foo[5m])`,
425`absent_over_time(foo[5m])`,
426`deg(foo)`,
427`rad(foo)`,
428`acos(foo)`,
429`asin(foo)`,
430`atan(foo)`,
431`cos(foo)`,
432`sin(foo)`,
433`tan(foo)`,
434`acosh(foo)`,
435`asinh(foo)`,
436`atanh(foo)`,
437`cosh(foo)`,
438`sinh(foo)`,
439`tanh(foo)`,
440`histogram_count(foo)`,
441`histogram_sum(foo)`,
442`histogram_avg(foo)`,
443`histogram_fraction(0, 0.1, foo)`,
444`histogram_stddev(foo)`,
445`histogram_stdvar(foo)`,
446`min(foo) by(job)`,
447`max(foo) without(job)`,
448`sum(foo * on(job) group_left(cluster) bar) by(cluster)`,
449`sum(foo * on(job) group_left(cluster) bar) without(instance)`,
450`foo atan2 on(job) bar`,
451`foo atan2 on(job) group_left(cluster) bar`,
452`foo != bool bar`,
453`foo == on(job) bar`,
454`foo > on(job) group_left() bar`,
455`foo < on(job) group_right() bar`,
456`foo >= on(job) group_left(cluster) bar`,
457`foo <= on(job) group_right(cluster) bar`,
458`foo * ignoring(job) group_left() bar`,
459`foo / ignoring(job) group_right() bar`,
460`foo % bar`,
461`foo ^ bar`,
462`sum(foo * on(job) group_left(cluster) bar) by(job) * on(job) group_left(cluster) baz`,
5370ba9dLukasz Mierzwa3 months ago463`sum by (colo) (metric_a) / scalar(sum(metric_b))`, // {colo} / <number> to avoid on()
5e086569Lukasz Mierzwa10 months ago464}
b4490cabLukasz Mierzwa1 years ago465
5e086569Lukasz Mierzwa10 months ago466func TestLabelsSource(t *testing.T) {
ee682eb6Lukasz Mierzwa1 years ago467type Snapshot struct {
468Expr string
66868a3eLukasz Mierzwa9 months ago469Output []source.Source
ee682eb6Lukasz Mierzwa1 years ago470}
471
a693f2e1Lukasz Mierzwa1 years ago472_, file, _, ok := runtime.Caller(0)
473require.True(t, ok, "can't get caller function")
474file = strings.TrimSuffix(filepath.Base(file), ".go")
475
ee682eb6Lukasz Mierzwa1 years ago476done := map[string]struct{}{}
477for i, expr := range testCases {
478t.Run(strconv.Itoa(i+1), func(t *testing.T) {
479if _, ok := done[expr]; ok {
480t.Fatalf("Duplicated query: %s", expr)
481}
482done[expr] = struct{}{}
483
34d2a1f9Lukasz Mierzwa8 months ago484t.Log(expr)
ee682eb6Lukasz Mierzwa1 years ago485n, err := parser.DecodeExpr(expr)
b4490cabLukasz Mierzwa1 years ago486if err != nil {
487t.Error(err)
488t.FailNow()
489}
66868a3eLukasz Mierzwa9 months ago490output := source.LabelsSource(expr, n.Expr)
800fda88Lukasz Mierzwa1 years ago491
492for _, src := range output {
66868a3eLukasz Mierzwa9 months ago493src.WalkSources(func(s source.Source, _ *source.Join, _ *source.Unless) {
800fda88Lukasz Mierzwa1 years ago494require.Positive(t, s.Position.End, "empty position %+v", s)
6af661ebLukasz Mierzwa1 years ago495if s.DeadInfo != nil {
496require.Positive(t, s.DeadInfo.Fragment.End, "empty dead position %+v", s)
800fda88Lukasz Mierzwa1 years ago497}
498})
499}
ee682eb6Lukasz Mierzwa1 years ago500
501snap := Snapshot{
502Expr: expr,
503Output: output,
504}
505d, err := yaml.Marshal(snap)
506require.NoError(t, err, "failed to YAML encode snapshots")
a693f2e1Lukasz Mierzwa1 years ago507snaps.WithConfig(snaps.Dir("."), snaps.Filename(file)).MatchSnapshot(t, string(d))
b4490cabLukasz Mierzwa1 years ago508})
509}
510}
0fff8c1eLukasz Mierzwa1 years ago511
512func TestLabelsSourceCallCoverage(t *testing.T) {
513for name, def := range promParser.Functions {
514t.Run(name, func(t *testing.T) {
515if def.Experimental {
516t.SkipNow()
517}
518
519var b strings.Builder
520b.WriteString(name)
521b.WriteRune('(')
522for i, at := range def.ArgTypes {
523if i > 0 {
524b.WriteString(", ")
525}
526switch at {
527case promParser.ValueTypeNone:
528case promParser.ValueTypeScalar:
529b.WriteRune('1')
530case promParser.ValueTypeVector:
531b.WriteString("http_requests_total")
532case promParser.ValueTypeMatrix:
533b.WriteString("http_requests_total[2m]")
534case promParser.ValueTypeString:
535b.WriteString(`"foo"`)
536}
537}
538b.WriteRune(')')
539
540n, err := parser.DecodeExpr(b.String())
541if err != nil {
542t.Error(err)
543t.FailNow()
544}
66868a3eLukasz Mierzwa9 months ago545output := source.LabelsSource(b.String(), n.Expr)
4b70d4afLukasz Mierzwa1 years ago546require.Len(t, output, 1)
87e76148Lukasz Mierzwa1 years ago547require.NotEmpty(t, output[0].Operations)
66868a3eLukasz Mierzwa9 months ago548call, ok := source.MostOuterOperation[*promParser.Call](output[0])
87e76148Lukasz Mierzwa1 years ago549require.True(t, ok, "no call found in operations for: %q ~> %+v", b.String(), output)
550require.NotNil(t, call, "no call detected in: %q ~> %+v", b.String(), output)
a708e693Lukasz Mierzwa1 years ago551require.Equal(t, name, output[0].Operation())
4b70d4afLukasz Mierzwa1 years ago552require.Equal(t, def.ReturnType, output[0].Returns, "incorrect return type on Source{}")
0fff8c1eLukasz Mierzwa1 years ago553})
554}
555}
556
30d99502Lukasz Mierzwa4 months ago557// Verifies that experimental functions can be parsed and that
558// LabelsSource produces output.
559func TestLabelsSourceCallCoverageExperimental(t *testing.T) {
560// info() second arg must be a bare label selector, not a named metric.
561overrides := map[string]string{
562"info": `info(http_requests_total, {job="foo"})`,
563}
564
565for name, def := range promParser.Functions {
566t.Run(name, func(t *testing.T) {
567if !def.Experimental {
568t.SkipNow()
569}
570
571var b strings.Builder
572if override, ok := overrides[name]; ok {
573b.WriteString(override)
574} else {
575b.WriteString(name)
576b.WriteRune('(')
577for i, at := range def.ArgTypes {
578if i > 0 {
579b.WriteString(", ")
580}
581switch at {
582case promParser.ValueTypeNone:
583case promParser.ValueTypeScalar:
584b.WriteRune('1')
585case promParser.ValueTypeVector:
586b.WriteString("http_requests_total")
587case promParser.ValueTypeMatrix:
588b.WriteString("http_requests_total[2m]")
589case promParser.ValueTypeString:
590b.WriteString(`"foo"`)
591}
592}
593b.WriteRune(')')
594}
595
596n, err := parser.DecodeExpr(b.String())
597require.NoError(t, err, "unexpected parse error for: %s", b.String())
598
599output := source.LabelsSource(b.String(), n.Expr)
600require.NotEmpty(t, output, "LabelsSource returned no sources for: %s", b.String())
601})
602}
603}
604
0fff8c1eLukasz Mierzwa1 years ago605func TestLabelsSourceCallCoverageFail(t *testing.T) {
606n := &parser.PromQLNode{
607Expr: &promParser.Call{
608Func: &promParser.Function{
609Name: "fake_call",
610},
611},
612}
66868a3eLukasz Mierzwa9 months ago613output := source.LabelsSource("fake_call()", n.Expr)
4b70d4afLukasz Mierzwa1 years ago614require.Len(t, output, 1)
66868a3eLukasz Mierzwa9 months ago615call, ok := source.MostOuterOperation[*promParser.Call](output[0])
87e76148Lukasz Mierzwa1 years ago616require.False(t, ok, "no call should have been detected in fake function, got: %v", ok)
617require.Nil(t, call, "no call should have been detected in fake function, got: %+v", call)
0fff8c1eLukasz Mierzwa1 years ago618}
a708e693Lukasz Mierzwa1 years ago619
620func TestVectorOperation(t *testing.T) {
621n := &parser.PromQLNode{
622Expr: &promParser.NumberLiteral{
623Val: 1,
624},
625}
66868a3eLukasz Mierzwa9 months ago626output := source.LabelsSource("1", n.Expr)
a708e693Lukasz Mierzwa1 years ago627require.Len(t, output, 1)
628require.Empty(t, output[0].Operation())
629}
5e086569Lukasz Mierzwa10 months ago630
1dcbf12bLukasz Mierzwa9 months ago631func TestDeadLabelKindUnknownString(t *testing.T) {
66868a3eLukasz Mierzwa9 months ago632var dl source.DeadLabelKind = 100
1dcbf12bLukasz Mierzwa9 months ago633require.Equal(t, "unknown", dl.String())
634}
635
2d7871b1Lukasz Mierzwa8 months ago636func TestFindFuncNamePositionNoMatch(t *testing.T) {
637within := posrange.PositionRange{Start: 0, End: 8}
638pos := source.FindFuncNamePosition("sum(foo)", within, "rate")
639require.Equal(t, within, pos)
640}
641
30d99502Lukasz Mierzwa4 months ago642// Verifies that RangeSelectorMode.MarshalYAML returns "default" for the zero value.
643func TestRangeSelectorModeDefaultMarshalYAML(t *testing.T) {
644var rsm source.RangeSelectorMode
645val, err := rsm.MarshalYAML()
646require.NoError(t, err)
647require.Equal(t, "default", val)
648}
649
650// Verifies that LabelsSource correctly processes expressions that require
651// experimental parser features.
652func TestLabelsSourceWithFeatures(t *testing.T) {
653type Snapshot struct {
654Expr string
655Output []source.Source
656}
657
658_, file, _, ok := runtime.Caller(0)
659require.True(t, ok, "can't get caller function")
660file = strings.TrimSuffix(filepath.Base(file), ".go")
661
662type testCaseT struct {
663description string
664expr string
665}
666
667testCases := []testCaseT{
668// Experimental function: mad_over_time.
669{
670description: "mad_over_time",
671expr: `mad_over_time(foo[5m])`,
672},
673// Experimental aggregator: limitk.
674{
675description: "limitk",
676expr: `limitk(5, foo)`,
677},
678// Experimental function: sort_by_label.
679{
680description: "sort_by_label",
681expr: `sort_by_label(foo, "job")`,
682},
683// Duration expression in matrix selector.
684{
685description: "duration expression in matrix selector",
686expr: `foo[11s+10s]`,
687},
688// Duration expression inside rate().
689{
690description: "duration expression inside rate",
691expr: `rate(foo[5m+1m])`,
692},
693// Anchored modifier on vector selector.
694{
695description: "anchored vector selector",
696expr: `foo anchored`,
697},
698// Smoothed modifier on matrix selector.
699{
700description: "smoothed matrix selector inside rate",
701expr: `rate(foo[5m] smoothed)`,
702},
703// Fill modifier on binop.
704{
705description: "binop fill modifier",
706expr: `foo + on(job) fill(0) bar`,
707},
708// fill_left modifier on binop.
709{
710description: "binop fill_left modifier",
711expr: `foo + on(job) fill_left(0) bar`,
712},
713// Experimental function with fill modifier.
714{
715description: "experimental function with fill modifier",
716expr: `mad_over_time(foo[5m]) + on(job) fill(0) bar`,
717},
718// Experimental function with smoothed modifier.
719{
720description: "experimental function with smoothed modifier",
721expr: `mad_over_time(foo[5m] smoothed)`,
722},
723// Duration expression with smoothed modifier.
724{
725description: "duration expression with smoothed modifier",
726expr: `rate(foo[5m+1m] smoothed)`,
727},
728// fill_left modifier on binop.
729{
730description: "binop fill_left modifier only",
731expr: `foo + on(job) fill_left(0) bar`,
732},
733// fill_right modifier on binop.
734{
735description: "binop fill_right modifier only",
736expr: `foo + on(job) fill_right(0) bar`,
737},
738// Duration expression in subquery range.
739{
740description: "duration expression in subquery range",
741expr: `max_over_time(rate(foo[5m])[1h+10m:5m])`,
742},
743// Duration expression in subquery step.
744{
745description: "duration expression in subquery step",
746expr: `max_over_time(foo[1h:5m+1m])`,
747},
748// Duration expression in both subquery range and step.
749{
750description: "duration expression in subquery range and step",
751expr: `max_over_time(rate(foo[5m])[1h+10m:5m+1m])`,
752},
753// Duration expression in vector selector offset.
754{
755description: "duration expression in vector offset",
756expr: `foo offset 5m+1m`,
757},
d6f07bd4Lukasz Mierzwa4 months ago758// Duration expression in vector selector offset using parenthesized
759// duration to trigger OriginalOffsetExpr on VectorSelector.
760{
761description: "duration expression in vector selector offset expr",
762expr: `foo offset (5m+1m)`,
763},
764// Duration expression in subquery offset using parenthesized duration
765// to trigger OriginalOffsetExpr on SubqueryExpr.
766{
767description: "duration expression in subquery offset expr",
768expr: `max_over_time(foo[1h:5m] offset (5m+1m))`,
769},
770// Fill modifier with group_right (CardOneToMany).
771{
772description: "fill with group_right",
773expr: `foo + on(job) group_right() fill(0) bar`,
774},
775// Fill modifier with group_left (CardManyToOne).
776{
777description: "fill with group_left",
778expr: `foo + on(job) group_left() fill(0) bar`,
779},
30d99502Lukasz Mierzwa4 months ago780// All four features combined in a single query.
781{
782description: "all four features combined",
783expr: `mad_over_time(foo[5m+1m] smoothed) + on(job) fill(0) bar`,
784},
d6f07bd4Lukasz Mierzwa4 months ago785// Experimental aggregator: limitk.
786{
787description: "limitk aggregator",
788expr: `limitk(5, foo) by(job)`,
789},
790// Experimental aggregator: limit_ratio.
791{
792description: "limit_ratio aggregator",
793expr: `limit_ratio(0.5, foo) by(job)`,
794},
795// Experimental aggregator: limitk without grouping.
796{
797description: "limitk without grouping",
798expr: `limitk(5, foo)`,
799},
800// Experimental aggregator: limit_ratio with without().
801{
802description: "limit_ratio with without",
803expr: `limit_ratio(0.5, foo) without(job)`,
804},
30d99502Lukasz Mierzwa4 months ago805}
806
807for _, tc := range testCases {
808t.Run(tc.description, func(t *testing.T) {
809n, err := parser.DecodeExpr(tc.expr)
810require.NoError(t, err, "unexpected parse error for: %s", tc.expr)
811
812output := source.LabelsSource(tc.expr, n.Expr)
813require.NotEmpty(t, output, "LabelsSource returned no sources for: %s", tc.expr)
814
815snap := Snapshot{
816Expr: tc.expr,
817Output: output,
818}
819d, err := yaml.Marshal(snap)
820require.NoError(t, err, "failed to YAML encode snapshots")
821snaps.WithConfig(snaps.Dir("."), snaps.Filename(file)).MatchSnapshot(t, string(d))
822})
823}
824}
825
5e086569Lukasz Mierzwa10 months ago826func BenchmarkLabelsSource(b *testing.B) {
827type testCase struct {
828node promParser.Node
829expr string
830}
831queries := make([]testCase, 0, len(testCases))
832for _, expr := range testCases {
833n, err := parser.DecodeExpr(expr)
834require.NoError(b, err)
835queries = append(queries, testCase{
836expr: expr,
837node: n.Expr,
838})
839}
840
841for b.Loop() {
842for _, tc := range queries {
66868a3eLukasz Mierzwa9 months ago843source.LabelsSource(tc.expr, tc.node)
5e086569Lukasz Mierzwa10 months ago844}
845}
846}