cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
cfce591c7ea27f1bdb39178995e1f65fff224fdc

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/utils/source_test.go

2285lines · modecode

1package utils_test
2
3import (
4 "strings"
5 "testing"
6 "time"
7
8 "github.com/stretchr/testify/require"
9
10 "github.com/cloudflare/pint/internal/parser"
11 "github.com/cloudflare/pint/internal/parser/utils"
12
13 promParser "github.com/prometheus/prometheus/promql/parser"
14 "github.com/prometheus/prometheus/promql/parser/posrange"
15)
16
17func TestLabelsSource(t *testing.T) {
18 type testCaseT struct {
19 expr string
20 output []utils.Source
21 }
22
23 mustParseVector := func(s string, offset int) *promParser.VectorSelector {
24 m, err := promParser.ParseExpr(s)
25 require.NoErrorf(t, err, "failed to parse vector selector: %s", s)
26 v := m.(*promParser.VectorSelector)
27 v.PosRange.Start += posrange.Pos(offset)
28 v.PosRange.End += posrange.Pos(offset)
29 return v
30 }
31
32 mustParseMatrix := func(s string, offset int) *promParser.MatrixSelector {
33 e, err := promParser.ParseExpr(s)
34 require.NoErrorf(t, err, "failed to parse matrix selector: %s", s)
35 m := e.(*promParser.MatrixSelector)
36 m.VectorSelector = mustParseVector(m.VectorSelector.String(), offset)
37 m.EndPos += posrange.Pos(offset)
38 return m
39 }
40
41 testCases := []testCaseT{
42 {
43 expr: "1",
44 output: []utils.Source{
45 {
46 Type: utils.NumberSource,
47 Returns: promParser.ValueTypeScalar,
48 FixedLabels: true,
49 ExcludeReason: map[string]utils.ExcludedLabel{
50 "": {
51 Reason: "This returns a number value with no labels.",
52 Fragment: "1",
53 },
54 },
55 },
56 },
57 },
58 {
59 expr: "1 / 5",
60 output: []utils.Source{
61 {
62 Type: utils.NumberSource,
63 Returns: promParser.ValueTypeScalar,
64 FixedLabels: true,
65 ExcludeReason: map[string]utils.ExcludedLabel{
66 "": {
67 Reason: "This returns a number value with no labels.",
68 Fragment: "1",
69 },
70 },
71 },
72 },
73 },
74 {
75 expr: `1 > bool 0`,
76 output: []utils.Source{
77 {
78 Type: utils.NumberSource,
79 Returns: promParser.ValueTypeScalar,
80 FixedLabels: true,
81 ExcludeReason: map[string]utils.ExcludedLabel{
82 "": {
83 Reason: "This returns a number value with no labels.",
84 Fragment: "1",
85 },
86 },
87 },
88 },
89 },
90 {
91 expr: `"test"`,
92 output: []utils.Source{
93 {
94 Type: utils.StringSource,
95 Returns: promParser.ValueTypeString,
96 FixedLabels: true,
97 ExcludeReason: map[string]utils.ExcludedLabel{
98 "": {
99 Reason: "This returns a string value with no labels.",
100 Fragment: `"test"`,
101 },
102 },
103 },
104 },
105 },
106 {
107 expr: "foo",
108 output: []utils.Source{
109 {
110 Type: utils.SelectorSource,
111 Returns: promParser.ValueTypeVector,
112 Selectors: []*promParser.VectorSelector{
113 mustParseVector("foo", 0),
114 },
115 },
116 },
117 },
118 {
119 expr: `foo{job="bar"}`,
120 output: []utils.Source{
121 {
122 Type: utils.SelectorSource,
123 Returns: promParser.ValueTypeVector,
124 Selectors: []*promParser.VectorSelector{
125 mustParseVector(`foo{job="bar"}`, 0),
126 },
127 GuaranteedLabels: []string{"job"},
128 },
129 },
130 },
131 {
132 expr: `foo{job="bar"} or bar{job="foo"}`,
133 output: []utils.Source{
134 {
135 Type: utils.SelectorSource,
136 Returns: promParser.ValueTypeVector,
137 Selectors: []*promParser.VectorSelector{
138 mustParseVector(`foo{job="bar"}`, 0),
139 },
140 Operation: promParser.CardManyToMany.String(),
141 GuaranteedLabels: []string{"job"},
142 },
143 {
144 Type: utils.SelectorSource,
145 Returns: promParser.ValueTypeVector,
146 Selectors: []*promParser.VectorSelector{
147 mustParseVector(`bar{job="foo"}`, 18),
148 },
149 Operation: promParser.CardManyToMany.String(),
150 GuaranteedLabels: []string{"job"},
151 },
152 },
153 },
154 {
155 expr: `foo{a="bar"} or bar{b="foo"}`,
156 output: []utils.Source{
157 {
158 Type: utils.SelectorSource,
159 Returns: promParser.ValueTypeVector,
160 Selectors: []*promParser.VectorSelector{
161 mustParseVector(`foo{a="bar"}`, 0),
162 },
163 Operation: promParser.CardManyToMany.String(),
164 GuaranteedLabels: []string{"a"},
165 },
166 {
167 Type: utils.SelectorSource,
168 Returns: promParser.ValueTypeVector,
169 Selectors: []*promParser.VectorSelector{
170 mustParseVector(`bar{b="foo"}`, 16),
171 },
172 Operation: promParser.CardManyToMany.String(),
173 GuaranteedLabels: []string{"b"},
174 },
175 },
176 },
177 {
178 expr: "foo[5m]",
179 output: []utils.Source{
180 {
181 Type: utils.SelectorSource,
182 Returns: promParser.ValueTypeVector,
183 Selectors: []*promParser.VectorSelector{
184 mustParseVector("foo", 0),
185 },
186 },
187 },
188 },
189 {
190 expr: "prometheus_build_info[2m:1m]",
191 output: []utils.Source{
192 {
193 Type: utils.SelectorSource,
194 Returns: promParser.ValueTypeVector,
195 Selectors: []*promParser.VectorSelector{
196 mustParseVector("prometheus_build_info", 0),
197 },
198 },
199 },
200 },
201 {
202 expr: "deriv(rate(distance_covered_meters_total[1m])[5m:1m])",
203 output: []utils.Source{
204 {
205 Type: utils.FuncSource,
206 Returns: promParser.ValueTypeVector,
207 Operation: "deriv",
208 Selectors: []*promParser.VectorSelector{
209 mustParseVector("distance_covered_meters_total", 11),
210 },
211 Call: &promParser.Call{
212 Func: &promParser.Function{
213 Name: "deriv",
214 ArgTypes: []promParser.ValueType{
215 promParser.ValueTypeMatrix,
216 },
217 Variadic: 0,
218 ReturnType: promParser.ValueTypeVector,
219 },
220 Args: promParser.Expressions{
221 &promParser.SubqueryExpr{
222 Expr: &promParser.Call{
223 Func: &promParser.Function{
224 Name: "rate",
225 ArgTypes: []promParser.ValueType{
226 promParser.ValueTypeMatrix,
227 },
228 Variadic: 0,
229 ReturnType: promParser.ValueTypeVector,
230 },
231 Args: promParser.Expressions{
232 mustParseMatrix(`distance_covered_meters_total[1m]`, 11),
233 },
234 PosRange: posrange.PositionRange{
235 Start: 6,
236 End: 45,
237 },
238 },
239 Range: time.Minute * 5,
240 Step: time.Minute,
241 EndPos: posrange.Pos(52),
242 },
243 },
244 PosRange: posrange.PositionRange{
245 Start: 0,
246 End: 53,
247 },
248 },
249 },
250 },
251 },
252 {
253 expr: "foo - 1",
254 output: []utils.Source{
255 {
256 Type: utils.SelectorSource,
257 Returns: promParser.ValueTypeVector,
258 Selectors: []*promParser.VectorSelector{
259 mustParseVector("foo", 0),
260 },
261 },
262 },
263 },
264 {
265 expr: "foo / 5",
266 output: []utils.Source{
267 {
268 Type: utils.SelectorSource,
269 Returns: promParser.ValueTypeVector,
270 Selectors: []*promParser.VectorSelector{
271 mustParseVector("foo", 0),
272 },
273 },
274 },
275 },
276 {
277 expr: "-foo",
278 output: []utils.Source{
279 {
280 Type: utils.SelectorSource,
281 Returns: promParser.ValueTypeVector,
282 Selectors: []*promParser.VectorSelector{
283 mustParseVector("foo", 1),
284 },
285 },
286 },
287 },
288 {
289 expr: `sum(foo{job="myjob"})`,
290 output: []utils.Source{
291 {
292 Type: utils.AggregateSource,
293 Returns: promParser.ValueTypeVector,
294 Operation: "sum",
295 Selectors: []*promParser.VectorSelector{
296 mustParseVector(`foo{job="myjob"}`, 4),
297 },
298 FixedLabels: true,
299 ExcludeReason: map[string]utils.ExcludedLabel{
300 "": {
301 Reason: "Query is using aggregation that removes all labels.",
302 Fragment: `sum(foo{job="myjob"})`,
303 },
304 },
305 },
306 },
307 },
308 {
309 expr: `sum(foo{job="myjob"}) without(job)`,
310 output: []utils.Source{
311 {
312 Type: utils.AggregateSource,
313 Returns: promParser.ValueTypeVector,
314 Operation: "sum",
315 Selectors: []*promParser.VectorSelector{
316 mustParseVector(`foo{job="myjob"}`, 4),
317 },
318 ExcludedLabels: []string{"job"},
319 ExcludeReason: map[string]utils.ExcludedLabel{
320 "job": {
321 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
322 Fragment: `sum(foo{job="myjob"}) without(job)`,
323 },
324 },
325 },
326 },
327 },
328 {
329 expr: `sum(foo) by(job)`,
330 output: []utils.Source{
331 {
332 Type: utils.AggregateSource,
333 Returns: promParser.ValueTypeVector,
334 Operation: "sum",
335 Selectors: []*promParser.VectorSelector{
336 mustParseVector(`foo`, 4),
337 },
338 IncludedLabels: []string{"job"},
339 FixedLabels: true,
340 ExcludeReason: map[string]utils.ExcludedLabel{
341 "": {
342 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
343 Fragment: `sum(foo) by(job)`,
344 },
345 },
346 },
347 },
348 },
349 {
350 expr: `sum(foo{job="myjob"}) by(job)`,
351 output: []utils.Source{
352 {
353 Type: utils.AggregateSource,
354 Returns: promParser.ValueTypeVector,
355 Operation: "sum",
356 Selectors: []*promParser.VectorSelector{
357 mustParseVector(`foo{job="myjob"}`, 4),
358 },
359 IncludedLabels: []string{"job"},
360 GuaranteedLabels: []string{"job"},
361 FixedLabels: true,
362 ExcludeReason: map[string]utils.ExcludedLabel{
363 "": {
364 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
365 Fragment: `sum(foo{job="myjob"}) by(job)`,
366 },
367 },
368 },
369 },
370 },
371 {
372 expr: `abs(foo{job="myjob"} or bar{cluster="dev"})`,
373 output: []utils.Source{
374 {
375 Type: utils.FuncSource,
376 Returns: promParser.ValueTypeVector,
377 Operation: "abs",
378 Selectors: []*promParser.VectorSelector{
379 mustParseVector(`foo{job="myjob"}`, 4),
380 mustParseVector(`bar{cluster="dev"}`, 24),
381 },
382 Call: &promParser.Call{
383 Func: &promParser.Function{
384 Name: "abs",
385 ArgTypes: []promParser.ValueType{
386 promParser.ValueTypeVector,
387 },
388 Variadic: 0,
389 ReturnType: promParser.ValueTypeVector,
390 },
391 Args: promParser.Expressions{
392 &promParser.BinaryExpr{
393 Op: promParser.LOR,
394 LHS: mustParseVector(`foo{job="myjob"}`, 4),
395 RHS: mustParseVector(`bar{cluster="dev"}`, 24),
396 VectorMatching: &promParser.VectorMatching{
397 Card: promParser.CardManyToMany,
398 },
399 },
400 },
401 PosRange: posrange.PositionRange{
402 Start: 0,
403 End: 43,
404 },
405 },
406 },
407 },
408 },
409 {
410 expr: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
411 output: []utils.Source{
412 {
413 Type: utils.AggregateSource,
414 Returns: promParser.ValueTypeVector,
415 Operation: "sum",
416 Selectors: []*promParser.VectorSelector{
417 mustParseVector(`foo{job="myjob"}`, 4),
418 },
419 GuaranteedLabels: []string{"job"},
420 ExcludedLabels: []string{"instance"},
421 ExcludeReason: map[string]utils.ExcludedLabel{
422 "instance": {
423 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
424 Fragment: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
425 },
426 },
427 },
428 {
429 Type: utils.AggregateSource,
430 Returns: promParser.ValueTypeVector,
431 Operation: "sum",
432 Selectors: []*promParser.VectorSelector{
433 mustParseVector(`bar{cluster="dev"}`, 24),
434 },
435 GuaranteedLabels: []string{"cluster"},
436 ExcludedLabels: []string{"instance"},
437 ExcludeReason: map[string]utils.ExcludedLabel{
438 "instance": {
439 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
440 Fragment: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
441 },
442 },
443 },
444 },
445 },
446 {
447 expr: `sum(foo{job="myjob"}) without(instance)`,
448 output: []utils.Source{
449 {
450 Type: utils.AggregateSource,
451 Returns: promParser.ValueTypeVector,
452 Operation: "sum",
453 Selectors: []*promParser.VectorSelector{
454 mustParseVector(`foo{job="myjob"}`, 4),
455 },
456 GuaranteedLabels: []string{"job"},
457 ExcludedLabels: []string{"instance"},
458 ExcludeReason: map[string]utils.ExcludedLabel{
459 "instance": {
460 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
461 Fragment: `sum(foo{job="myjob"}) without(instance)`,
462 },
463 },
464 },
465 },
466 },
467 {
468 expr: `min(foo{job="myjob"}) / max(foo{job="myjob"})`,
469 output: []utils.Source{
470 {
471 Type: utils.AggregateSource,
472 Returns: promParser.ValueTypeVector,
473 Operation: "min",
474 Selectors: []*promParser.VectorSelector{
475 mustParseVector(`foo{job="myjob"}`, 4),
476 },
477 FixedLabels: true,
478 ExcludeReason: map[string]utils.ExcludedLabel{
479 "": {
480 Reason: "Query is using aggregation that removes all labels.",
481 Fragment: `min(foo{job="myjob"})`,
482 },
483 },
484 },
485 },
486 },
487 {
488 expr: `max(foo{job="myjob"}) / min(foo{job="myjob"})`,
489 output: []utils.Source{
490 {
491 Type: utils.AggregateSource,
492 Returns: promParser.ValueTypeVector,
493 Operation: "max",
494 Selectors: []*promParser.VectorSelector{
495 mustParseVector(`foo{job="myjob"}`, 4),
496 },
497 FixedLabels: true,
498 ExcludeReason: map[string]utils.ExcludedLabel{
499 "": {
500 Reason: "Query is using aggregation that removes all labels.",
501 Fragment: `max(foo{job="myjob"})`,
502 },
503 },
504 },
505 },
506 },
507 {
508 expr: `avg(foo{job="myjob"}) by(job)`,
509 output: []utils.Source{
510 {
511 Type: utils.AggregateSource,
512 Returns: promParser.ValueTypeVector,
513 Operation: "avg",
514 Selectors: []*promParser.VectorSelector{
515 mustParseVector(`foo{job="myjob"}`, 4),
516 },
517 GuaranteedLabels: []string{"job"},
518 IncludedLabels: []string{"job"},
519 FixedLabels: true,
520 ExcludeReason: map[string]utils.ExcludedLabel{
521 "": {
522 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
523 Fragment: `avg(foo{job="myjob"}) by(job)`,
524 },
525 },
526 },
527 },
528 },
529 {
530 expr: `group(foo) by(job)`,
531 output: []utils.Source{
532 {
533 Type: utils.AggregateSource,
534 Returns: promParser.ValueTypeVector,
535 Operation: "group",
536 Selectors: []*promParser.VectorSelector{
537 mustParseVector(`foo`, 6),
538 },
539 IncludedLabels: []string{"job"},
540 FixedLabels: true,
541 ExcludeReason: map[string]utils.ExcludedLabel{
542 "": {
543 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
544 Fragment: `group(foo) by(job)`,
545 },
546 },
547 },
548 },
549 },
550 {
551 expr: `stddev(rate(foo[5m]))`,
552 output: []utils.Source{
553 {
554 Type: utils.AggregateSource,
555 Returns: promParser.ValueTypeVector,
556 Operation: "stddev",
557 Selectors: []*promParser.VectorSelector{
558 mustParseVector(`foo`, 12),
559 },
560 FixedLabels: true,
561 ExcludeReason: map[string]utils.ExcludedLabel{
562 "": {
563 Reason: "Query is using aggregation that removes all labels.",
564 Fragment: `stddev(rate(foo[5m]))`,
565 },
566 },
567 },
568 },
569 },
570 {
571 expr: `stdvar(rate(foo[5m]))`,
572 output: []utils.Source{
573 {
574 Type: utils.AggregateSource,
575 Returns: promParser.ValueTypeVector,
576 Operation: "stdvar",
577 Selectors: []*promParser.VectorSelector{
578 mustParseVector(`foo`, 12),
579 },
580 FixedLabels: true,
581 ExcludeReason: map[string]utils.ExcludedLabel{
582 "": {
583 Reason: "Query is using aggregation that removes all labels.",
584 Fragment: `stdvar(rate(foo[5m]))`,
585 },
586 },
587 },
588 },
589 },
590 {
591 expr: `stddev_over_time(foo[5m])`,
592 output: []utils.Source{
593 {
594 Type: utils.FuncSource,
595 Returns: promParser.ValueTypeVector,
596 Operation: "stddev_over_time",
597 Selectors: []*promParser.VectorSelector{
598 mustParseVector(`foo`, 17),
599 },
600 Call: &promParser.Call{
601 Func: &promParser.Function{
602 Name: "stddev_over_time",
603 ArgTypes: []promParser.ValueType{
604 promParser.ValueTypeMatrix,
605 },
606 Variadic: 0,
607 ReturnType: promParser.ValueTypeVector,
608 },
609 Args: promParser.Expressions{
610 mustParseMatrix(`foo[5m]`, 17),
611 },
612 PosRange: posrange.PositionRange{
613 Start: 0,
614 End: 25,
615 },
616 },
617 },
618 },
619 },
620 {
621 expr: `stdvar_over_time(foo[5m])`,
622 output: []utils.Source{
623 {
624 Type: utils.FuncSource,
625 Returns: promParser.ValueTypeVector,
626 Operation: "stdvar_over_time",
627 Selectors: []*promParser.VectorSelector{
628 mustParseVector(`foo`, 17),
629 },
630 Call: &promParser.Call{
631 Func: &promParser.Function{
632 Name: "stdvar_over_time",
633 ArgTypes: []promParser.ValueType{
634 promParser.ValueTypeMatrix,
635 },
636 Variadic: 0,
637 ReturnType: promParser.ValueTypeVector,
638 },
639 Args: promParser.Expressions{
640 mustParseMatrix(`foo[5m]`, 17),
641 },
642 PosRange: posrange.PositionRange{
643 Start: 0,
644 End: 25,
645 },
646 },
647 },
648 },
649 },
650 {
651 expr: `quantile(0.9, rate(foo[5m]))`,
652 output: []utils.Source{
653 {
654 Type: utils.AggregateSource,
655 Returns: promParser.ValueTypeVector,
656 Operation: "quantile",
657 Selectors: []*promParser.VectorSelector{
658 mustParseVector(`foo`, 19),
659 },
660 FixedLabels: true,
661 ExcludeReason: map[string]utils.ExcludedLabel{
662 "": {
663 Reason: "Query is using aggregation that removes all labels.",
664 Fragment: `quantile(0.9, rate(foo[5m]))`,
665 },
666 },
667 },
668 },
669 },
670 {
671 expr: `count_values("version", build_version)`,
672 output: []utils.Source{
673 {
674 Type: utils.AggregateSource,
675 Returns: promParser.ValueTypeVector,
676 Operation: "count_values",
677 Selectors: []*promParser.VectorSelector{
678 mustParseVector(`build_version`, 24),
679 },
680 GuaranteedLabels: []string{"version"},
681 IncludedLabels: []string{"version"},
682 FixedLabels: true,
683 ExcludeReason: map[string]utils.ExcludedLabel{
684 "": {
685 Reason: "Query is using aggregation that removes all labels.",
686 Fragment: `count_values("version", build_version)`,
687 },
688 },
689 },
690 },
691 },
692 {
693 expr: `count_values("version", build_version) without(job)`,
694 output: []utils.Source{
695 {
696 Type: utils.AggregateSource,
697 Returns: promParser.ValueTypeVector,
698 Operation: "count_values",
699 Selectors: []*promParser.VectorSelector{
700 mustParseVector(`build_version`, 24),
701 },
702 IncludedLabels: []string{"version"},
703 GuaranteedLabels: []string{"version"},
704 ExcludedLabels: []string{"job"},
705 ExcludeReason: map[string]utils.ExcludedLabel{
706 "job": {
707 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
708 Fragment: `count_values("version", build_version) without(job)`,
709 },
710 },
711 },
712 },
713 },
714 {
715 expr: `count_values("version", build_version{job="foo"}) without(job)`,
716 output: []utils.Source{
717 {
718 Type: utils.AggregateSource,
719 Returns: promParser.ValueTypeVector,
720 Operation: "count_values",
721 Selectors: []*promParser.VectorSelector{
722 mustParseVector(`build_version{job="foo"}`, 24),
723 },
724 IncludedLabels: []string{"version"},
725 GuaranteedLabels: []string{"version"},
726 ExcludedLabels: []string{"job"},
727 ExcludeReason: map[string]utils.ExcludedLabel{
728 "job": {
729 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
730 Fragment: `count_values("version", build_version{job="foo"}) without(job)`,
731 },
732 },
733 },
734 },
735 },
736 {
737 expr: `count_values("version", build_version) by(job)`,
738 output: []utils.Source{
739 {
740 Type: utils.AggregateSource,
741 Returns: promParser.ValueTypeVector,
742 Operation: "count_values",
743 Selectors: []*promParser.VectorSelector{
744 mustParseVector(`build_version`, 24),
745 },
746 GuaranteedLabels: []string{"version"},
747 IncludedLabels: []string{"job", "version"},
748 FixedLabels: true,
749 ExcludeReason: map[string]utils.ExcludedLabel{
750 "": {
751 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
752 Fragment: `count_values("version", build_version) by(job)`,
753 },
754 },
755 },
756 },
757 },
758 {
759 expr: `topk(10, foo{job="myjob"}) > 10`,
760 output: []utils.Source{
761 {
762 Type: utils.AggregateSource,
763 Returns: promParser.ValueTypeVector,
764 Operation: "topk",
765 Selectors: []*promParser.VectorSelector{
766 mustParseVector(`foo{job="myjob"}`, 9),
767 },
768 GuaranteedLabels: []string{"job"},
769 },
770 },
771 },
772 {
773 expr: `topk(10, foo or bar)`,
774 output: []utils.Source{
775 {
776 Type: utils.AggregateSource,
777 Returns: promParser.ValueTypeVector,
778 Operation: "topk",
779 Selectors: []*promParser.VectorSelector{
780 mustParseVector(`foo`, 9),
781 },
782 },
783 {
784 Type: utils.AggregateSource,
785 Operation: "topk",
786 Returns: promParser.ValueTypeVector,
787 Selectors: []*promParser.VectorSelector{
788 mustParseVector(`bar`, 16),
789 },
790 },
791 },
792 },
793 {
794 expr: `rate(foo[10m])`,
795 output: []utils.Source{
796 {
797 Type: utils.FuncSource,
798 Returns: promParser.ValueTypeVector,
799 Operation: "rate",
800 Selectors: []*promParser.VectorSelector{
801 mustParseVector(`foo`, 5),
802 },
803 Call: &promParser.Call{
804 Func: &promParser.Function{
805 Name: "rate",
806 ArgTypes: []promParser.ValueType{
807 promParser.ValueTypeMatrix,
808 },
809 Variadic: 0,
810 ReturnType: promParser.ValueTypeVector,
811 },
812 Args: promParser.Expressions{
813 mustParseMatrix(`foo[10m]`, 5),
814 },
815 PosRange: posrange.PositionRange{
816 Start: 0,
817 End: 14,
818 },
819 },
820 },
821 },
822 },
823 {
824 expr: `sum(rate(foo[10m])) without(instance)`,
825 output: []utils.Source{
826 {
827 Type: utils.AggregateSource,
828 Returns: promParser.ValueTypeVector,
829 Operation: "sum",
830 Selectors: []*promParser.VectorSelector{
831 mustParseVector(`foo`, 9),
832 },
833 ExcludedLabels: []string{"instance"},
834 ExcludeReason: map[string]utils.ExcludedLabel{
835 "instance": {
836 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
837 Fragment: `sum(rate(foo[10m])) without(instance)`,
838 },
839 },
840 },
841 },
842 },
843 {
844 expr: `foo{job="foo"} / bar`,
845 output: []utils.Source{
846 {
847 Type: utils.SelectorSource,
848 Returns: promParser.ValueTypeVector,
849 Operation: promParser.CardOneToOne.String(),
850 Selectors: []*promParser.VectorSelector{
851 mustParseVector(`foo{job="foo"}`, 0),
852 },
853 GuaranteedLabels: []string{"job"},
854 },
855 },
856 },
857 {
858 expr: `foo{job="foo"} * on(instance) bar`,
859 output: []utils.Source{
860 {
861 Type: utils.SelectorSource,
862 Returns: promParser.ValueTypeVector,
863 Operation: promParser.CardOneToOne.String(),
864 Selectors: []*promParser.VectorSelector{
865 mustParseVector(`foo{job="foo"}`, 0),
866 },
867 GuaranteedLabels: []string{"job"},
868 IncludedLabels: []string{"instance"},
869 FixedLabels: true,
870 ExcludeReason: map[string]utils.ExcludedLabel{
871 "": {
872 Reason: "Query is using one-to-one vector matching with `on(instance)`, only labels included inside `on(...)` will be present on the results.",
873 Fragment: `foo{job="foo"} * on(instance) bar`,
874 },
875 },
876 },
877 },
878 },
879 {
880 expr: `foo{job="foo"} * on(instance) group_left(bar) bar`,
881 output: []utils.Source{
882 {
883 Type: utils.SelectorSource,
884 Returns: promParser.ValueTypeVector,
885 Operation: promParser.CardManyToOne.String(),
886 Selectors: []*promParser.VectorSelector{
887 mustParseVector(`foo{job="foo"}`, 0),
888 },
889 IncludedLabels: []string{"bar", "instance"},
890 GuaranteedLabels: []string{"job"},
891 },
892 },
893 },
894 {
895 expr: `foo{job="foo"} * on(instance) group_left(cluster) bar{cluster="bar", ignored="true"}`,
896 output: []utils.Source{
897 {
898 Type: utils.SelectorSource,
899 Returns: promParser.ValueTypeVector,
900 Operation: promParser.CardManyToOne.String(),
901 Selectors: []*promParser.VectorSelector{
902 mustParseVector(`foo{job="foo"}`, 0),
903 },
904 IncludedLabels: []string{"cluster", "instance"},
905 GuaranteedLabels: []string{"job"},
906 },
907 },
908 },
909 {
910 expr: `foo{job="foo", ignored="true"} * on(instance) group_right(job) bar{cluster="bar"}`,
911 output: []utils.Source{
912 {
913 Type: utils.SelectorSource,
914 Returns: promParser.ValueTypeVector,
915 Operation: promParser.CardOneToMany.String(),
916 Selectors: []*promParser.VectorSelector{
917 mustParseVector(`bar{cluster="bar"}`, 63),
918 },
919 IncludedLabels: []string{"job", "instance"},
920 GuaranteedLabels: []string{"cluster"},
921 },
922 },
923 },
924 {
925 expr: `count(foo / bar)`,
926 output: []utils.Source{
927 {
928 Type: utils.AggregateSource,
929 Returns: promParser.ValueTypeVector,
930 Operation: "count",
931 Selectors: []*promParser.VectorSelector{
932 mustParseVector(`foo`, 6),
933 },
934 FixedLabels: true,
935 ExcludeReason: map[string]utils.ExcludedLabel{
936 "": {
937 Reason: "Query is using aggregation that removes all labels.",
938 Fragment: `count(foo / bar)`,
939 },
940 },
941 },
942 },
943 },
944 {
945 expr: `count(up{job="a"} / on () up{job="b"})`,
946 output: []utils.Source{
947 {
948 Type: utils.AggregateSource,
949 Returns: promParser.ValueTypeVector,
950 Operation: "count",
951 Selectors: []*promParser.VectorSelector{
952 mustParseVector(`up{job="a"}`, 6),
953 },
954 FixedLabels: true,
955 ExcludeReason: map[string]utils.ExcludedLabel{
956 "": {
957 Reason: "Query is using aggregation that removes all labels.",
958 Fragment: `count(up{job="a"} / on () up{job="b"})`,
959 },
960 },
961 },
962 },
963 },
964 {
965 expr: `count(up{job="a"} / on (env) up{job="b"})`,
966 output: []utils.Source{
967 {
968 Type: utils.AggregateSource,
969 Returns: promParser.ValueTypeVector,
970 Operation: "count",
971 Selectors: []*promParser.VectorSelector{
972 mustParseVector(`up{job="a"}`, 6),
973 },
974 FixedLabels: true,
975 ExcludeReason: map[string]utils.ExcludedLabel{
976 "": {
977 Reason: "Query is using aggregation that removes all labels.",
978 Fragment: `count(up{job="a"} / on (env) up{job="b"})`,
979 },
980 },
981 },
982 },
983 },
984 {
985 expr: `foo{job="foo", instance="1"} and bar`,
986 output: []utils.Source{
987 {
988 Type: utils.SelectorSource,
989 Returns: promParser.ValueTypeVector,
990 Operation: promParser.CardManyToMany.String(),
991 Selectors: []*promParser.VectorSelector{
992 mustParseVector(`foo{job="foo", instance="1"}`, 0),
993 },
994 GuaranteedLabels: []string{"job", "instance"},
995 },
996 },
997 },
998 {
999 expr: `foo{job="foo", instance="1"} and on(cluster) bar`,
1000 output: []utils.Source{
1001 {
1002 Type: utils.SelectorSource,
1003 Returns: promParser.ValueTypeVector,
1004 Operation: promParser.CardManyToMany.String(),
1005 Selectors: []*promParser.VectorSelector{
1006 mustParseVector(`foo{job="foo", instance="1"}`, 0),
1007 },
1008 IncludedLabels: []string{"cluster"},
1009 GuaranteedLabels: []string{"job", "instance"},
1010 },
1011 },
1012 },
1013 {
1014 expr: `topk(10, foo)`,
1015 output: []utils.Source{
1016 {
1017 Type: utils.AggregateSource,
1018 Returns: promParser.ValueTypeVector,
1019 Operation: "topk",
1020 Selectors: []*promParser.VectorSelector{
1021 mustParseVector(`foo`, 9),
1022 },
1023 },
1024 },
1025 },
1026 {
1027 expr: `topk(10, foo) without(cluster)`,
1028 output: []utils.Source{
1029 {
1030 Type: utils.AggregateSource,
1031 Returns: promParser.ValueTypeVector,
1032 Operation: "topk",
1033 Selectors: []*promParser.VectorSelector{
1034 mustParseVector(`foo`, 9),
1035 },
1036 },
1037 },
1038 },
1039 {
1040 expr: `topk(10, foo) by(cluster)`,
1041 output: []utils.Source{
1042 {
1043 Type: utils.AggregateSource,
1044 Returns: promParser.ValueTypeVector,
1045 Operation: "topk",
1046 Selectors: []*promParser.VectorSelector{
1047 mustParseVector(`foo`, 9),
1048 },
1049 },
1050 },
1051 },
1052 {
1053 expr: `bottomk(10, sum(rate(foo[5m])) without(job))`,
1054 output: []utils.Source{
1055 {
1056 Type: utils.AggregateSource,
1057 Returns: promParser.ValueTypeVector,
1058 Operation: "bottomk",
1059 Selectors: []*promParser.VectorSelector{
1060 mustParseVector(`foo`, 21),
1061 },
1062 ExcludedLabels: []string{"job"},
1063 ExcludeReason: map[string]utils.ExcludedLabel{
1064 "job": {
1065 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
1066 Fragment: `sum(rate(foo[5m])) without(job)`,
1067 },
1068 },
1069 },
1070 },
1071 },
1072 {
1073 expr: `foo or bar`,
1074 output: []utils.Source{
1075 {
1076 Type: utils.SelectorSource,
1077 Returns: promParser.ValueTypeVector,
1078 Operation: promParser.CardManyToMany.String(),
1079 Selectors: []*promParser.VectorSelector{
1080 mustParseVector(`foo`, 0),
1081 },
1082 },
1083 {
1084 Type: utils.SelectorSource,
1085 Returns: promParser.ValueTypeVector,
1086 Operation: promParser.CardManyToMany.String(),
1087 Selectors: []*promParser.VectorSelector{
1088 mustParseVector(`bar`, 7),
1089 },
1090 },
1091 },
1092 },
1093 {
1094 expr: `foo or bar or baz`,
1095 output: []utils.Source{
1096 {
1097 Type: utils.SelectorSource,
1098 Returns: promParser.ValueTypeVector,
1099 Operation: promParser.CardManyToMany.String(),
1100 Selectors: []*promParser.VectorSelector{
1101 mustParseVector(`foo`, 0),
1102 },
1103 },
1104 {
1105 Type: utils.SelectorSource,
1106 Returns: promParser.ValueTypeVector,
1107 Operation: promParser.CardManyToMany.String(),
1108 Selectors: []*promParser.VectorSelector{
1109 mustParseVector(`bar`, 7),
1110 },
1111 },
1112 {
1113 Type: utils.SelectorSource,
1114 Returns: promParser.ValueTypeVector,
1115 Operation: promParser.CardManyToMany.String(),
1116 Selectors: []*promParser.VectorSelector{
1117 mustParseVector(`baz`, 14),
1118 },
1119 },
1120 },
1121 },
1122 {
1123 expr: `(foo or bar) or baz`,
1124 output: []utils.Source{
1125 {
1126 Type: utils.SelectorSource,
1127 Returns: promParser.ValueTypeVector,
1128 Operation: promParser.CardManyToMany.String(),
1129 Selectors: []*promParser.VectorSelector{
1130 mustParseVector(`foo`, 1),
1131 },
1132 },
1133 {
1134 Type: utils.SelectorSource,
1135 Returns: promParser.ValueTypeVector,
1136 Operation: promParser.CardManyToMany.String(),
1137 Selectors: []*promParser.VectorSelector{
1138 mustParseVector(`bar`, 8),
1139 },
1140 },
1141 {
1142 Type: utils.SelectorSource,
1143 Returns: promParser.ValueTypeVector,
1144 Operation: promParser.CardManyToMany.String(),
1145 Selectors: []*promParser.VectorSelector{
1146 mustParseVector(`baz`, 16),
1147 },
1148 },
1149 },
1150 },
1151 {
1152 expr: `foo unless bar`,
1153 output: []utils.Source{
1154 {
1155 Type: utils.SelectorSource,
1156 Returns: promParser.ValueTypeVector,
1157 Operation: promParser.CardManyToMany.String(),
1158 Selectors: []*promParser.VectorSelector{
1159 mustParseVector(`foo`, 0),
1160 },
1161 },
1162 },
1163 },
1164 {
1165 expr: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
1166 output: []utils.Source{
1167 {
1168 Type: utils.AggregateSource,
1169 Returns: promParser.ValueTypeVector,
1170 Operation: "count",
1171 Selectors: []*promParser.VectorSelector{
1172 mustParseVector(`up{job="foo", cluster="dev"}`, 10),
1173 },
1174 ExcludedLabels: []string{"job", "cluster"}, // FIXME empty
1175 FixedLabels: true,
1176 ExcludeReason: map[string]utils.ExcludedLabel{
1177 "": {
1178 Reason: "Query is using aggregation with `by(job, cluster)`, only labels included inside `by(...)` will be present on the results.",
1179 Fragment: `sum(up{job="foo", cluster="dev"}) by(job, cluster)`,
1180 },
1181 "job": {
1182 Reason: "Query is using aggregation with `without(job, cluster)`, all labels included inside `without(...)` will be removed from the results.",
1183 Fragment: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
1184 },
1185 "cluster": {
1186 Reason: "Query is using aggregation with `without(job, cluster)`, all labels included inside `without(...)` will be removed from the results.",
1187 Fragment: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
1188 },
1189 },
1190 },
1191 },
1192 },
1193 {
1194 expr: "year()",
1195 output: []utils.Source{
1196 {
1197 Type: utils.FuncSource,
1198 Returns: promParser.ValueTypeVector,
1199 Operation: "year",
1200 FixedLabels: true,
1201 ExcludeReason: map[string]utils.ExcludedLabel{
1202 "": {
1203 Reason: "Calling `year()` with no arguments will return an empty time series with no labels.",
1204 Fragment: `year()`,
1205 },
1206 },
1207 Call: &promParser.Call{
1208 Func: &promParser.Function{
1209 Name: "year",
1210 ArgTypes: []promParser.ValueType{
1211 promParser.ValueTypeVector,
1212 },
1213 Variadic: 1,
1214 ReturnType: promParser.ValueTypeVector,
1215 },
1216 Args: promParser.Expressions{},
1217 PosRange: posrange.PositionRange{
1218 Start: 0,
1219 End: 6,
1220 },
1221 },
1222 },
1223 },
1224 },
1225 {
1226 expr: "year(foo)",
1227 output: []utils.Source{
1228 {
1229 Type: utils.FuncSource,
1230 Returns: promParser.ValueTypeVector,
1231 Operation: "year",
1232 Selectors: []*promParser.VectorSelector{
1233 mustParseVector("foo", 5),
1234 },
1235 Call: &promParser.Call{
1236 Func: &promParser.Function{
1237 Name: "year",
1238 ArgTypes: []promParser.ValueType{
1239 promParser.ValueTypeVector,
1240 },
1241 Variadic: 1,
1242 ReturnType: promParser.ValueTypeVector,
1243 },
1244 Args: promParser.Expressions{
1245 mustParseVector("foo", 5),
1246 },
1247 PosRange: posrange.PositionRange{
1248 Start: 0,
1249 End: 9,
1250 },
1251 },
1252 },
1253 },
1254 },
1255 {
1256 expr: `label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")`,
1257 output: []utils.Source{
1258 {
1259 Type: utils.FuncSource,
1260 Returns: promParser.ValueTypeVector,
1261 Operation: "label_join",
1262 Selectors: []*promParser.VectorSelector{
1263 mustParseVector(`up{job="api-server",src1="a",src2="b",src3="c"}`, 11),
1264 },
1265 GuaranteedLabels: []string{"job", "src1", "src2", "src3", "foo"},
1266 Call: &promParser.Call{
1267 Func: &promParser.Function{
1268 Name: "label_join",
1269 ArgTypes: []promParser.ValueType{
1270 promParser.ValueTypeVector,
1271 promParser.ValueTypeString,
1272 promParser.ValueTypeString,
1273 promParser.ValueTypeString,
1274 },
1275 Variadic: -1,
1276 ReturnType: promParser.ValueTypeVector,
1277 },
1278 Args: promParser.Expressions{
1279 mustParseVector(`up{job="api-server",src1="a",src2="b",src3="c"}`, 11),
1280 &promParser.StringLiteral{
1281 Val: "foo",
1282 PosRange: posrange.PositionRange{Start: 60, End: 65},
1283 },
1284 &promParser.StringLiteral{
1285 Val: ",",
1286 PosRange: posrange.PositionRange{Start: 67, End: 70},
1287 },
1288 &promParser.StringLiteral{
1289 Val: "src1",
1290 PosRange: posrange.PositionRange{Start: 72, End: 78},
1291 },
1292 &promParser.StringLiteral{
1293 Val: "src2",
1294 PosRange: posrange.PositionRange{Start: 80, End: 86},
1295 },
1296 &promParser.StringLiteral{
1297 Val: "src3",
1298 PosRange: posrange.PositionRange{Start: 88, End: 94},
1299 },
1300 },
1301 PosRange: posrange.PositionRange{
1302 Start: 0,
1303 End: 95,
1304 },
1305 },
1306 },
1307 },
1308 },
1309 {
1310 expr: `
1311(
1312 sum(foo:sum > 0) without(notify)
1313 * on(job) group_left(notify)
1314 job:notify
1315)
1316and on(job)
1317sum(foo:count) by(job) > 20`,
1318 output: []utils.Source{
1319 {
1320 Type: utils.AggregateSource,
1321 Returns: promParser.ValueTypeVector,
1322 Operation: "sum",
1323 Selectors: []*promParser.VectorSelector{
1324 mustParseVector(`foo:sum`, 8),
1325 },
1326 IncludedLabels: []string{"notify", "job"},
1327 ExcludeReason: map[string]utils.ExcludedLabel{},
1328 },
1329 },
1330 },
1331 {
1332 expr: `container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`,
1333 output: []utils.Source{
1334 {
1335 Type: utils.SelectorSource,
1336 Returns: promParser.ValueTypeVector,
1337 Operation: promParser.CardOneToOne.String(),
1338 Selectors: []*promParser.VectorSelector{
1339 mustParseVector(`container_file_descriptors`, 0),
1340 },
1341 IncludedLabels: []string{"instance", "app_name"},
1342 FixedLabels: true,
1343 ExcludeReason: map[string]utils.ExcludedLabel{
1344 "": {
1345 Reason: "Query is using one-to-one vector matching with `on(instance, app_name)`, only labels included inside `on(...)` will be present on the results.",
1346 Fragment: `container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`,
1347 },
1348 },
1349 },
1350 },
1351 },
1352 {
1353 expr: `container_file_descriptors / on (instance, app_name) group_left() container_ulimits_soft{ulimit="max_open_files"}`,
1354 output: []utils.Source{
1355 {
1356 Type: utils.SelectorSource,
1357 Returns: promParser.ValueTypeVector,
1358 Operation: promParser.CardManyToOne.String(),
1359 Selectors: []*promParser.VectorSelector{
1360 mustParseVector(`container_file_descriptors`, 0),
1361 },
1362 IncludedLabels: []string{"instance", "app_name"},
1363 },
1364 },
1365 },
1366 {
1367 expr: `absent(foo{job="bar"})`,
1368 output: []utils.Source{
1369 {
1370 Type: utils.FuncSource,
1371 Returns: promParser.ValueTypeVector,
1372 Operation: "absent",
1373 Selectors: []*promParser.VectorSelector{
1374 mustParseVector(`foo{job="bar"}`, 7),
1375 },
1376 IncludedLabels: []string{"job"},
1377 GuaranteedLabels: []string{"job"},
1378 FixedLabels: true,
1379 ExcludeReason: map[string]utils.ExcludedLabel{
1380 "": {
1381 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1382 Fragment: `absent(foo{job="bar"})`,
1383 },
1384 },
1385 Call: &promParser.Call{
1386 Func: &promParser.Function{
1387 Name: "absent",
1388 ArgTypes: []promParser.ValueType{
1389 promParser.ValueTypeVector,
1390 },
1391 Variadic: 0,
1392 ReturnType: promParser.ValueTypeVector,
1393 },
1394 Args: promParser.Expressions{
1395 mustParseVector(`foo{job="bar"}`, 7),
1396 },
1397 PosRange: posrange.PositionRange{
1398 Start: 0,
1399 End: 22,
1400 },
1401 },
1402 },
1403 },
1404 },
1405 {
1406 expr: `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`,
1407 output: []utils.Source{
1408 {
1409 Type: utils.FuncSource,
1410 Returns: promParser.ValueTypeVector,
1411 Operation: "absent",
1412 Selectors: []*promParser.VectorSelector{
1413 mustParseVector(`foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7),
1414 },
1415 IncludedLabels: []string{"job", "env"},
1416 GuaranteedLabels: []string{"job", "env"},
1417 FixedLabels: true,
1418 ExcludeReason: map[string]utils.ExcludedLabel{
1419 "": {
1420 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1421 Fragment: `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`,
1422 },
1423 },
1424 Call: &promParser.Call{
1425 Func: &promParser.Function{
1426 Name: "absent",
1427 ArgTypes: []promParser.ValueType{
1428 promParser.ValueTypeVector,
1429 },
1430 Variadic: 0,
1431 ReturnType: promParser.ValueTypeVector,
1432 },
1433 Args: promParser.Expressions{
1434 mustParseVector(`foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7),
1435 },
1436 PosRange: posrange.PositionRange{
1437 Start: 0,
1438 End: 66,
1439 },
1440 },
1441 },
1442 },
1443 },
1444 {
1445 expr: `absent(sum(foo) by(job, instance))`,
1446 output: []utils.Source{
1447 {
1448 Type: utils.FuncSource,
1449 Returns: promParser.ValueTypeVector,
1450 Operation: "absent",
1451 Selectors: []*promParser.VectorSelector{
1452 mustParseVector(`foo`, 11),
1453 },
1454 FixedLabels: true,
1455 ExcludeReason: map[string]utils.ExcludedLabel{
1456 "": {
1457 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1458 Fragment: `absent(sum(foo) by(job, instance))`,
1459 },
1460 },
1461 Call: &promParser.Call{
1462 Func: &promParser.Function{
1463 Name: "absent",
1464 ArgTypes: []promParser.ValueType{
1465 promParser.ValueTypeVector,
1466 },
1467 Variadic: 0,
1468 ReturnType: promParser.ValueTypeVector,
1469 },
1470 Args: promParser.Expressions{
1471 &promParser.AggregateExpr{
1472 Op: promParser.SUM,
1473 Expr: mustParseVector("foo", 11),
1474 Grouping: []string{"job", "instance"},
1475 PosRange: posrange.PositionRange{
1476 Start: 7,
1477 End: 33,
1478 },
1479 },
1480 },
1481 PosRange: posrange.PositionRange{
1482 Start: 0,
1483 End: 34,
1484 },
1485 },
1486 },
1487 },
1488 },
1489 {
1490 expr: `absent(foo{job="prometheus", xxx="1"}) AND on(job) prometheus_build_info`,
1491 output: []utils.Source{
1492 {
1493 Type: utils.FuncSource,
1494 Returns: promParser.ValueTypeVector,
1495 Operation: "absent",
1496 Selectors: []*promParser.VectorSelector{
1497 mustParseVector(`foo{job="prometheus", xxx="1"}`, 7),
1498 },
1499 IncludedLabels: []string{"job", "xxx"},
1500 GuaranteedLabels: []string{"job", "xxx"},
1501 FixedLabels: true,
1502 ExcludeReason: map[string]utils.ExcludedLabel{
1503 "": {
1504 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1505 Fragment: `absent(foo{job="prometheus", xxx="1"})`,
1506 },
1507 },
1508 Call: &promParser.Call{
1509 Func: &promParser.Function{
1510 Name: "absent",
1511 ArgTypes: []promParser.ValueType{
1512 promParser.ValueTypeVector,
1513 },
1514 Variadic: 0,
1515 ReturnType: promParser.ValueTypeVector,
1516 },
1517 Args: promParser.Expressions{
1518 mustParseVector(`foo{job="prometheus", xxx="1"}`, 7),
1519 },
1520 PosRange: posrange.PositionRange{
1521 Start: 0,
1522 End: 38,
1523 },
1524 },
1525 },
1526 },
1527 },
1528 {
1529 expr: `1 + sum(foo) by(notjob)`,
1530 output: []utils.Source{
1531 {
1532 Type: utils.AggregateSource,
1533 Returns: promParser.ValueTypeVector,
1534 Operation: "sum",
1535 Selectors: []*promParser.VectorSelector{
1536 mustParseVector(`foo`, 8),
1537 },
1538 IncludedLabels: []string{"notjob"},
1539 FixedLabels: true,
1540 ExcludeReason: map[string]utils.ExcludedLabel{
1541 "": {
1542 Reason: "Query is using aggregation with `by(notjob)`, only labels included inside `by(...)` will be present on the results.",
1543 Fragment: `sum(foo) by(notjob)`,
1544 },
1545 },
1546 },
1547 },
1548 },
1549 {
1550 expr: `count(node_exporter_build_info) by (instance, version) != ignoring(package,version) group_left(foo) count(deb_package_version) by (instance, version, package)`,
1551 output: []utils.Source{
1552 {
1553 Type: utils.AggregateSource,
1554 Returns: promParser.ValueTypeVector,
1555 Operation: "count",
1556 Selectors: []*promParser.VectorSelector{
1557 mustParseVector(`node_exporter_build_info`, 6),
1558 },
1559 IncludedLabels: []string{"instance", "version", "foo"}, // FIXME foo shouldn't be there because count() doesn't produce it
1560 FixedLabels: true,
1561 ExcludeReason: map[string]utils.ExcludedLabel{
1562 "": {
1563 Reason: "Query is using aggregation with `by(instance, version)`, only labels included inside `by(...)` will be present on the results.",
1564 Fragment: `count(node_exporter_build_info) by (instance, version)`,
1565 },
1566 },
1567 },
1568 },
1569 },
1570 {
1571 expr: `absent(foo) or absent(bar)`,
1572 output: []utils.Source{
1573 {
1574 Type: utils.FuncSource,
1575 Returns: promParser.ValueTypeVector,
1576 Operation: "absent",
1577 Selectors: []*promParser.VectorSelector{
1578 mustParseVector(`foo`, 7),
1579 },
1580 FixedLabels: true,
1581 ExcludeReason: map[string]utils.ExcludedLabel{
1582 "": {
1583 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1584 Fragment: `absent(foo)`,
1585 },
1586 },
1587 Call: &promParser.Call{
1588 Func: &promParser.Function{
1589 Name: "absent",
1590 ArgTypes: []promParser.ValueType{
1591 promParser.ValueTypeVector,
1592 },
1593 Variadic: 0,
1594 ReturnType: promParser.ValueTypeVector,
1595 },
1596 Args: promParser.Expressions{
1597 mustParseVector(`foo`, 7),
1598 },
1599 PosRange: posrange.PositionRange{
1600 Start: 0,
1601 End: 11,
1602 },
1603 },
1604 },
1605 {
1606 Type: utils.FuncSource,
1607 Returns: promParser.ValueTypeVector,
1608 Operation: "absent",
1609 Selectors: []*promParser.VectorSelector{
1610 mustParseVector(`bar`, 22),
1611 },
1612 FixedLabels: true,
1613 ExcludeReason: map[string]utils.ExcludedLabel{
1614 "": {
1615 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1616 Fragment: `absent(bar)`,
1617 },
1618 },
1619 Call: &promParser.Call{
1620 Func: &promParser.Function{
1621 Name: "absent",
1622 ArgTypes: []promParser.ValueType{
1623 promParser.ValueTypeVector,
1624 },
1625 Variadic: 0,
1626 ReturnType: promParser.ValueTypeVector,
1627 },
1628 Args: promParser.Expressions{
1629 mustParseVector(`bar`, 22),
1630 },
1631 PosRange: posrange.PositionRange{
1632 Start: 15,
1633 End: 26,
1634 },
1635 },
1636 },
1637 },
1638 },
1639 {
1640 expr: `absent_over_time(foo[5m]) or absent(bar)`,
1641 output: []utils.Source{
1642 {
1643 Type: utils.FuncSource,
1644 Returns: promParser.ValueTypeVector,
1645 Operation: "absent_over_time",
1646 Selectors: []*promParser.VectorSelector{
1647 mustParseVector(`foo`, 17),
1648 },
1649 FixedLabels: true,
1650 ExcludeReason: map[string]utils.ExcludedLabel{
1651 "": {
1652 Reason: "The [absent_over_time()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent_over_time) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1653 Fragment: `absent_over_time(foo[5m])`,
1654 },
1655 },
1656 Call: &promParser.Call{
1657 Func: &promParser.Function{
1658 Name: "absent_over_time",
1659 ArgTypes: []promParser.ValueType{
1660 promParser.ValueTypeMatrix,
1661 },
1662 Variadic: 0,
1663 ReturnType: promParser.ValueTypeVector,
1664 },
1665 Args: promParser.Expressions{
1666 mustParseMatrix(`foo[5m]`, 17),
1667 },
1668 PosRange: posrange.PositionRange{
1669 Start: 0,
1670 End: 25,
1671 },
1672 },
1673 },
1674 {
1675 Type: utils.FuncSource,
1676 Returns: promParser.ValueTypeVector,
1677 Operation: "absent",
1678 Selectors: []*promParser.VectorSelector{
1679 mustParseVector(`bar`, 36),
1680 },
1681 FixedLabels: true,
1682 ExcludeReason: map[string]utils.ExcludedLabel{
1683 "": {
1684 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1685 Fragment: `absent(bar)`,
1686 },
1687 },
1688 Call: &promParser.Call{
1689 Func: &promParser.Function{
1690 Name: "absent",
1691 ArgTypes: []promParser.ValueType{
1692 promParser.ValueTypeVector,
1693 },
1694 Variadic: 0,
1695 ReturnType: promParser.ValueTypeVector,
1696 },
1697 Args: promParser.Expressions{
1698 mustParseVector(`bar`, 36),
1699 },
1700 PosRange: posrange.PositionRange{
1701 Start: 29,
1702 End: 40,
1703 },
1704 },
1705 },
1706 },
1707 },
1708 {
1709 expr: `bar * on() group_right(cluster, env) absent(foo{job="xxx"})`,
1710 output: []utils.Source{
1711 {
1712 Type: utils.FuncSource,
1713 Returns: promParser.ValueTypeVector,
1714 Operation: "absent",
1715 Selectors: []*promParser.VectorSelector{
1716 mustParseVector(`foo{job="xxx"}`, 44),
1717 },
1718 IncludedLabels: []string{"job", "cluster", "env"},
1719 GuaranteedLabels: []string{"job"},
1720 FixedLabels: true,
1721 ExcludeReason: map[string]utils.ExcludedLabel{
1722 "": {
1723 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1724 Fragment: `absent(foo{job="xxx"})`,
1725 },
1726 },
1727 Call: &promParser.Call{
1728 Func: &promParser.Function{
1729 Name: "absent",
1730 ArgTypes: []promParser.ValueType{
1731 promParser.ValueTypeVector,
1732 },
1733 Variadic: 0,
1734 ReturnType: promParser.ValueTypeVector,
1735 },
1736 Args: promParser.Expressions{
1737 mustParseVector(`foo{job="xxx"}`, 44),
1738 },
1739 PosRange: posrange.PositionRange{
1740 Start: 37,
1741 End: 59,
1742 },
1743 },
1744 },
1745 },
1746 },
1747 {
1748 expr: `bar * on() group_right() absent(foo{job="xxx"})`,
1749 output: []utils.Source{
1750 {
1751 Type: utils.FuncSource,
1752 Returns: promParser.ValueTypeVector,
1753 Operation: "absent",
1754 Selectors: []*promParser.VectorSelector{
1755 mustParseVector(`foo{job="xxx"}`, 32),
1756 },
1757 IncludedLabels: []string{"job"},
1758 GuaranteedLabels: []string{"job"},
1759 FixedLabels: true,
1760 ExcludeReason: map[string]utils.ExcludedLabel{
1761 "": {
1762 Reason: "The [absent()](https://prometheus.io/docs/prometheus/latest/querying/functions/#absent) function is used to check if provided query doesn't match any time series.\nYou will only get any results back if the metric selector you pass doesn't match anything.\nSince there are no matching time series there are also no labels. If some time series is missing you cannot read its labels.\nThis means that the only labels you can get back from absent call are the ones you pass to it.\nIf you're hoping to get instance specific labels this way and alert when some target is down then that won't work, use the `up` metric instead.",
1763 Fragment: `absent(foo{job="xxx"})`,
1764 },
1765 },
1766 Call: &promParser.Call{
1767 Func: &promParser.Function{
1768 Name: "absent",
1769 ArgTypes: []promParser.ValueType{
1770 promParser.ValueTypeVector,
1771 },
1772 Variadic: 0,
1773 ReturnType: promParser.ValueTypeVector,
1774 },
1775 Args: promParser.Expressions{
1776 mustParseVector(`foo{job="xxx"}`, 32),
1777 },
1778 PosRange: posrange.PositionRange{
1779 Start: 25,
1780 End: 47,
1781 },
1782 },
1783 },
1784 },
1785 },
1786 {
1787 expr: "vector(1)",
1788 output: []utils.Source{
1789 {
1790 Type: utils.FuncSource,
1791 Returns: promParser.ValueTypeVector,
1792 Operation: "vector",
1793 FixedLabels: true,
1794 ExcludeReason: map[string]utils.ExcludedLabel{
1795 "": {
1796 Reason: "Calling `vector()` will return a vector value with no labels.",
1797 Fragment: `vector(1)`,
1798 },
1799 },
1800 Call: &promParser.Call{
1801 Func: &promParser.Function{
1802 Name: "vector",
1803 ArgTypes: []promParser.ValueType{
1804 promParser.ValueTypeScalar,
1805 },
1806 Variadic: 0,
1807 ReturnType: promParser.ValueTypeVector,
1808 },
1809 Args: promParser.Expressions{
1810 &promParser.NumberLiteral{
1811 Val: 1,
1812 PosRange: posrange.PositionRange{
1813 Start: 7,
1814 End: 8,
1815 },
1816 },
1817 },
1818 PosRange: posrange.PositionRange{
1819 Start: 0,
1820 End: 9,
1821 },
1822 },
1823 },
1824 },
1825 },
1826 {
1827 expr: `sum_over_time(foo{job="myjob"}[5m])`,
1828 output: []utils.Source{
1829 {
1830 Type: utils.FuncSource,
1831 Returns: promParser.ValueTypeVector,
1832 Operation: "sum_over_time",
1833 Selectors: []*promParser.VectorSelector{
1834 mustParseVector(`foo{job="myjob"}`, 14),
1835 },
1836 GuaranteedLabels: []string{"job"},
1837 Call: &promParser.Call{
1838 Func: &promParser.Function{
1839 Name: "sum_over_time",
1840 ArgTypes: []promParser.ValueType{
1841 promParser.ValueTypeMatrix,
1842 },
1843 Variadic: 0,
1844 ReturnType: promParser.ValueTypeVector,
1845 },
1846 Args: promParser.Expressions{
1847 mustParseMatrix(`foo{job="myjob"}[5m]`, 14),
1848 },
1849 PosRange: posrange.PositionRange{
1850 Start: 0,
1851 End: 35,
1852 },
1853 },
1854 },
1855 },
1856 },
1857 {
1858 expr: `days_in_month()`,
1859 output: []utils.Source{
1860 {
1861 Type: utils.FuncSource,
1862 Returns: promParser.ValueTypeVector,
1863 Operation: "days_in_month",
1864 FixedLabels: true,
1865 ExcludeReason: map[string]utils.ExcludedLabel{
1866 "": {
1867 Reason: "Calling `days_in_month()` with no arguments will return an empty time series with no labels.",
1868 Fragment: `days_in_month()`,
1869 },
1870 },
1871 Call: &promParser.Call{
1872 Func: &promParser.Function{
1873 Name: "days_in_month",
1874 ArgTypes: []promParser.ValueType{
1875 promParser.ValueTypeVector,
1876 },
1877 Variadic: 1,
1878 ReturnType: promParser.ValueTypeVector,
1879 },
1880 Args: promParser.Expressions{},
1881 PosRange: posrange.PositionRange{
1882 Start: 0,
1883 End: 15,
1884 },
1885 },
1886 },
1887 },
1888 },
1889 {
1890 expr: `days_in_month(foo{job="foo"})`,
1891 output: []utils.Source{
1892 {
1893 Type: utils.FuncSource,
1894 Returns: promParser.ValueTypeVector,
1895 Operation: "days_in_month",
1896 Selectors: []*promParser.VectorSelector{
1897 mustParseVector(`foo{job="foo"}`, 14),
1898 },
1899 GuaranteedLabels: []string{"job"},
1900 Call: &promParser.Call{
1901 Func: &promParser.Function{
1902 Name: "days_in_month",
1903 ArgTypes: []promParser.ValueType{
1904 promParser.ValueTypeVector,
1905 },
1906 Variadic: 1,
1907 ReturnType: promParser.ValueTypeVector,
1908 },
1909 Args: promParser.Expressions{
1910 mustParseVector(`foo{job="foo"}`, 14),
1911 },
1912 PosRange: posrange.PositionRange{
1913 Start: 0,
1914 End: 29,
1915 },
1916 },
1917 },
1918 },
1919 },
1920 {
1921 expr: `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`,
1922 output: []utils.Source{
1923 {
1924 Type: utils.FuncSource,
1925 Returns: promParser.ValueTypeVector,
1926 Operation: "label_replace",
1927 Selectors: []*promParser.VectorSelector{
1928 mustParseVector(`up{job="api-server",service="a:c"}`, 14),
1929 },
1930 GuaranteedLabels: []string{"job", "service", "foo"},
1931 Call: &promParser.Call{
1932 Func: &promParser.Function{
1933 Name: "label_replace",
1934 ArgTypes: []promParser.ValueType{
1935 promParser.ValueTypeVector,
1936 promParser.ValueTypeString,
1937 promParser.ValueTypeString,
1938 promParser.ValueTypeString,
1939 promParser.ValueTypeString,
1940 },
1941 Variadic: 0,
1942 ReturnType: promParser.ValueTypeVector,
1943 },
1944 Args: promParser.Expressions{
1945 mustParseVector(`up{job="api-server",service="a:c"}`, 14),
1946 &promParser.StringLiteral{
1947 Val: "foo",
1948 PosRange: posrange.PositionRange{
1949 Start: 50,
1950 End: 55,
1951 },
1952 },
1953 &promParser.StringLiteral{
1954 Val: "$1",
1955 PosRange: posrange.PositionRange{
1956 Start: 57,
1957 End: 61,
1958 },
1959 },
1960 &promParser.StringLiteral{
1961 Val: "service",
1962 PosRange: posrange.PositionRange{
1963 Start: 63,
1964 End: 72,
1965 },
1966 },
1967 &promParser.StringLiteral{
1968 Val: "(.*):.*",
1969 PosRange: posrange.PositionRange{
1970 Start: 74,
1971 End: 83,
1972 },
1973 },
1974 },
1975 PosRange: posrange.PositionRange{
1976 Start: 0,
1977 End: 84,
1978 },
1979 },
1980 },
1981 },
1982 },
1983 {
1984 expr: `(time() - my_metric) > 5*3600`,
1985 output: []utils.Source{
1986 {
1987 Type: utils.SelectorSource,
1988 Returns: promParser.ValueTypeVector,
1989 Selectors: []*promParser.VectorSelector{
1990 mustParseVector("my_metric", 10),
1991 },
1992 },
1993 },
1994 },
1995 {
1996 expr: `up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`,
1997 output: []utils.Source{
1998 {
1999 Type: utils.SelectorSource,
2000 Returns: promParser.ValueTypeVector,
2001 Operation: promParser.CardOneToOne.String(),
2002 Selectors: []*promParser.VectorSelector{
2003 mustParseVector(`up{instance="a", job="prometheus"}`, 0),
2004 },
2005 GuaranteedLabels: []string{"instance"},
2006 ExcludedLabels: []string{"job"},
2007 ExcludeReason: map[string]utils.ExcludedLabel{
2008 "job": {
2009 Reason: "Query is using one-to-one vector matching with `ignoring(job)`, all labels included inside `ignoring(...)` will be removed on the results.",
2010 Fragment: `up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`,
2011 },
2012 },
2013 },
2014 },
2015 },
2016 {
2017 expr: `
2018avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})
2019< 0.5 > 0
2020or sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})
2021< on() count(colo_router_tier:disabled_pops:max{tier="1",router=~"edge.*"}) * 0.4 > 0
2022or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})
2023< 0.1 > 0
2024`,
2025 output: []utils.Source{
2026 {
2027 Type: utils.AggregateSource,
2028 Returns: promParser.ValueTypeVector,
2029 Operation: "avg",
2030 Selectors: []*promParser.VectorSelector{
2031 mustParseVector(`router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"}`, 41),
2032 },
2033 ExcludedLabels: []string{"router", "colo_id", "instance"},
2034 ExcludeReason: map[string]utils.ExcludedLabel{
2035 "router": {
2036 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2037 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`,
2038 },
2039 "colo_id": {
2040 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2041 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`,
2042 },
2043 "instance": {
2044 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2045 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`,
2046 },
2047 },
2048 },
2049 {
2050 Type: utils.AggregateSource,
2051 Returns: promParser.ValueTypeVector,
2052 Operation: "sum",
2053 Selectors: []*promParser.VectorSelector{
2054 mustParseVector(`router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"}`, 155),
2055 },
2056 GuaranteedLabels: []string{"cidr_use_case"},
2057 ExcludedLabels: []string{"router", "colo_id", "instance"},
2058 FixedLabels: true,
2059 ExcludeReason: map[string]utils.ExcludedLabel{
2060 "router": {
2061 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2062 Fragment: `sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})`,
2063 },
2064 "colo_id": {
2065 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2066 Fragment: `sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})`,
2067 },
2068 "instance": {
2069 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2070 Fragment: `sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})`,
2071 },
2072 "": {
2073 Reason: "Query is using one-to-one vector matching with `on()`, only labels included inside `on(...)` will be present on the results.",
2074 Fragment: "sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~\".*tier1.*\"})\n< on() count(colo_router_tier:disabled_pops:max{tier=\"1\",router=~\"edge.*\"}) * 0.4",
2075 },
2076 },
2077 },
2078 {
2079 Type: utils.AggregateSource,
2080 Returns: promParser.ValueTypeVector,
2081 Operation: "avg",
2082 Selectors: []*promParser.VectorSelector{
2083 mustParseVector(`router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"}`, 343),
2084 },
2085 GuaranteedLabels: []string{"cidr_use_case"},
2086 ExcludedLabels: []string{"router", "colo_id", "instance"},
2087 ExcludeReason: map[string]utils.ExcludedLabel{
2088 "router": {
2089 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2090 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`,
2091 },
2092 "colo_id": {
2093 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2094 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`,
2095 },
2096 "instance": {
2097 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2098 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`,
2099 },
2100 },
2101 },
2102 },
2103 },
2104 {
2105 expr: `label_replace(sum(foo) without(instance), "instance", "none", "", "")`,
2106 output: []utils.Source{
2107 {
2108 Type: utils.FuncSource,
2109 Returns: promParser.ValueTypeVector,
2110 Operation: "label_replace",
2111 Selectors: []*promParser.VectorSelector{
2112 mustParseVector(`foo`, 18),
2113 },
2114 GuaranteedLabels: []string{"instance"},
2115 Call: &promParser.Call{
2116 Func: &promParser.Function{
2117 Name: "label_replace",
2118 ArgTypes: []promParser.ValueType{
2119 promParser.ValueTypeVector,
2120 promParser.ValueTypeString,
2121 promParser.ValueTypeString,
2122 promParser.ValueTypeString,
2123 promParser.ValueTypeString,
2124 },
2125 Variadic: 0,
2126 ReturnType: promParser.ValueTypeVector,
2127 },
2128 Args: promParser.Expressions{
2129 &promParser.AggregateExpr{
2130 Op: promParser.SUM,
2131 Expr: mustParseVector("foo", 18),
2132 Grouping: []string{"instance"},
2133 Without: true,
2134 PosRange: posrange.PositionRange{
2135 Start: 14,
2136 End: 40,
2137 },
2138 },
2139 &promParser.StringLiteral{
2140 Val: "instance",
2141 PosRange: posrange.PositionRange{
2142 Start: 42,
2143 End: 52,
2144 },
2145 },
2146 &promParser.StringLiteral{
2147 Val: "none",
2148 PosRange: posrange.PositionRange{
2149 Start: 54,
2150 End: 60,
2151 },
2152 },
2153 &promParser.StringLiteral{
2154 Val: "",
2155 PosRange: posrange.PositionRange{
2156 Start: 62,
2157 End: 64,
2158 },
2159 },
2160 &promParser.StringLiteral{
2161 Val: "",
2162 PosRange: posrange.PositionRange{
2163 Start: 66,
2164 End: 68,
2165 },
2166 },
2167 },
2168 PosRange: posrange.PositionRange{
2169 Start: 0,
2170 End: 69,
2171 },
2172 },
2173 },
2174 },
2175 },
2176 {
2177 expr: `
2178sum by (region, target, colo_name) (
2179 sum_over_time(probe_success{job="abc"}[5m])
2180 or
2181 vector(1)
2182) == 0`,
2183 output: []utils.Source{
2184 {
2185 Type: utils.AggregateSource,
2186 Returns: promParser.ValueTypeVector,
2187 Operation: "sum",
2188 Selectors: []*promParser.VectorSelector{
2189 mustParseVector(`probe_success{job="abc"}`, 56),
2190 },
2191 IncludedLabels: []string{"region", "target", "colo_name"},
2192 FixedLabels: true,
2193 ExcludeReason: map[string]utils.ExcludedLabel{
2194 "": {
2195 Reason: "Query is using aggregation with `by(region, target, colo_name)`, only labels included inside `by(...)` will be present on the results.",
2196 Fragment: "sum by (region, target, colo_name) (\n sum_over_time(probe_success{job=\"abc\"}[5m])\n\tor\n\tvector(1)\n)",
2197 },
2198 },
2199 },
2200 {
2201 Type: utils.AggregateSource,
2202 Returns: promParser.ValueTypeVector,
2203 Operation: "sum",
2204 FixedLabels: true,
2205 ExcludeReason: map[string]utils.ExcludedLabel{
2206 "": {
2207 Reason: "Calling `vector()` will return a vector value with no labels.",
2208 Fragment: "vector(1)",
2209 },
2210 },
2211 },
2212 },
2213 },
2214 }
2215
2216 for _, tc := range testCases {
2217 t.Run(tc.expr, func(t *testing.T) {
2218 n, err := parser.DecodeExpr(tc.expr)
2219 if err != nil {
2220 t.Error(err)
2221 t.FailNow()
2222 }
2223 output := utils.LabelsSource(tc.expr, n.Expr)
2224 require.Len(t, output, len(tc.output))
2225 for i := range len(tc.output) {
2226 require.EqualExportedValues(t, tc.output[i], output[i], "Mismatch at index %d", i)
2227 }
2228 })
2229 }
2230}
2231
2232func TestLabelsSourceCallCoverage(t *testing.T) {
2233 for name, def := range promParser.Functions {
2234 t.Run(name, func(t *testing.T) {
2235 if def.Experimental {
2236 t.SkipNow()
2237 }
2238
2239 var b strings.Builder
2240 b.WriteString(name)
2241 b.WriteRune('(')
2242 for i, at := range def.ArgTypes {
2243 if i > 0 {
2244 b.WriteString(", ")
2245 }
2246 switch at {
2247 case promParser.ValueTypeNone:
2248 case promParser.ValueTypeScalar:
2249 b.WriteRune('1')
2250 case promParser.ValueTypeVector:
2251 b.WriteString("http_requests_total")
2252 case promParser.ValueTypeMatrix:
2253 b.WriteString("http_requests_total[2m]")
2254 case promParser.ValueTypeString:
2255 b.WriteString(`"foo"`)
2256 }
2257 }
2258 b.WriteRune(')')
2259
2260 n, err := parser.DecodeExpr(b.String())
2261 if err != nil {
2262 t.Error(err)
2263 t.FailNow()
2264 }
2265 output := utils.LabelsSource(b.String(), n.Expr)
2266 require.Len(t, output, 1)
2267 require.NotNil(t, output[0].Call, "no call detected in: %q ~> %+v", b.String(), output)
2268 require.Equal(t, name, output[0].Operation)
2269 require.Equal(t, def.ReturnType, output[0].Returns, "incorrect return type on Source{}")
2270 })
2271 }
2272}
2273
2274func TestLabelsSourceCallCoverageFail(t *testing.T) {
2275 n := &parser.PromQLNode{
2276 Expr: &promParser.Call{
2277 Func: &promParser.Function{
2278 Name: "fake_call",
2279 },
2280 },
2281 }
2282 output := utils.LabelsSource("fake_call()", n.Expr)
2283 require.Len(t, output, 1)
2284 require.Nil(t, output[0].Call, "no call should have been detected in fake function")
2285}
2286