cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
29ed4c2ccc1fb946d416df7635c9bae86ffca5b5

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/utils/source_test.go

2905lines · 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 AlwaysReturns: true,
50 ReturnedNumbers: []float64{1},
51 ExcludeReason: map[string]utils.ExcludedLabel{
52 "": {
53 Reason: "This returns a number value with no labels.",
54 Fragment: "1",
55 },
56 },
57 },
58 },
59 },
60 {
61 expr: "1 / 5",
62 output: []utils.Source{
63 {
64 Type: utils.NumberSource,
65 Returns: promParser.ValueTypeScalar,
66 FixedLabels: true,
67 AlwaysReturns: true,
68 ReturnedNumbers: []float64{0.2},
69 ExcludeReason: map[string]utils.ExcludedLabel{
70 "": {
71 Reason: "This returns a number value with no labels.",
72 Fragment: "1",
73 },
74 },
75 },
76 },
77 },
78 {
79 expr: "(2 ^ 5) == bool 5",
80 output: []utils.Source{
81 {
82 Type: utils.NumberSource,
83 Returns: promParser.ValueTypeScalar,
84 FixedLabels: true,
85 AlwaysReturns: true,
86 IsDead: true,
87 ReturnedNumbers: []float64{32},
88 ExcludeReason: map[string]utils.ExcludedLabel{
89 "": {
90 Reason: "This returns a number value with no labels.",
91 Fragment: "2",
92 },
93 },
94 },
95 },
96 },
97 {
98 expr: "(2 ^ 5 + 11) % 5 <= bool 2",
99 output: []utils.Source{
100 {
101 Type: utils.NumberSource,
102 Returns: promParser.ValueTypeScalar,
103 FixedLabels: true,
104 AlwaysReturns: true,
105 IsDead: true,
106 ReturnedNumbers: []float64{3},
107 ExcludeReason: map[string]utils.ExcludedLabel{
108 "": {
109 Reason: "This returns a number value with no labels.",
110 Fragment: "2",
111 },
112 },
113 },
114 },
115 },
116 {
117 expr: "(2 ^ 5 + 11) % 5 >= bool 20",
118 output: []utils.Source{
119 {
120 Type: utils.NumberSource,
121 Returns: promParser.ValueTypeScalar,
122 FixedLabels: true,
123 AlwaysReturns: true,
124 IsDead: true,
125 ReturnedNumbers: []float64{3},
126 ExcludeReason: map[string]utils.ExcludedLabel{
127 "": {
128 Reason: "This returns a number value with no labels.",
129 Fragment: "2",
130 },
131 },
132 },
133 },
134 },
135 {
136 expr: "(2 ^ 5 + 11) % 5 <= bool 3",
137 output: []utils.Source{
138 {
139 Type: utils.NumberSource,
140 Returns: promParser.ValueTypeScalar,
141 FixedLabels: true,
142 AlwaysReturns: true,
143 ReturnedNumbers: []float64{3},
144 ExcludeReason: map[string]utils.ExcludedLabel{
145 "": {
146 Reason: "This returns a number value with no labels.",
147 Fragment: "2",
148 },
149 },
150 },
151 },
152 },
153 {
154 expr: "(2 ^ 5 + 11) % 5 < bool 1",
155 output: []utils.Source{
156 {
157 Type: utils.NumberSource,
158 Returns: promParser.ValueTypeScalar,
159 FixedLabels: true,
160 AlwaysReturns: true,
161 IsDead: true,
162 ReturnedNumbers: []float64{3},
163 ExcludeReason: map[string]utils.ExcludedLabel{
164 "": {
165 Reason: "This returns a number value with no labels.",
166 Fragment: "2",
167 },
168 },
169 },
170 },
171 },
172 {
173 expr: "20 - 15 < bool 1",
174 output: []utils.Source{
175 {
176 Type: utils.NumberSource,
177 Returns: promParser.ValueTypeScalar,
178 FixedLabels: true,
179 AlwaysReturns: true,
180 IsDead: true,
181 ReturnedNumbers: []float64{5},
182 ExcludeReason: map[string]utils.ExcludedLabel{
183 "": {
184 Reason: "This returns a number value with no labels.",
185 Fragment: "20",
186 },
187 },
188 },
189 },
190 },
191 {
192 expr: "2 * 5",
193 output: []utils.Source{
194 {
195 Type: utils.NumberSource,
196 Returns: promParser.ValueTypeScalar,
197 FixedLabels: true,
198 AlwaysReturns: true,
199 ReturnedNumbers: []float64{10},
200 ExcludeReason: map[string]utils.ExcludedLabel{
201 "": {
202 Reason: "This returns a number value with no labels.",
203 Fragment: "2",
204 },
205 },
206 },
207 },
208 },
209 {
210 expr: "(foo or bar) * 5",
211 output: []utils.Source{
212 {
213 Type: utils.SelectorSource,
214 Returns: promParser.ValueTypeVector,
215 Operation: promParser.CardManyToMany.String(),
216 Selectors: []*promParser.VectorSelector{
217 mustParseVector("foo", 1),
218 },
219 },
220 {
221 Type: utils.SelectorSource,
222 Returns: promParser.ValueTypeVector,
223 Operation: promParser.CardManyToMany.String(),
224 Selectors: []*promParser.VectorSelector{
225 mustParseVector("bar", 8),
226 },
227 },
228 },
229 },
230 {
231 expr: "(foo or vector(2)) * 5",
232 output: []utils.Source{
233 {
234 Type: utils.SelectorSource,
235 Returns: promParser.ValueTypeVector,
236 Operation: promParser.CardManyToMany.String(),
237 Selectors: []*promParser.VectorSelector{
238 mustParseVector("foo", 1),
239 },
240 },
241 {
242 Type: utils.FuncSource,
243 Returns: promParser.ValueTypeVector,
244 Operation: "vector",
245 FixedLabels: true,
246 AlwaysReturns: true,
247 ReturnedNumbers: []float64{10},
248 ExcludeReason: map[string]utils.ExcludedLabel{
249 "": {
250 Reason: "Calling `vector()` will return a vector value with no labels.",
251 Fragment: "vector(2)",
252 },
253 },
254 Call: &promParser.Call{
255 Func: &promParser.Function{
256 Name: "vector",
257 ArgTypes: []promParser.ValueType{
258 promParser.ValueTypeScalar,
259 },
260 Variadic: 0,
261 ReturnType: promParser.ValueTypeVector,
262 },
263 Args: promParser.Expressions{
264 &promParser.NumberLiteral{
265 Val: 2,
266 PosRange: posrange.PositionRange{
267 Start: 15,
268 End: 16,
269 },
270 },
271 },
272 PosRange: posrange.PositionRange{
273 Start: 8,
274 End: 17,
275 },
276 },
277 },
278 },
279 },
280 {
281 expr: "(foo or vector(5)) * (vector(2) or bar)",
282 output: []utils.Source{
283 {
284 Type: utils.SelectorSource,
285 Returns: promParser.ValueTypeVector,
286 Operation: promParser.CardManyToMany.String(),
287 Selectors: []*promParser.VectorSelector{
288 mustParseVector("foo", 1),
289 },
290 },
291 {
292 Type: utils.FuncSource,
293 Returns: promParser.ValueTypeVector,
294 Operation: "vector",
295 FixedLabels: true,
296 AlwaysReturns: true,
297 ReturnedNumbers: []float64{5}, // FIXME should be 10 really but it's one-to-one binops
298 ExcludeReason: map[string]utils.ExcludedLabel{
299 "": {
300 Reason: "Calling `vector()` will return a vector value with no labels.",
301 Fragment: "vector(5)",
302 },
303 },
304 Call: &promParser.Call{
305 Func: &promParser.Function{
306 Name: "vector",
307 ArgTypes: []promParser.ValueType{
308 promParser.ValueTypeScalar,
309 },
310 Variadic: 0,
311 ReturnType: promParser.ValueTypeVector,
312 },
313 Args: promParser.Expressions{
314 &promParser.NumberLiteral{
315 Val: 5,
316 PosRange: posrange.PositionRange{
317 Start: 15,
318 End: 16,
319 },
320 },
321 },
322 PosRange: posrange.PositionRange{
323 Start: 8,
324 End: 17,
325 },
326 },
327 },
328 },
329 },
330 {
331 expr: `1 > bool 0`,
332 output: []utils.Source{
333 {
334 Type: utils.NumberSource,
335 Returns: promParser.ValueTypeScalar,
336 FixedLabels: true,
337 AlwaysReturns: true,
338 ReturnedNumbers: []float64{1},
339 ExcludeReason: map[string]utils.ExcludedLabel{
340 "": {
341 Reason: "This returns a number value with no labels.",
342 Fragment: "1",
343 },
344 },
345 },
346 },
347 },
348 {
349 expr: `20 > bool 10`,
350 output: []utils.Source{
351 {
352 Type: utils.NumberSource,
353 Returns: promParser.ValueTypeScalar,
354 FixedLabels: true,
355 AlwaysReturns: true,
356 ReturnedNumbers: []float64{20},
357 ExcludeReason: map[string]utils.ExcludedLabel{
358 "": {
359 Reason: "This returns a number value with no labels.",
360 Fragment: "20",
361 },
362 },
363 },
364 },
365 },
366 {
367 expr: `"test"`,
368 output: []utils.Source{
369 {
370 Type: utils.StringSource,
371 Returns: promParser.ValueTypeString,
372 FixedLabels: true,
373 AlwaysReturns: true,
374 ExcludeReason: map[string]utils.ExcludedLabel{
375 "": {
376 Reason: "This returns a string value with no labels.",
377 Fragment: `"test"`,
378 },
379 },
380 },
381 },
382 },
383 {
384 expr: "foo",
385 output: []utils.Source{
386 {
387 Type: utils.SelectorSource,
388 Returns: promParser.ValueTypeVector,
389 Selectors: []*promParser.VectorSelector{
390 mustParseVector("foo", 0),
391 },
392 },
393 },
394 },
395 {
396 expr: `foo{job="bar"}`,
397 output: []utils.Source{
398 {
399 Type: utils.SelectorSource,
400 Returns: promParser.ValueTypeVector,
401 Selectors: []*promParser.VectorSelector{
402 mustParseVector(`foo{job="bar"}`, 0),
403 },
404 GuaranteedLabels: []string{"job"},
405 },
406 },
407 },
408 {
409 expr: `foo{job="bar"} or bar{job="foo"}`,
410 output: []utils.Source{
411 {
412 Type: utils.SelectorSource,
413 Returns: promParser.ValueTypeVector,
414 Selectors: []*promParser.VectorSelector{
415 mustParseVector(`foo{job="bar"}`, 0),
416 },
417 Operation: promParser.CardManyToMany.String(),
418 GuaranteedLabels: []string{"job"},
419 },
420 {
421 Type: utils.SelectorSource,
422 Returns: promParser.ValueTypeVector,
423 Selectors: []*promParser.VectorSelector{
424 mustParseVector(`bar{job="foo"}`, 18),
425 },
426 Operation: promParser.CardManyToMany.String(),
427 GuaranteedLabels: []string{"job"},
428 },
429 },
430 },
431 {
432 expr: `foo{a="bar"} or bar{b="foo"}`,
433 output: []utils.Source{
434 {
435 Type: utils.SelectorSource,
436 Returns: promParser.ValueTypeVector,
437 Selectors: []*promParser.VectorSelector{
438 mustParseVector(`foo{a="bar"}`, 0),
439 },
440 Operation: promParser.CardManyToMany.String(),
441 GuaranteedLabels: []string{"a"},
442 },
443 {
444 Type: utils.SelectorSource,
445 Returns: promParser.ValueTypeVector,
446 Selectors: []*promParser.VectorSelector{
447 mustParseVector(`bar{b="foo"}`, 16),
448 },
449 Operation: promParser.CardManyToMany.String(),
450 GuaranteedLabels: []string{"b"},
451 },
452 },
453 },
454 {
455 expr: "foo[5m]",
456 output: []utils.Source{
457 {
458 Type: utils.SelectorSource,
459 Returns: promParser.ValueTypeVector,
460 Selectors: []*promParser.VectorSelector{
461 mustParseVector("foo", 0),
462 },
463 },
464 },
465 },
466 {
467 expr: "prometheus_build_info[2m:1m]",
468 output: []utils.Source{
469 {
470 Type: utils.SelectorSource,
471 Returns: promParser.ValueTypeVector,
472 Selectors: []*promParser.VectorSelector{
473 mustParseVector("prometheus_build_info", 0),
474 },
475 },
476 },
477 },
478 {
479 expr: "deriv(rate(distance_covered_meters_total[1m])[5m:1m])",
480 output: []utils.Source{
481 {
482 Type: utils.FuncSource,
483 Returns: promParser.ValueTypeVector,
484 Operation: "deriv",
485 Selectors: []*promParser.VectorSelector{
486 mustParseVector("distance_covered_meters_total", 11),
487 },
488 Call: &promParser.Call{
489 Func: &promParser.Function{
490 Name: "deriv",
491 ArgTypes: []promParser.ValueType{
492 promParser.ValueTypeMatrix,
493 },
494 Variadic: 0,
495 ReturnType: promParser.ValueTypeVector,
496 },
497 Args: promParser.Expressions{
498 &promParser.SubqueryExpr{
499 Expr: &promParser.Call{
500 Func: &promParser.Function{
501 Name: "rate",
502 ArgTypes: []promParser.ValueType{
503 promParser.ValueTypeMatrix,
504 },
505 Variadic: 0,
506 ReturnType: promParser.ValueTypeVector,
507 },
508 Args: promParser.Expressions{
509 mustParseMatrix(`distance_covered_meters_total[1m]`, 11),
510 },
511 PosRange: posrange.PositionRange{
512 Start: 6,
513 End: 45,
514 },
515 },
516 Range: time.Minute * 5,
517 Step: time.Minute,
518 EndPos: posrange.Pos(52),
519 },
520 },
521 PosRange: posrange.PositionRange{
522 Start: 0,
523 End: 53,
524 },
525 },
526 },
527 },
528 },
529 {
530 expr: "foo - 1",
531 output: []utils.Source{
532 {
533 Type: utils.SelectorSource,
534 Returns: promParser.ValueTypeVector,
535 Selectors: []*promParser.VectorSelector{
536 mustParseVector("foo", 0),
537 },
538 },
539 },
540 },
541 {
542 expr: "foo / 5",
543 output: []utils.Source{
544 {
545 Type: utils.SelectorSource,
546 Returns: promParser.ValueTypeVector,
547 Selectors: []*promParser.VectorSelector{
548 mustParseVector("foo", 0),
549 },
550 },
551 },
552 },
553 {
554 expr: "-foo",
555 output: []utils.Source{
556 {
557 Type: utils.SelectorSource,
558 Returns: promParser.ValueTypeVector,
559 Selectors: []*promParser.VectorSelector{
560 mustParseVector("foo", 1),
561 },
562 },
563 },
564 },
565 {
566 expr: `sum(foo{job="myjob"})`,
567 output: []utils.Source{
568 {
569 Type: utils.AggregateSource,
570 Returns: promParser.ValueTypeVector,
571 Operation: "sum",
572 Selectors: []*promParser.VectorSelector{
573 mustParseVector(`foo{job="myjob"}`, 4),
574 },
575 FixedLabels: true,
576 ExcludeReason: map[string]utils.ExcludedLabel{
577 "": {
578 Reason: "Query is using aggregation that removes all labels.",
579 Fragment: `sum(foo{job="myjob"})`,
580 },
581 },
582 },
583 },
584 },
585 {
586 expr: `sum(foo{job="myjob"}) without(job)`,
587 output: []utils.Source{
588 {
589 Type: utils.AggregateSource,
590 Returns: promParser.ValueTypeVector,
591 Operation: "sum",
592 Selectors: []*promParser.VectorSelector{
593 mustParseVector(`foo{job="myjob"}`, 4),
594 },
595 ExcludedLabels: []string{"job"},
596 ExcludeReason: map[string]utils.ExcludedLabel{
597 "job": {
598 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
599 Fragment: `sum(foo{job="myjob"}) without(job)`,
600 },
601 },
602 },
603 },
604 },
605 {
606 expr: `sum(foo) by(job)`,
607 output: []utils.Source{
608 {
609 Type: utils.AggregateSource,
610 Returns: promParser.ValueTypeVector,
611 Operation: "sum",
612 Selectors: []*promParser.VectorSelector{
613 mustParseVector(`foo`, 4),
614 },
615 IncludedLabels: []string{"job"},
616 FixedLabels: true,
617 ExcludeReason: map[string]utils.ExcludedLabel{
618 "": {
619 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
620 Fragment: `sum(foo) by(job)`,
621 },
622 },
623 },
624 },
625 },
626 {
627 expr: `sum(foo{job="myjob"}) by(job)`,
628 output: []utils.Source{
629 {
630 Type: utils.AggregateSource,
631 Returns: promParser.ValueTypeVector,
632 Operation: "sum",
633 Selectors: []*promParser.VectorSelector{
634 mustParseVector(`foo{job="myjob"}`, 4),
635 },
636 IncludedLabels: []string{"job"},
637 GuaranteedLabels: []string{"job"},
638 FixedLabels: true,
639 ExcludeReason: map[string]utils.ExcludedLabel{
640 "": {
641 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
642 Fragment: `sum(foo{job="myjob"}) by(job)`,
643 },
644 },
645 },
646 },
647 },
648 {
649 expr: `abs(foo{job="myjob"} or bar{cluster="dev"})`,
650 output: []utils.Source{
651 {
652 Type: utils.FuncSource,
653 Returns: promParser.ValueTypeVector,
654 Operation: "abs",
655 Selectors: []*promParser.VectorSelector{
656 mustParseVector(`foo{job="myjob"}`, 4),
657 mustParseVector(`bar{cluster="dev"}`, 24),
658 },
659 Call: &promParser.Call{
660 Func: &promParser.Function{
661 Name: "abs",
662 ArgTypes: []promParser.ValueType{
663 promParser.ValueTypeVector,
664 },
665 Variadic: 0,
666 ReturnType: promParser.ValueTypeVector,
667 },
668 Args: promParser.Expressions{
669 &promParser.BinaryExpr{
670 Op: promParser.LOR,
671 LHS: mustParseVector(`foo{job="myjob"}`, 4),
672 RHS: mustParseVector(`bar{cluster="dev"}`, 24),
673 VectorMatching: &promParser.VectorMatching{
674 Card: promParser.CardManyToMany,
675 },
676 },
677 },
678 PosRange: posrange.PositionRange{
679 Start: 0,
680 End: 43,
681 },
682 },
683 },
684 },
685 },
686 {
687 expr: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
688 output: []utils.Source{
689 {
690 Type: utils.AggregateSource,
691 Returns: promParser.ValueTypeVector,
692 Operation: "sum",
693 Selectors: []*promParser.VectorSelector{
694 mustParseVector(`foo{job="myjob"}`, 4),
695 },
696 GuaranteedLabels: []string{"job"},
697 ExcludedLabels: []string{"instance"},
698 ExcludeReason: map[string]utils.ExcludedLabel{
699 "instance": {
700 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
701 Fragment: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
702 },
703 },
704 },
705 {
706 Type: utils.AggregateSource,
707 Returns: promParser.ValueTypeVector,
708 Operation: "sum",
709 Selectors: []*promParser.VectorSelector{
710 mustParseVector(`bar{cluster="dev"}`, 24),
711 },
712 GuaranteedLabels: []string{"cluster"},
713 ExcludedLabels: []string{"instance"},
714 ExcludeReason: map[string]utils.ExcludedLabel{
715 "instance": {
716 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
717 Fragment: `sum(foo{job="myjob"} or bar{cluster="dev"}) without(instance)`,
718 },
719 },
720 },
721 },
722 },
723 {
724 expr: `sum(foo{job="myjob"}) without(instance)`,
725 output: []utils.Source{
726 {
727 Type: utils.AggregateSource,
728 Returns: promParser.ValueTypeVector,
729 Operation: "sum",
730 Selectors: []*promParser.VectorSelector{
731 mustParseVector(`foo{job="myjob"}`, 4),
732 },
733 GuaranteedLabels: []string{"job"},
734 ExcludedLabels: []string{"instance"},
735 ExcludeReason: map[string]utils.ExcludedLabel{
736 "instance": {
737 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
738 Fragment: `sum(foo{job="myjob"}) without(instance)`,
739 },
740 },
741 },
742 },
743 },
744 {
745 expr: `min(foo{job="myjob"}) / max(foo{job="myjob"})`,
746 output: []utils.Source{
747 {
748 Type: utils.AggregateSource,
749 Returns: promParser.ValueTypeVector,
750 Operation: "min",
751 Selectors: []*promParser.VectorSelector{
752 mustParseVector(`foo{job="myjob"}`, 4),
753 },
754 FixedLabels: true,
755 ExcludeReason: map[string]utils.ExcludedLabel{
756 "": {
757 Reason: "Query is using aggregation that removes all labels.",
758 Fragment: `min(foo{job="myjob"})`,
759 },
760 },
761 },
762 },
763 },
764 {
765 expr: `max(foo{job="myjob"}) / min(foo{job="myjob"})`,
766 output: []utils.Source{
767 {
768 Type: utils.AggregateSource,
769 Returns: promParser.ValueTypeVector,
770 Operation: "max",
771 Selectors: []*promParser.VectorSelector{
772 mustParseVector(`foo{job="myjob"}`, 4),
773 },
774 FixedLabels: true,
775 ExcludeReason: map[string]utils.ExcludedLabel{
776 "": {
777 Reason: "Query is using aggregation that removes all labels.",
778 Fragment: `max(foo{job="myjob"})`,
779 },
780 },
781 },
782 },
783 },
784 {
785 expr: `avg(foo{job="myjob"}) by(job)`,
786 output: []utils.Source{
787 {
788 Type: utils.AggregateSource,
789 Returns: promParser.ValueTypeVector,
790 Operation: "avg",
791 Selectors: []*promParser.VectorSelector{
792 mustParseVector(`foo{job="myjob"}`, 4),
793 },
794 GuaranteedLabels: []string{"job"},
795 IncludedLabels: []string{"job"},
796 FixedLabels: true,
797 ExcludeReason: map[string]utils.ExcludedLabel{
798 "": {
799 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
800 Fragment: `avg(foo{job="myjob"}) by(job)`,
801 },
802 },
803 },
804 },
805 },
806 {
807 expr: `group(foo) by(job)`,
808 output: []utils.Source{
809 {
810 Type: utils.AggregateSource,
811 Returns: promParser.ValueTypeVector,
812 Operation: "group",
813 Selectors: []*promParser.VectorSelector{
814 mustParseVector(`foo`, 6),
815 },
816 IncludedLabels: []string{"job"},
817 FixedLabels: true,
818 ExcludeReason: map[string]utils.ExcludedLabel{
819 "": {
820 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
821 Fragment: `group(foo) by(job)`,
822 },
823 },
824 },
825 },
826 },
827 {
828 expr: `stddev(rate(foo[5m]))`,
829 output: []utils.Source{
830 {
831 Type: utils.AggregateSource,
832 Returns: promParser.ValueTypeVector,
833 Operation: "stddev",
834 Selectors: []*promParser.VectorSelector{
835 mustParseVector(`foo`, 12),
836 },
837 FixedLabels: true,
838 ExcludeReason: map[string]utils.ExcludedLabel{
839 "": {
840 Reason: "Query is using aggregation that removes all labels.",
841 Fragment: `stddev(rate(foo[5m]))`,
842 },
843 },
844 },
845 },
846 },
847 {
848 expr: `stdvar(rate(foo[5m]))`,
849 output: []utils.Source{
850 {
851 Type: utils.AggregateSource,
852 Returns: promParser.ValueTypeVector,
853 Operation: "stdvar",
854 Selectors: []*promParser.VectorSelector{
855 mustParseVector(`foo`, 12),
856 },
857 FixedLabels: true,
858 ExcludeReason: map[string]utils.ExcludedLabel{
859 "": {
860 Reason: "Query is using aggregation that removes all labels.",
861 Fragment: `stdvar(rate(foo[5m]))`,
862 },
863 },
864 },
865 },
866 },
867 {
868 expr: `stddev_over_time(foo[5m])`,
869 output: []utils.Source{
870 {
871 Type: utils.FuncSource,
872 Returns: promParser.ValueTypeVector,
873 Operation: "stddev_over_time",
874 Selectors: []*promParser.VectorSelector{
875 mustParseVector(`foo`, 17),
876 },
877 Call: &promParser.Call{
878 Func: &promParser.Function{
879 Name: "stddev_over_time",
880 ArgTypes: []promParser.ValueType{
881 promParser.ValueTypeMatrix,
882 },
883 Variadic: 0,
884 ReturnType: promParser.ValueTypeVector,
885 },
886 Args: promParser.Expressions{
887 mustParseMatrix(`foo[5m]`, 17),
888 },
889 PosRange: posrange.PositionRange{
890 Start: 0,
891 End: 25,
892 },
893 },
894 },
895 },
896 },
897 {
898 expr: `stdvar_over_time(foo[5m])`,
899 output: []utils.Source{
900 {
901 Type: utils.FuncSource,
902 Returns: promParser.ValueTypeVector,
903 Operation: "stdvar_over_time",
904 Selectors: []*promParser.VectorSelector{
905 mustParseVector(`foo`, 17),
906 },
907 Call: &promParser.Call{
908 Func: &promParser.Function{
909 Name: "stdvar_over_time",
910 ArgTypes: []promParser.ValueType{
911 promParser.ValueTypeMatrix,
912 },
913 Variadic: 0,
914 ReturnType: promParser.ValueTypeVector,
915 },
916 Args: promParser.Expressions{
917 mustParseMatrix(`foo[5m]`, 17),
918 },
919 PosRange: posrange.PositionRange{
920 Start: 0,
921 End: 25,
922 },
923 },
924 },
925 },
926 },
927 {
928 expr: `quantile(0.9, rate(foo[5m]))`,
929 output: []utils.Source{
930 {
931 Type: utils.AggregateSource,
932 Returns: promParser.ValueTypeVector,
933 Operation: "quantile",
934 Selectors: []*promParser.VectorSelector{
935 mustParseVector(`foo`, 19),
936 },
937 FixedLabels: true,
938 ExcludeReason: map[string]utils.ExcludedLabel{
939 "": {
940 Reason: "Query is using aggregation that removes all labels.",
941 Fragment: `quantile(0.9, rate(foo[5m]))`,
942 },
943 },
944 },
945 },
946 },
947 {
948 expr: `count_values("version", build_version)`,
949 output: []utils.Source{
950 {
951 Type: utils.AggregateSource,
952 Returns: promParser.ValueTypeVector,
953 Operation: "count_values",
954 Selectors: []*promParser.VectorSelector{
955 mustParseVector(`build_version`, 24),
956 },
957 GuaranteedLabels: []string{"version"},
958 IncludedLabels: []string{"version"},
959 FixedLabels: true,
960 ExcludeReason: map[string]utils.ExcludedLabel{
961 "": {
962 Reason: "Query is using aggregation that removes all labels.",
963 Fragment: `count_values("version", build_version)`,
964 },
965 },
966 },
967 },
968 },
969 {
970 expr: `count_values("version", build_version) without(job)`,
971 output: []utils.Source{
972 {
973 Type: utils.AggregateSource,
974 Returns: promParser.ValueTypeVector,
975 Operation: "count_values",
976 Selectors: []*promParser.VectorSelector{
977 mustParseVector(`build_version`, 24),
978 },
979 IncludedLabels: []string{"version"},
980 GuaranteedLabels: []string{"version"},
981 ExcludedLabels: []string{"job"},
982 ExcludeReason: map[string]utils.ExcludedLabel{
983 "job": {
984 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
985 Fragment: `count_values("version", build_version) without(job)`,
986 },
987 },
988 },
989 },
990 },
991 {
992 expr: `count_values("version", build_version{job="foo"}) without(job)`,
993 output: []utils.Source{
994 {
995 Type: utils.AggregateSource,
996 Returns: promParser.ValueTypeVector,
997 Operation: "count_values",
998 Selectors: []*promParser.VectorSelector{
999 mustParseVector(`build_version{job="foo"}`, 24),
1000 },
1001 IncludedLabels: []string{"version"},
1002 GuaranteedLabels: []string{"version"},
1003 ExcludedLabels: []string{"job"},
1004 ExcludeReason: map[string]utils.ExcludedLabel{
1005 "job": {
1006 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
1007 Fragment: `count_values("version", build_version{job="foo"}) without(job)`,
1008 },
1009 },
1010 },
1011 },
1012 },
1013 {
1014 expr: `count_values("version", build_version) by(job)`,
1015 output: []utils.Source{
1016 {
1017 Type: utils.AggregateSource,
1018 Returns: promParser.ValueTypeVector,
1019 Operation: "count_values",
1020 Selectors: []*promParser.VectorSelector{
1021 mustParseVector(`build_version`, 24),
1022 },
1023 GuaranteedLabels: []string{"version"},
1024 IncludedLabels: []string{"job", "version"},
1025 FixedLabels: true,
1026 ExcludeReason: map[string]utils.ExcludedLabel{
1027 "": {
1028 Reason: "Query is using aggregation with `by(job)`, only labels included inside `by(...)` will be present on the results.",
1029 Fragment: `count_values("version", build_version) by(job)`,
1030 },
1031 },
1032 },
1033 },
1034 },
1035 {
1036 expr: `topk(10, foo{job="myjob"}) > 10`,
1037 output: []utils.Source{
1038 {
1039 Type: utils.AggregateSource,
1040 Returns: promParser.ValueTypeVector,
1041 Operation: "topk",
1042 Selectors: []*promParser.VectorSelector{
1043 mustParseVector(`foo{job="myjob"}`, 9),
1044 },
1045 GuaranteedLabels: []string{"job"},
1046 },
1047 },
1048 },
1049 {
1050 expr: `topk(10, foo or bar)`,
1051 output: []utils.Source{
1052 {
1053 Type: utils.AggregateSource,
1054 Returns: promParser.ValueTypeVector,
1055 Operation: "topk",
1056 Selectors: []*promParser.VectorSelector{
1057 mustParseVector(`foo`, 9),
1058 },
1059 },
1060 {
1061 Type: utils.AggregateSource,
1062 Operation: "topk",
1063 Returns: promParser.ValueTypeVector,
1064 Selectors: []*promParser.VectorSelector{
1065 mustParseVector(`bar`, 16),
1066 },
1067 },
1068 },
1069 },
1070 {
1071 expr: `rate(foo[10m])`,
1072 output: []utils.Source{
1073 {
1074 Type: utils.FuncSource,
1075 Returns: promParser.ValueTypeVector,
1076 Operation: "rate",
1077 Selectors: []*promParser.VectorSelector{
1078 mustParseVector(`foo`, 5),
1079 },
1080 Call: &promParser.Call{
1081 Func: &promParser.Function{
1082 Name: "rate",
1083 ArgTypes: []promParser.ValueType{
1084 promParser.ValueTypeMatrix,
1085 },
1086 Variadic: 0,
1087 ReturnType: promParser.ValueTypeVector,
1088 },
1089 Args: promParser.Expressions{
1090 mustParseMatrix(`foo[10m]`, 5),
1091 },
1092 PosRange: posrange.PositionRange{
1093 Start: 0,
1094 End: 14,
1095 },
1096 },
1097 },
1098 },
1099 },
1100 {
1101 expr: `sum(rate(foo[10m])) without(instance)`,
1102 output: []utils.Source{
1103 {
1104 Type: utils.AggregateSource,
1105 Returns: promParser.ValueTypeVector,
1106 Operation: "sum",
1107 Selectors: []*promParser.VectorSelector{
1108 mustParseVector(`foo`, 9),
1109 },
1110 ExcludedLabels: []string{"instance"},
1111 ExcludeReason: map[string]utils.ExcludedLabel{
1112 "instance": {
1113 Reason: "Query is using aggregation with `without(instance)`, all labels included inside `without(...)` will be removed from the results.",
1114 Fragment: `sum(rate(foo[10m])) without(instance)`,
1115 },
1116 },
1117 },
1118 },
1119 },
1120 {
1121 expr: `foo{job="foo"} / bar`,
1122 output: []utils.Source{
1123 {
1124 Type: utils.SelectorSource,
1125 Returns: promParser.ValueTypeVector,
1126 Operation: promParser.CardOneToOne.String(),
1127 Selectors: []*promParser.VectorSelector{
1128 mustParseVector(`foo{job="foo"}`, 0),
1129 },
1130 GuaranteedLabels: []string{"job"},
1131 },
1132 },
1133 },
1134 {
1135 expr: `foo{job="foo"} * on(instance) bar`,
1136 output: []utils.Source{
1137 {
1138 Type: utils.SelectorSource,
1139 Returns: promParser.ValueTypeVector,
1140 Operation: promParser.CardOneToOne.String(),
1141 Selectors: []*promParser.VectorSelector{
1142 mustParseVector(`foo{job="foo"}`, 0),
1143 },
1144 GuaranteedLabels: []string{"job"},
1145 IncludedLabels: []string{"instance"},
1146 FixedLabels: true,
1147 ExcludeReason: map[string]utils.ExcludedLabel{
1148 "": {
1149 Reason: "Query is using one-to-one vector matching with `on(instance)`, only labels included inside `on(...)` will be present on the results.",
1150 Fragment: `foo{job="foo"} * on(instance) bar`,
1151 },
1152 },
1153 },
1154 },
1155 },
1156 {
1157 expr: `foo{job="foo"} * on(instance) group_left(bar) bar`,
1158 output: []utils.Source{
1159 {
1160 Type: utils.SelectorSource,
1161 Returns: promParser.ValueTypeVector,
1162 Operation: promParser.CardManyToOne.String(),
1163 Selectors: []*promParser.VectorSelector{
1164 mustParseVector(`foo{job="foo"}`, 0),
1165 },
1166 IncludedLabels: []string{"bar", "instance"},
1167 GuaranteedLabels: []string{"job"},
1168 },
1169 },
1170 },
1171 {
1172 expr: `foo{job="foo"} * on(instance) group_left(cluster) bar{cluster="bar", ignored="true"}`,
1173 output: []utils.Source{
1174 {
1175 Type: utils.SelectorSource,
1176 Returns: promParser.ValueTypeVector,
1177 Operation: promParser.CardManyToOne.String(),
1178 Selectors: []*promParser.VectorSelector{
1179 mustParseVector(`foo{job="foo"}`, 0),
1180 },
1181 IncludedLabels: []string{"cluster", "instance"},
1182 GuaranteedLabels: []string{"job"},
1183 },
1184 },
1185 },
1186 {
1187 expr: `foo{job="foo", ignored="true"} * on(instance) group_right(job) bar{cluster="bar"}`,
1188 output: []utils.Source{
1189 {
1190 Type: utils.SelectorSource,
1191 Returns: promParser.ValueTypeVector,
1192 Operation: promParser.CardOneToMany.String(),
1193 Selectors: []*promParser.VectorSelector{
1194 mustParseVector(`bar{cluster="bar"}`, 63),
1195 },
1196 IncludedLabels: []string{"job", "instance"},
1197 GuaranteedLabels: []string{"cluster"},
1198 },
1199 },
1200 },
1201 {
1202 expr: `count(foo / bar)`,
1203 output: []utils.Source{
1204 {
1205 Type: utils.AggregateSource,
1206 Returns: promParser.ValueTypeVector,
1207 Operation: "count",
1208 Selectors: []*promParser.VectorSelector{
1209 mustParseVector(`foo`, 6),
1210 },
1211 FixedLabels: true,
1212 ExcludeReason: map[string]utils.ExcludedLabel{
1213 "": {
1214 Reason: "Query is using aggregation that removes all labels.",
1215 Fragment: `count(foo / bar)`,
1216 },
1217 },
1218 },
1219 },
1220 },
1221 {
1222 expr: `count(up{job="a"} / on () up{job="b"})`,
1223 output: []utils.Source{
1224 {
1225 Type: utils.AggregateSource,
1226 Returns: promParser.ValueTypeVector,
1227 Operation: "count",
1228 Selectors: []*promParser.VectorSelector{
1229 mustParseVector(`up{job="a"}`, 6),
1230 },
1231 FixedLabels: true,
1232 ExcludeReason: map[string]utils.ExcludedLabel{
1233 "": {
1234 Reason: "Query is using aggregation that removes all labels.",
1235 Fragment: `count(up{job="a"} / on () up{job="b"})`,
1236 },
1237 },
1238 },
1239 },
1240 },
1241 {
1242 expr: `count(up{job="a"} / on (env) up{job="b"})`,
1243 output: []utils.Source{
1244 {
1245 Type: utils.AggregateSource,
1246 Returns: promParser.ValueTypeVector,
1247 Operation: "count",
1248 Selectors: []*promParser.VectorSelector{
1249 mustParseVector(`up{job="a"}`, 6),
1250 },
1251 FixedLabels: true,
1252 ExcludeReason: map[string]utils.ExcludedLabel{
1253 "": {
1254 Reason: "Query is using aggregation that removes all labels.",
1255 Fragment: `count(up{job="a"} / on (env) up{job="b"})`,
1256 },
1257 },
1258 },
1259 },
1260 },
1261 {
1262 expr: `foo{job="foo", instance="1"} and bar`,
1263 output: []utils.Source{
1264 {
1265 Type: utils.SelectorSource,
1266 Returns: promParser.ValueTypeVector,
1267 Operation: promParser.CardManyToMany.String(),
1268 Selectors: []*promParser.VectorSelector{
1269 mustParseVector(`foo{job="foo", instance="1"}`, 0),
1270 },
1271 GuaranteedLabels: []string{"job", "instance"},
1272 },
1273 },
1274 },
1275 {
1276 expr: `foo{job="foo", instance="1"} and on(cluster) bar`,
1277 output: []utils.Source{
1278 {
1279 Type: utils.SelectorSource,
1280 Returns: promParser.ValueTypeVector,
1281 Operation: promParser.CardManyToMany.String(),
1282 Selectors: []*promParser.VectorSelector{
1283 mustParseVector(`foo{job="foo", instance="1"}`, 0),
1284 },
1285 IncludedLabels: []string{"cluster"},
1286 GuaranteedLabels: []string{"job", "instance"},
1287 },
1288 },
1289 },
1290 {
1291 expr: `topk(10, foo)`,
1292 output: []utils.Source{
1293 {
1294 Type: utils.AggregateSource,
1295 Returns: promParser.ValueTypeVector,
1296 Operation: "topk",
1297 Selectors: []*promParser.VectorSelector{
1298 mustParseVector(`foo`, 9),
1299 },
1300 },
1301 },
1302 },
1303 {
1304 expr: `topk(10, foo) without(cluster)`,
1305 output: []utils.Source{
1306 {
1307 Type: utils.AggregateSource,
1308 Returns: promParser.ValueTypeVector,
1309 Operation: "topk",
1310 Selectors: []*promParser.VectorSelector{
1311 mustParseVector(`foo`, 9),
1312 },
1313 },
1314 },
1315 },
1316 {
1317 expr: `topk(10, foo) by(cluster)`,
1318 output: []utils.Source{
1319 {
1320 Type: utils.AggregateSource,
1321 Returns: promParser.ValueTypeVector,
1322 Operation: "topk",
1323 Selectors: []*promParser.VectorSelector{
1324 mustParseVector(`foo`, 9),
1325 },
1326 },
1327 },
1328 },
1329 {
1330 expr: `bottomk(10, sum(rate(foo[5m])) without(job))`,
1331 output: []utils.Source{
1332 {
1333 Type: utils.AggregateSource,
1334 Returns: promParser.ValueTypeVector,
1335 Operation: "bottomk",
1336 Selectors: []*promParser.VectorSelector{
1337 mustParseVector(`foo`, 21),
1338 },
1339 ExcludedLabels: []string{"job"},
1340 ExcludeReason: map[string]utils.ExcludedLabel{
1341 "job": {
1342 Reason: "Query is using aggregation with `without(job)`, all labels included inside `without(...)` will be removed from the results.",
1343 Fragment: `sum(rate(foo[5m])) without(job)`,
1344 },
1345 },
1346 },
1347 },
1348 },
1349 {
1350 expr: `foo or bar`,
1351 output: []utils.Source{
1352 {
1353 Type: utils.SelectorSource,
1354 Returns: promParser.ValueTypeVector,
1355 Operation: promParser.CardManyToMany.String(),
1356 Selectors: []*promParser.VectorSelector{
1357 mustParseVector(`foo`, 0),
1358 },
1359 },
1360 {
1361 Type: utils.SelectorSource,
1362 Returns: promParser.ValueTypeVector,
1363 Operation: promParser.CardManyToMany.String(),
1364 Selectors: []*promParser.VectorSelector{
1365 mustParseVector(`bar`, 7),
1366 },
1367 },
1368 },
1369 },
1370 {
1371 expr: `foo or bar or baz`,
1372 output: []utils.Source{
1373 {
1374 Type: utils.SelectorSource,
1375 Returns: promParser.ValueTypeVector,
1376 Operation: promParser.CardManyToMany.String(),
1377 Selectors: []*promParser.VectorSelector{
1378 mustParseVector(`foo`, 0),
1379 },
1380 },
1381 {
1382 Type: utils.SelectorSource,
1383 Returns: promParser.ValueTypeVector,
1384 Operation: promParser.CardManyToMany.String(),
1385 Selectors: []*promParser.VectorSelector{
1386 mustParseVector(`bar`, 7),
1387 },
1388 },
1389 {
1390 Type: utils.SelectorSource,
1391 Returns: promParser.ValueTypeVector,
1392 Operation: promParser.CardManyToMany.String(),
1393 Selectors: []*promParser.VectorSelector{
1394 mustParseVector(`baz`, 14),
1395 },
1396 },
1397 },
1398 },
1399 {
1400 expr: `(foo or bar) or baz`,
1401 output: []utils.Source{
1402 {
1403 Type: utils.SelectorSource,
1404 Returns: promParser.ValueTypeVector,
1405 Operation: promParser.CardManyToMany.String(),
1406 Selectors: []*promParser.VectorSelector{
1407 mustParseVector(`foo`, 1),
1408 },
1409 },
1410 {
1411 Type: utils.SelectorSource,
1412 Returns: promParser.ValueTypeVector,
1413 Operation: promParser.CardManyToMany.String(),
1414 Selectors: []*promParser.VectorSelector{
1415 mustParseVector(`bar`, 8),
1416 },
1417 },
1418 {
1419 Type: utils.SelectorSource,
1420 Returns: promParser.ValueTypeVector,
1421 Operation: promParser.CardManyToMany.String(),
1422 Selectors: []*promParser.VectorSelector{
1423 mustParseVector(`baz`, 16),
1424 },
1425 },
1426 },
1427 },
1428 {
1429 expr: `foo unless bar`,
1430 output: []utils.Source{
1431 {
1432 Type: utils.SelectorSource,
1433 Returns: promParser.ValueTypeVector,
1434 Operation: promParser.CardManyToMany.String(),
1435 Selectors: []*promParser.VectorSelector{
1436 mustParseVector(`foo`, 0),
1437 },
1438 },
1439 },
1440 },
1441 {
1442 expr: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
1443 output: []utils.Source{
1444 {
1445 Type: utils.AggregateSource,
1446 Returns: promParser.ValueTypeVector,
1447 Operation: "count",
1448 Selectors: []*promParser.VectorSelector{
1449 mustParseVector(`up{job="foo", cluster="dev"}`, 10),
1450 },
1451 ExcludedLabels: []string{"job", "cluster"}, // FIXME empty
1452 FixedLabels: true,
1453 ExcludeReason: map[string]utils.ExcludedLabel{
1454 "": {
1455 Reason: "Query is using aggregation with `by(job, cluster)`, only labels included inside `by(...)` will be present on the results.",
1456 Fragment: `sum(up{job="foo", cluster="dev"}) by(job, cluster)`,
1457 },
1458 "job": {
1459 Reason: "Query is using aggregation with `without(job, cluster)`, all labels included inside `without(...)` will be removed from the results.",
1460 Fragment: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
1461 },
1462 "cluster": {
1463 Reason: "Query is using aggregation with `without(job, cluster)`, all labels included inside `without(...)` will be removed from the results.",
1464 Fragment: `count(sum(up{job="foo", cluster="dev"}) by(job, cluster) == 0) without(job, cluster)`,
1465 },
1466 },
1467 },
1468 },
1469 },
1470 {
1471 expr: "year()",
1472 output: []utils.Source{
1473 {
1474 Type: utils.FuncSource,
1475 Returns: promParser.ValueTypeVector,
1476 Operation: "year",
1477 FixedLabels: true,
1478 AlwaysReturns: true,
1479 ExcludeReason: map[string]utils.ExcludedLabel{
1480 "": {
1481 Reason: "Calling `year()` with no arguments will return an empty time series with no labels.",
1482 Fragment: `year()`,
1483 },
1484 },
1485 Call: &promParser.Call{
1486 Func: &promParser.Function{
1487 Name: "year",
1488 ArgTypes: []promParser.ValueType{
1489 promParser.ValueTypeVector,
1490 },
1491 Variadic: 1,
1492 ReturnType: promParser.ValueTypeVector,
1493 },
1494 Args: promParser.Expressions{},
1495 PosRange: posrange.PositionRange{
1496 Start: 0,
1497 End: 6,
1498 },
1499 },
1500 },
1501 },
1502 },
1503 {
1504 expr: "year(foo)",
1505 output: []utils.Source{
1506 {
1507 Type: utils.FuncSource,
1508 Returns: promParser.ValueTypeVector,
1509 Operation: "year",
1510 Selectors: []*promParser.VectorSelector{
1511 mustParseVector("foo", 5),
1512 },
1513 Call: &promParser.Call{
1514 Func: &promParser.Function{
1515 Name: "year",
1516 ArgTypes: []promParser.ValueType{
1517 promParser.ValueTypeVector,
1518 },
1519 Variadic: 1,
1520 ReturnType: promParser.ValueTypeVector,
1521 },
1522 Args: promParser.Expressions{
1523 mustParseVector("foo", 5),
1524 },
1525 PosRange: posrange.PositionRange{
1526 Start: 0,
1527 End: 9,
1528 },
1529 },
1530 },
1531 },
1532 },
1533 {
1534 expr: `label_join(up{job="api-server",src1="a",src2="b",src3="c"}, "foo", ",", "src1", "src2", "src3")`,
1535 output: []utils.Source{
1536 {
1537 Type: utils.FuncSource,
1538 Returns: promParser.ValueTypeVector,
1539 Operation: "label_join",
1540 Selectors: []*promParser.VectorSelector{
1541 mustParseVector(`up{job="api-server",src1="a",src2="b",src3="c"}`, 11),
1542 },
1543 GuaranteedLabels: []string{"job", "src1", "src2", "src3", "foo"},
1544 Call: &promParser.Call{
1545 Func: &promParser.Function{
1546 Name: "label_join",
1547 ArgTypes: []promParser.ValueType{
1548 promParser.ValueTypeVector,
1549 promParser.ValueTypeString,
1550 promParser.ValueTypeString,
1551 promParser.ValueTypeString,
1552 },
1553 Variadic: -1,
1554 ReturnType: promParser.ValueTypeVector,
1555 },
1556 Args: promParser.Expressions{
1557 mustParseVector(`up{job="api-server",src1="a",src2="b",src3="c"}`, 11),
1558 &promParser.StringLiteral{
1559 Val: "foo",
1560 PosRange: posrange.PositionRange{Start: 60, End: 65},
1561 },
1562 &promParser.StringLiteral{
1563 Val: ",",
1564 PosRange: posrange.PositionRange{Start: 67, End: 70},
1565 },
1566 &promParser.StringLiteral{
1567 Val: "src1",
1568 PosRange: posrange.PositionRange{Start: 72, End: 78},
1569 },
1570 &promParser.StringLiteral{
1571 Val: "src2",
1572 PosRange: posrange.PositionRange{Start: 80, End: 86},
1573 },
1574 &promParser.StringLiteral{
1575 Val: "src3",
1576 PosRange: posrange.PositionRange{Start: 88, End: 94},
1577 },
1578 },
1579 PosRange: posrange.PositionRange{
1580 Start: 0,
1581 End: 95,
1582 },
1583 },
1584 },
1585 },
1586 },
1587 {
1588 expr: `
1589(
1590 sum(foo:sum > 0) without(notify)
1591 * on(job) group_left(notify)
1592 job:notify
1593)
1594and on(job)
1595sum(foo:count) by(job) > 20`,
1596 output: []utils.Source{
1597 {
1598 Type: utils.AggregateSource,
1599 Returns: promParser.ValueTypeVector,
1600 Operation: "sum",
1601 Selectors: []*promParser.VectorSelector{
1602 mustParseVector(`foo:sum`, 8),
1603 },
1604 IncludedLabels: []string{"notify", "job"},
1605 ExcludeReason: map[string]utils.ExcludedLabel{},
1606 },
1607 },
1608 },
1609 {
1610 expr: `container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`,
1611 output: []utils.Source{
1612 {
1613 Type: utils.SelectorSource,
1614 Returns: promParser.ValueTypeVector,
1615 Operation: promParser.CardOneToOne.String(),
1616 Selectors: []*promParser.VectorSelector{
1617 mustParseVector(`container_file_descriptors`, 0),
1618 },
1619 IncludedLabels: []string{"instance", "app_name"},
1620 FixedLabels: true,
1621 ExcludeReason: map[string]utils.ExcludedLabel{
1622 "": {
1623 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.",
1624 Fragment: `container_file_descriptors / on (instance, app_name) container_ulimits_soft{ulimit="max_open_files"}`,
1625 },
1626 },
1627 },
1628 },
1629 },
1630 {
1631 expr: `container_file_descriptors / on (instance, app_name) group_left() container_ulimits_soft{ulimit="max_open_files"}`,
1632 output: []utils.Source{
1633 {
1634 Type: utils.SelectorSource,
1635 Returns: promParser.ValueTypeVector,
1636 Operation: promParser.CardManyToOne.String(),
1637 Selectors: []*promParser.VectorSelector{
1638 mustParseVector(`container_file_descriptors`, 0),
1639 },
1640 IncludedLabels: []string{"instance", "app_name"},
1641 },
1642 },
1643 },
1644 {
1645 expr: `absent(foo{job="bar"})`,
1646 output: []utils.Source{
1647 {
1648 Type: utils.FuncSource,
1649 Returns: promParser.ValueTypeVector,
1650 Operation: "absent",
1651 Selectors: []*promParser.VectorSelector{
1652 mustParseVector(`foo{job="bar"}`, 7),
1653 },
1654 IncludedLabels: []string{"job"},
1655 GuaranteedLabels: []string{"job"},
1656 FixedLabels: true,
1657 ExcludeReason: map[string]utils.ExcludedLabel{
1658 "": {
1659 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.",
1660 Fragment: `absent(foo{job="bar"})`,
1661 },
1662 },
1663 Call: &promParser.Call{
1664 Func: &promParser.Function{
1665 Name: "absent",
1666 ArgTypes: []promParser.ValueType{
1667 promParser.ValueTypeVector,
1668 },
1669 Variadic: 0,
1670 ReturnType: promParser.ValueTypeVector,
1671 },
1672 Args: promParser.Expressions{
1673 mustParseVector(`foo{job="bar"}`, 7),
1674 },
1675 PosRange: posrange.PositionRange{
1676 Start: 0,
1677 End: 22,
1678 },
1679 },
1680 },
1681 },
1682 },
1683 {
1684 expr: `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`,
1685 output: []utils.Source{
1686 {
1687 Type: utils.FuncSource,
1688 Returns: promParser.ValueTypeVector,
1689 Operation: "absent",
1690 Selectors: []*promParser.VectorSelector{
1691 mustParseVector(`foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7),
1692 },
1693 IncludedLabels: []string{"job", "env"},
1694 GuaranteedLabels: []string{"job", "env"},
1695 FixedLabels: true,
1696 ExcludeReason: map[string]utils.ExcludedLabel{
1697 "": {
1698 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.",
1699 Fragment: `absent(foo{job="bar", cluster!="dev", instance=~".+", env="prod"})`,
1700 },
1701 },
1702 Call: &promParser.Call{
1703 Func: &promParser.Function{
1704 Name: "absent",
1705 ArgTypes: []promParser.ValueType{
1706 promParser.ValueTypeVector,
1707 },
1708 Variadic: 0,
1709 ReturnType: promParser.ValueTypeVector,
1710 },
1711 Args: promParser.Expressions{
1712 mustParseVector(`foo{job="bar", cluster!="dev", instance=~".+", env="prod"}`, 7),
1713 },
1714 PosRange: posrange.PositionRange{
1715 Start: 0,
1716 End: 66,
1717 },
1718 },
1719 },
1720 },
1721 },
1722 {
1723 expr: `absent(sum(foo) by(job, instance))`,
1724 output: []utils.Source{
1725 {
1726 Type: utils.FuncSource,
1727 Returns: promParser.ValueTypeVector,
1728 Operation: "absent",
1729 Selectors: []*promParser.VectorSelector{
1730 mustParseVector(`foo`, 11),
1731 },
1732 FixedLabels: true,
1733 ExcludeReason: map[string]utils.ExcludedLabel{
1734 "": {
1735 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.",
1736 Fragment: `absent(sum(foo) by(job, instance))`,
1737 },
1738 },
1739 Call: &promParser.Call{
1740 Func: &promParser.Function{
1741 Name: "absent",
1742 ArgTypes: []promParser.ValueType{
1743 promParser.ValueTypeVector,
1744 },
1745 Variadic: 0,
1746 ReturnType: promParser.ValueTypeVector,
1747 },
1748 Args: promParser.Expressions{
1749 &promParser.AggregateExpr{
1750 Op: promParser.SUM,
1751 Expr: mustParseVector("foo", 11),
1752 Grouping: []string{"job", "instance"},
1753 PosRange: posrange.PositionRange{
1754 Start: 7,
1755 End: 33,
1756 },
1757 },
1758 },
1759 PosRange: posrange.PositionRange{
1760 Start: 0,
1761 End: 34,
1762 },
1763 },
1764 },
1765 },
1766 },
1767 {
1768 expr: `absent(foo{job="prometheus", xxx="1"}) AND on(job) prometheus_build_info`,
1769 output: []utils.Source{
1770 {
1771 Type: utils.FuncSource,
1772 Returns: promParser.ValueTypeVector,
1773 Operation: "absent",
1774 Selectors: []*promParser.VectorSelector{
1775 mustParseVector(`foo{job="prometheus", xxx="1"}`, 7),
1776 },
1777 IncludedLabels: []string{"job", "xxx"},
1778 GuaranteedLabels: []string{"job", "xxx"},
1779 FixedLabels: true,
1780 ExcludeReason: map[string]utils.ExcludedLabel{
1781 "": {
1782 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.",
1783 Fragment: `absent(foo{job="prometheus", xxx="1"})`,
1784 },
1785 },
1786 Call: &promParser.Call{
1787 Func: &promParser.Function{
1788 Name: "absent",
1789 ArgTypes: []promParser.ValueType{
1790 promParser.ValueTypeVector,
1791 },
1792 Variadic: 0,
1793 ReturnType: promParser.ValueTypeVector,
1794 },
1795 Args: promParser.Expressions{
1796 mustParseVector(`foo{job="prometheus", xxx="1"}`, 7),
1797 },
1798 PosRange: posrange.PositionRange{
1799 Start: 0,
1800 End: 38,
1801 },
1802 },
1803 },
1804 },
1805 },
1806 {
1807 expr: `1 + sum(foo) by(notjob)`,
1808 output: []utils.Source{
1809 {
1810 Type: utils.AggregateSource,
1811 Returns: promParser.ValueTypeVector,
1812 Operation: "sum",
1813 Selectors: []*promParser.VectorSelector{
1814 mustParseVector(`foo`, 8),
1815 },
1816 IncludedLabels: []string{"notjob"},
1817 FixedLabels: true,
1818 ExcludeReason: map[string]utils.ExcludedLabel{
1819 "": {
1820 Reason: "Query is using aggregation with `by(notjob)`, only labels included inside `by(...)` will be present on the results.",
1821 Fragment: `sum(foo) by(notjob)`,
1822 },
1823 },
1824 },
1825 },
1826 },
1827 {
1828 expr: `count(node_exporter_build_info) by (instance, version) != ignoring(package,version) group_left(foo) count(deb_package_version) by (instance, version, package)`,
1829 output: []utils.Source{
1830 {
1831 Type: utils.AggregateSource,
1832 Returns: promParser.ValueTypeVector,
1833 Operation: "count",
1834 Selectors: []*promParser.VectorSelector{
1835 mustParseVector(`node_exporter_build_info`, 6),
1836 },
1837 IncludedLabels: []string{"instance", "version", "foo"}, // FIXME foo shouldn't be there because count() doesn't produce it
1838 FixedLabels: true,
1839 ExcludeReason: map[string]utils.ExcludedLabel{
1840 "": {
1841 Reason: "Query is using aggregation with `by(instance, version)`, only labels included inside `by(...)` will be present on the results.",
1842 Fragment: `count(node_exporter_build_info) by (instance, version)`,
1843 },
1844 },
1845 },
1846 },
1847 },
1848 {
1849 expr: `absent(foo) or absent(bar)`,
1850 output: []utils.Source{
1851 {
1852 Type: utils.FuncSource,
1853 Returns: promParser.ValueTypeVector,
1854 Operation: "absent",
1855 Selectors: []*promParser.VectorSelector{
1856 mustParseVector(`foo`, 7),
1857 },
1858 FixedLabels: true,
1859 ExcludeReason: map[string]utils.ExcludedLabel{
1860 "": {
1861 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.",
1862 Fragment: `absent(foo)`,
1863 },
1864 },
1865 Call: &promParser.Call{
1866 Func: &promParser.Function{
1867 Name: "absent",
1868 ArgTypes: []promParser.ValueType{
1869 promParser.ValueTypeVector,
1870 },
1871 Variadic: 0,
1872 ReturnType: promParser.ValueTypeVector,
1873 },
1874 Args: promParser.Expressions{
1875 mustParseVector(`foo`, 7),
1876 },
1877 PosRange: posrange.PositionRange{
1878 Start: 0,
1879 End: 11,
1880 },
1881 },
1882 },
1883 {
1884 Type: utils.FuncSource,
1885 Returns: promParser.ValueTypeVector,
1886 Operation: "absent",
1887 Selectors: []*promParser.VectorSelector{
1888 mustParseVector(`bar`, 22),
1889 },
1890 FixedLabels: true,
1891 ExcludeReason: map[string]utils.ExcludedLabel{
1892 "": {
1893 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.",
1894 Fragment: `absent(bar)`,
1895 },
1896 },
1897 Call: &promParser.Call{
1898 Func: &promParser.Function{
1899 Name: "absent",
1900 ArgTypes: []promParser.ValueType{
1901 promParser.ValueTypeVector,
1902 },
1903 Variadic: 0,
1904 ReturnType: promParser.ValueTypeVector,
1905 },
1906 Args: promParser.Expressions{
1907 mustParseVector(`bar`, 22),
1908 },
1909 PosRange: posrange.PositionRange{
1910 Start: 15,
1911 End: 26,
1912 },
1913 },
1914 },
1915 },
1916 },
1917 {
1918 expr: `absent_over_time(foo[5m]) or absent(bar)`,
1919 output: []utils.Source{
1920 {
1921 Type: utils.FuncSource,
1922 Returns: promParser.ValueTypeVector,
1923 Operation: "absent_over_time",
1924 Selectors: []*promParser.VectorSelector{
1925 mustParseVector(`foo`, 17),
1926 },
1927 FixedLabels: true,
1928 ExcludeReason: map[string]utils.ExcludedLabel{
1929 "": {
1930 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.",
1931 Fragment: `absent_over_time(foo[5m])`,
1932 },
1933 },
1934 Call: &promParser.Call{
1935 Func: &promParser.Function{
1936 Name: "absent_over_time",
1937 ArgTypes: []promParser.ValueType{
1938 promParser.ValueTypeMatrix,
1939 },
1940 Variadic: 0,
1941 ReturnType: promParser.ValueTypeVector,
1942 },
1943 Args: promParser.Expressions{
1944 mustParseMatrix(`foo[5m]`, 17),
1945 },
1946 PosRange: posrange.PositionRange{
1947 Start: 0,
1948 End: 25,
1949 },
1950 },
1951 },
1952 {
1953 Type: utils.FuncSource,
1954 Returns: promParser.ValueTypeVector,
1955 Operation: "absent",
1956 Selectors: []*promParser.VectorSelector{
1957 mustParseVector(`bar`, 36),
1958 },
1959 FixedLabels: true,
1960 ExcludeReason: map[string]utils.ExcludedLabel{
1961 "": {
1962 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.",
1963 Fragment: `absent(bar)`,
1964 },
1965 },
1966 Call: &promParser.Call{
1967 Func: &promParser.Function{
1968 Name: "absent",
1969 ArgTypes: []promParser.ValueType{
1970 promParser.ValueTypeVector,
1971 },
1972 Variadic: 0,
1973 ReturnType: promParser.ValueTypeVector,
1974 },
1975 Args: promParser.Expressions{
1976 mustParseVector(`bar`, 36),
1977 },
1978 PosRange: posrange.PositionRange{
1979 Start: 29,
1980 End: 40,
1981 },
1982 },
1983 },
1984 },
1985 },
1986 {
1987 expr: `bar * on() group_right(cluster, env) absent(foo{job="xxx"})`,
1988 output: []utils.Source{
1989 {
1990 Type: utils.FuncSource,
1991 Returns: promParser.ValueTypeVector,
1992 Operation: "absent",
1993 Selectors: []*promParser.VectorSelector{
1994 mustParseVector(`foo{job="xxx"}`, 44),
1995 },
1996 IncludedLabels: []string{"job", "cluster", "env"},
1997 GuaranteedLabels: []string{"job"},
1998 FixedLabels: true,
1999 ExcludeReason: map[string]utils.ExcludedLabel{
2000 "": {
2001 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.",
2002 Fragment: `absent(foo{job="xxx"})`,
2003 },
2004 },
2005 Call: &promParser.Call{
2006 Func: &promParser.Function{
2007 Name: "absent",
2008 ArgTypes: []promParser.ValueType{
2009 promParser.ValueTypeVector,
2010 },
2011 Variadic: 0,
2012 ReturnType: promParser.ValueTypeVector,
2013 },
2014 Args: promParser.Expressions{
2015 mustParseVector(`foo{job="xxx"}`, 44),
2016 },
2017 PosRange: posrange.PositionRange{
2018 Start: 37,
2019 End: 59,
2020 },
2021 },
2022 },
2023 },
2024 },
2025 {
2026 expr: `bar * on() group_right() absent(foo{job="xxx"})`,
2027 output: []utils.Source{
2028 {
2029 Type: utils.FuncSource,
2030 Returns: promParser.ValueTypeVector,
2031 Operation: "absent",
2032 Selectors: []*promParser.VectorSelector{
2033 mustParseVector(`foo{job="xxx"}`, 32),
2034 },
2035 IncludedLabels: []string{"job"},
2036 GuaranteedLabels: []string{"job"},
2037 FixedLabels: true,
2038 ExcludeReason: map[string]utils.ExcludedLabel{
2039 "": {
2040 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.",
2041 Fragment: `absent(foo{job="xxx"})`,
2042 },
2043 },
2044 Call: &promParser.Call{
2045 Func: &promParser.Function{
2046 Name: "absent",
2047 ArgTypes: []promParser.ValueType{
2048 promParser.ValueTypeVector,
2049 },
2050 Variadic: 0,
2051 ReturnType: promParser.ValueTypeVector,
2052 },
2053 Args: promParser.Expressions{
2054 mustParseVector(`foo{job="xxx"}`, 32),
2055 },
2056 PosRange: posrange.PositionRange{
2057 Start: 25,
2058 End: 47,
2059 },
2060 },
2061 },
2062 },
2063 },
2064 {
2065 expr: "vector(1)",
2066 output: []utils.Source{
2067 {
2068 Type: utils.FuncSource,
2069 Returns: promParser.ValueTypeVector,
2070 Operation: "vector",
2071 FixedLabels: true,
2072 AlwaysReturns: true,
2073 ReturnedNumbers: []float64{1},
2074 ExcludeReason: map[string]utils.ExcludedLabel{
2075 "": {
2076 Reason: "Calling `vector()` will return a vector value with no labels.",
2077 Fragment: `vector(1)`,
2078 },
2079 },
2080 Call: &promParser.Call{
2081 Func: &promParser.Function{
2082 Name: "vector",
2083 ArgTypes: []promParser.ValueType{
2084 promParser.ValueTypeScalar,
2085 },
2086 Variadic: 0,
2087 ReturnType: promParser.ValueTypeVector,
2088 },
2089 Args: promParser.Expressions{
2090 &promParser.NumberLiteral{
2091 Val: 1,
2092 PosRange: posrange.PositionRange{
2093 Start: 7,
2094 End: 8,
2095 },
2096 },
2097 },
2098 PosRange: posrange.PositionRange{
2099 Start: 0,
2100 End: 9,
2101 },
2102 },
2103 },
2104 },
2105 },
2106 {
2107 expr: "vector(scalar(foo))",
2108 output: []utils.Source{
2109 {
2110 Type: utils.FuncSource,
2111 Returns: promParser.ValueTypeVector,
2112 Operation: "vector",
2113 FixedLabels: true,
2114 AlwaysReturns: true,
2115 ExcludeReason: map[string]utils.ExcludedLabel{
2116 "": {
2117 Reason: "Calling `vector()` will return a vector value with no labels.",
2118 Fragment: `vector(scalar(foo))`,
2119 },
2120 },
2121 Call: &promParser.Call{
2122 Func: &promParser.Function{
2123 Name: "vector",
2124 ArgTypes: []promParser.ValueType{
2125 promParser.ValueTypeScalar,
2126 },
2127 Variadic: 0,
2128 ReturnType: promParser.ValueTypeVector,
2129 },
2130 Args: promParser.Expressions{
2131 &promParser.Call{
2132 Func: &promParser.Function{
2133 Name: "scalar",
2134 ArgTypes: []promParser.ValueType{
2135 promParser.ValueTypeVector,
2136 },
2137 Variadic: 0,
2138 ReturnType: promParser.ValueTypeScalar,
2139 },
2140 Args: promParser.Expressions{
2141 mustParseVector("foo", 14),
2142 },
2143 PosRange: posrange.PositionRange{
2144 Start: 7,
2145 End: 18,
2146 },
2147 },
2148 },
2149 PosRange: posrange.PositionRange{
2150 Start: 0,
2151 End: 19,
2152 },
2153 },
2154 },
2155 },
2156 },
2157 {
2158 expr: "vector(0.0 >= bool 0.5) == 1",
2159 output: []utils.Source{
2160 {
2161 Type: utils.FuncSource,
2162 Returns: promParser.ValueTypeVector,
2163 Operation: "vector",
2164 FixedLabels: true,
2165 AlwaysReturns: true,
2166 ExcludeReason: map[string]utils.ExcludedLabel{
2167 "": {
2168 Reason: "Calling `vector()` will return a vector value with no labels.",
2169 Fragment: `vector(0.0 >= bool 0.5)`,
2170 },
2171 },
2172 Call: &promParser.Call{
2173 Func: &promParser.Function{
2174 Name: "vector",
2175 ArgTypes: []promParser.ValueType{
2176 promParser.ValueTypeScalar,
2177 },
2178 Variadic: 0,
2179 ReturnType: promParser.ValueTypeVector,
2180 },
2181 Args: promParser.Expressions{
2182 &promParser.BinaryExpr{
2183 Op: promParser.GTE,
2184 LHS: &promParser.NumberLiteral{
2185 Val: 0,
2186 PosRange: posrange.PositionRange{
2187 Start: 7,
2188 End: 10,
2189 },
2190 },
2191 RHS: &promParser.NumberLiteral{
2192 Val: 0.5,
2193 PosRange: posrange.PositionRange{
2194 Start: 20,
2195 End: 23,
2196 },
2197 },
2198 ReturnBool: true,
2199 },
2200 },
2201 PosRange: posrange.PositionRange{
2202 Start: 0,
2203 End: 24,
2204 },
2205 },
2206 },
2207 },
2208 },
2209 {
2210 expr: `sum_over_time(foo{job="myjob"}[5m])`,
2211 output: []utils.Source{
2212 {
2213 Type: utils.FuncSource,
2214 Returns: promParser.ValueTypeVector,
2215 Operation: "sum_over_time",
2216 Selectors: []*promParser.VectorSelector{
2217 mustParseVector(`foo{job="myjob"}`, 14),
2218 },
2219 GuaranteedLabels: []string{"job"},
2220 Call: &promParser.Call{
2221 Func: &promParser.Function{
2222 Name: "sum_over_time",
2223 ArgTypes: []promParser.ValueType{
2224 promParser.ValueTypeMatrix,
2225 },
2226 Variadic: 0,
2227 ReturnType: promParser.ValueTypeVector,
2228 },
2229 Args: promParser.Expressions{
2230 mustParseMatrix(`foo{job="myjob"}[5m]`, 14),
2231 },
2232 PosRange: posrange.PositionRange{
2233 Start: 0,
2234 End: 35,
2235 },
2236 },
2237 },
2238 },
2239 },
2240 {
2241 expr: `days_in_month()`,
2242 output: []utils.Source{
2243 {
2244 Type: utils.FuncSource,
2245 Returns: promParser.ValueTypeVector,
2246 Operation: "days_in_month",
2247 FixedLabels: true,
2248 AlwaysReturns: true,
2249 ExcludeReason: map[string]utils.ExcludedLabel{
2250 "": {
2251 Reason: "Calling `days_in_month()` with no arguments will return an empty time series with no labels.",
2252 Fragment: `days_in_month()`,
2253 },
2254 },
2255 Call: &promParser.Call{
2256 Func: &promParser.Function{
2257 Name: "days_in_month",
2258 ArgTypes: []promParser.ValueType{
2259 promParser.ValueTypeVector,
2260 },
2261 Variadic: 1,
2262 ReturnType: promParser.ValueTypeVector,
2263 },
2264 Args: promParser.Expressions{},
2265 PosRange: posrange.PositionRange{
2266 Start: 0,
2267 End: 15,
2268 },
2269 },
2270 },
2271 },
2272 },
2273 {
2274 expr: `days_in_month(foo{job="foo"})`,
2275 output: []utils.Source{
2276 {
2277 Type: utils.FuncSource,
2278 Returns: promParser.ValueTypeVector,
2279 Operation: "days_in_month",
2280 Selectors: []*promParser.VectorSelector{
2281 mustParseVector(`foo{job="foo"}`, 14),
2282 },
2283 GuaranteedLabels: []string{"job"},
2284 Call: &promParser.Call{
2285 Func: &promParser.Function{
2286 Name: "days_in_month",
2287 ArgTypes: []promParser.ValueType{
2288 promParser.ValueTypeVector,
2289 },
2290 Variadic: 1,
2291 ReturnType: promParser.ValueTypeVector,
2292 },
2293 Args: promParser.Expressions{
2294 mustParseVector(`foo{job="foo"}`, 14),
2295 },
2296 PosRange: posrange.PositionRange{
2297 Start: 0,
2298 End: 29,
2299 },
2300 },
2301 },
2302 },
2303 },
2304 {
2305 expr: `label_replace(up{job="api-server",service="a:c"}, "foo", "$1", "service", "(.*):.*")`,
2306 output: []utils.Source{
2307 {
2308 Type: utils.FuncSource,
2309 Returns: promParser.ValueTypeVector,
2310 Operation: "label_replace",
2311 Selectors: []*promParser.VectorSelector{
2312 mustParseVector(`up{job="api-server",service="a:c"}`, 14),
2313 },
2314 GuaranteedLabels: []string{"job", "service", "foo"},
2315 Call: &promParser.Call{
2316 Func: &promParser.Function{
2317 Name: "label_replace",
2318 ArgTypes: []promParser.ValueType{
2319 promParser.ValueTypeVector,
2320 promParser.ValueTypeString,
2321 promParser.ValueTypeString,
2322 promParser.ValueTypeString,
2323 promParser.ValueTypeString,
2324 },
2325 Variadic: 0,
2326 ReturnType: promParser.ValueTypeVector,
2327 },
2328 Args: promParser.Expressions{
2329 mustParseVector(`up{job="api-server",service="a:c"}`, 14),
2330 &promParser.StringLiteral{
2331 Val: "foo",
2332 PosRange: posrange.PositionRange{
2333 Start: 50,
2334 End: 55,
2335 },
2336 },
2337 &promParser.StringLiteral{
2338 Val: "$1",
2339 PosRange: posrange.PositionRange{
2340 Start: 57,
2341 End: 61,
2342 },
2343 },
2344 &promParser.StringLiteral{
2345 Val: "service",
2346 PosRange: posrange.PositionRange{
2347 Start: 63,
2348 End: 72,
2349 },
2350 },
2351 &promParser.StringLiteral{
2352 Val: "(.*):.*",
2353 PosRange: posrange.PositionRange{
2354 Start: 74,
2355 End: 83,
2356 },
2357 },
2358 },
2359 PosRange: posrange.PositionRange{
2360 Start: 0,
2361 End: 84,
2362 },
2363 },
2364 },
2365 },
2366 },
2367 {
2368 expr: `(time() - my_metric) > 5*3600`,
2369 output: []utils.Source{
2370 {
2371 Type: utils.SelectorSource,
2372 Returns: promParser.ValueTypeVector,
2373 Selectors: []*promParser.VectorSelector{
2374 mustParseVector("my_metric", 10),
2375 },
2376 },
2377 },
2378 },
2379 {
2380 expr: `up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`,
2381 output: []utils.Source{
2382 {
2383 Type: utils.SelectorSource,
2384 Returns: promParser.ValueTypeVector,
2385 Operation: promParser.CardOneToOne.String(),
2386 Selectors: []*promParser.VectorSelector{
2387 mustParseVector(`up{instance="a", job="prometheus"}`, 0),
2388 },
2389 GuaranteedLabels: []string{"instance"},
2390 ExcludedLabels: []string{"job"},
2391 ExcludeReason: map[string]utils.ExcludedLabel{
2392 "job": {
2393 Reason: "Query is using one-to-one vector matching with `ignoring(job)`, all labels included inside `ignoring(...)` will be removed on the results.",
2394 Fragment: `up{instance="a", job="prometheus"} * ignoring(job) up{instance="a", job="pint"}`,
2395 },
2396 },
2397 },
2398 },
2399 },
2400 {
2401 expr: `
2402avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})
2403< 0.5 > 0
2404or sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})
2405< on() count(colo_router_tier:disabled_pops:max{tier="1",router=~"edge.*"}) * 0.4 > 0
2406or avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})
2407< 0.1 > 0
2408`,
2409 output: []utils.Source{
2410 {
2411 Type: utils.AggregateSource,
2412 Returns: promParser.ValueTypeVector,
2413 Operation: "avg",
2414 Selectors: []*promParser.VectorSelector{
2415 mustParseVector(`router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"}`, 41),
2416 },
2417 ExcludedLabels: []string{"router", "colo_id", "instance"},
2418 ExcludeReason: map[string]utils.ExcludedLabel{
2419 "router": {
2420 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2421 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`,
2422 },
2423 "colo_id": {
2424 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2425 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`,
2426 },
2427 "instance": {
2428 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2429 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case!~".*offpeak.*"})`,
2430 },
2431 },
2432 },
2433 {
2434 Type: utils.AggregateSource,
2435 Returns: promParser.ValueTypeVector,
2436 Operation: "sum",
2437 Selectors: []*promParser.VectorSelector{
2438 mustParseVector(`router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"}`, 155),
2439 },
2440 GuaranteedLabels: []string{"cidr_use_case"},
2441 ExcludedLabels: []string{"router", "colo_id", "instance"},
2442 FixedLabels: true,
2443 ExcludeReason: map[string]utils.ExcludedLabel{
2444 "router": {
2445 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2446 Fragment: `sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})`,
2447 },
2448 "colo_id": {
2449 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2450 Fragment: `sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})`,
2451 },
2452 "instance": {
2453 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2454 Fragment: `sum without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*tier1.*"})`,
2455 },
2456 "": {
2457 Reason: "Query is using one-to-one vector matching with `on()`, only labels included inside `on(...)` will be present on the results.",
2458 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",
2459 },
2460 },
2461 },
2462 {
2463 Type: utils.AggregateSource,
2464 Returns: promParser.ValueTypeVector,
2465 Operation: "avg",
2466 Selectors: []*promParser.VectorSelector{
2467 mustParseVector(`router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"}`, 343),
2468 },
2469 GuaranteedLabels: []string{"cidr_use_case"},
2470 ExcludedLabels: []string{"router", "colo_id", "instance"},
2471 ExcludeReason: map[string]utils.ExcludedLabel{
2472 "router": {
2473 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2474 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`,
2475 },
2476 "colo_id": {
2477 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2478 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`,
2479 },
2480 "instance": {
2481 Reason: "Query is using aggregation with `without(router, colo_id, instance)`, all labels included inside `without(...)` will be removed from the results.",
2482 Fragment: `avg without(router, colo_id, instance) (router_anycast_prefix_enabled{cidr_use_case=~".*regional.*"})`,
2483 },
2484 },
2485 },
2486 },
2487 },
2488 {
2489 expr: `label_replace(sum(foo) without(instance), "instance", "none", "", "")`,
2490 output: []utils.Source{
2491 {
2492 Type: utils.FuncSource,
2493 Returns: promParser.ValueTypeVector,
2494 Operation: "label_replace",
2495 Selectors: []*promParser.VectorSelector{
2496 mustParseVector(`foo`, 18),
2497 },
2498 GuaranteedLabels: []string{"instance"},
2499 Call: &promParser.Call{
2500 Func: &promParser.Function{
2501 Name: "label_replace",
2502 ArgTypes: []promParser.ValueType{
2503 promParser.ValueTypeVector,
2504 promParser.ValueTypeString,
2505 promParser.ValueTypeString,
2506 promParser.ValueTypeString,
2507 promParser.ValueTypeString,
2508 },
2509 Variadic: 0,
2510 ReturnType: promParser.ValueTypeVector,
2511 },
2512 Args: promParser.Expressions{
2513 &promParser.AggregateExpr{
2514 Op: promParser.SUM,
2515 Expr: mustParseVector("foo", 18),
2516 Grouping: []string{"instance"},
2517 Without: true,
2518 PosRange: posrange.PositionRange{
2519 Start: 14,
2520 End: 40,
2521 },
2522 },
2523 &promParser.StringLiteral{
2524 Val: "instance",
2525 PosRange: posrange.PositionRange{
2526 Start: 42,
2527 End: 52,
2528 },
2529 },
2530 &promParser.StringLiteral{
2531 Val: "none",
2532 PosRange: posrange.PositionRange{
2533 Start: 54,
2534 End: 60,
2535 },
2536 },
2537 &promParser.StringLiteral{
2538 Val: "",
2539 PosRange: posrange.PositionRange{
2540 Start: 62,
2541 End: 64,
2542 },
2543 },
2544 &promParser.StringLiteral{
2545 Val: "",
2546 PosRange: posrange.PositionRange{
2547 Start: 66,
2548 End: 68,
2549 },
2550 },
2551 },
2552 PosRange: posrange.PositionRange{
2553 Start: 0,
2554 End: 69,
2555 },
2556 },
2557 },
2558 },
2559 },
2560 {
2561 expr: `
2562sum by (region, target, colo_name) (
2563 sum_over_time(probe_success{job="abc"}[5m])
2564 or
2565 vector(1)
2566) == 0`,
2567 output: []utils.Source{
2568 {
2569 Type: utils.AggregateSource,
2570 Returns: promParser.ValueTypeVector,
2571 Operation: "sum",
2572 Selectors: []*promParser.VectorSelector{
2573 mustParseVector(`probe_success{job="abc"}`, 56),
2574 },
2575 IncludedLabels: []string{"region", "target", "colo_name"},
2576 FixedLabels: true,
2577 ExcludeReason: map[string]utils.ExcludedLabel{
2578 "": {
2579 Reason: "Query is using aggregation with `by(region, target, colo_name)`, only labels included inside `by(...)` will be present on the results.",
2580 Fragment: "sum by (region, target, colo_name) (\n sum_over_time(probe_success{job=\"abc\"}[5m])\n\tor\n\tvector(1)\n)",
2581 },
2582 },
2583 },
2584 {
2585 Type: utils.AggregateSource,
2586 Returns: promParser.ValueTypeVector,
2587 Operation: "sum",
2588 FixedLabels: true,
2589 AlwaysReturns: true,
2590 IsDead: true,
2591 ReturnedNumbers: []float64{1},
2592 ExcludeReason: map[string]utils.ExcludedLabel{
2593 "": {
2594 Reason: "Calling `vector()` will return a vector value with no labels.",
2595 Fragment: "vector(1)",
2596 },
2597 },
2598 },
2599 },
2600 },
2601 {
2602 expr: `vector(1) or foo`,
2603 output: []utils.Source{
2604 {
2605 Type: utils.FuncSource,
2606 Returns: promParser.ValueTypeVector,
2607 Operation: "vector",
2608 FixedLabels: true,
2609 AlwaysReturns: true,
2610 ReturnedNumbers: []float64{1},
2611 ExcludeReason: map[string]utils.ExcludedLabel{
2612 "": {
2613 Reason: "Calling `vector()` will return a vector value with no labels.",
2614 Fragment: "vector(1)",
2615 },
2616 },
2617 Call: &promParser.Call{
2618 Func: &promParser.Function{
2619 Name: "vector",
2620 ArgTypes: []promParser.ValueType{
2621 promParser.ValueTypeScalar,
2622 },
2623 Variadic: 0,
2624 ReturnType: promParser.ValueTypeVector,
2625 },
2626 Args: promParser.Expressions{
2627 &promParser.NumberLiteral{
2628 Val: 1,
2629 PosRange: posrange.PositionRange{
2630 Start: 7,
2631 End: 8,
2632 },
2633 },
2634 },
2635 PosRange: posrange.PositionRange{
2636 Start: 0,
2637 End: 9,
2638 },
2639 },
2640 },
2641 {
2642 Type: utils.SelectorSource,
2643 Operation: promParser.CardManyToMany.String(),
2644 Returns: promParser.ValueTypeVector,
2645 Selectors: []*promParser.VectorSelector{
2646 mustParseVector("foo", 13),
2647 },
2648 IsDead: true,
2649 },
2650 },
2651 },
2652 {
2653 expr: `vector(0) > 0`,
2654 output: []utils.Source{
2655 {
2656 Type: utils.FuncSource,
2657 Returns: promParser.ValueTypeVector,
2658 Operation: "vector",
2659 FixedLabels: true,
2660 AlwaysReturns: true,
2661 ReturnedNumbers: []float64{0},
2662 IsDead: true,
2663 ExcludeReason: map[string]utils.ExcludedLabel{
2664 "": {
2665 Reason: "Calling `vector()` will return a vector value with no labels.",
2666 Fragment: "vector(0)",
2667 },
2668 },
2669 Call: &promParser.Call{
2670 Func: &promParser.Function{
2671 Name: "vector",
2672 ArgTypes: []promParser.ValueType{
2673 promParser.ValueTypeScalar,
2674 },
2675 Variadic: 0,
2676 ReturnType: promParser.ValueTypeVector,
2677 },
2678 Args: promParser.Expressions{
2679 &promParser.NumberLiteral{
2680 Val: 0,
2681 PosRange: posrange.PositionRange{
2682 Start: 7,
2683 End: 8,
2684 },
2685 },
2686 },
2687 PosRange: posrange.PositionRange{
2688 Start: 0,
2689 End: 9,
2690 },
2691 },
2692 },
2693 },
2694 },
2695 {
2696 expr: `sum(foo or vector(0)) > 0`,
2697 output: []utils.Source{
2698 {
2699 Type: utils.AggregateSource,
2700 Returns: promParser.ValueTypeVector,
2701 Operation: "sum",
2702 Selectors: []*promParser.VectorSelector{
2703 mustParseVector(`foo`, 4),
2704 },
2705 FixedLabels: true,
2706 ExcludeReason: map[string]utils.ExcludedLabel{
2707 "": {
2708 Reason: "Query is using aggregation that removes all labels.",
2709 Fragment: `sum(foo or vector(0))`,
2710 },
2711 },
2712 },
2713 {
2714 Type: utils.AggregateSource,
2715 Returns: promParser.ValueTypeVector,
2716 Operation: "sum",
2717 FixedLabels: true,
2718 AlwaysReturns: true,
2719 ReturnedNumbers: []float64{0},
2720 IsDead: true,
2721 ExcludeReason: map[string]utils.ExcludedLabel{
2722 "": {
2723 Reason: "Query is using aggregation that removes all labels.",
2724 Fragment: "sum(foo or vector(0))",
2725 },
2726 },
2727 },
2728 },
2729 },
2730 {
2731 expr: `(sum(foo or vector(1)) > 0) == 2`,
2732 output: []utils.Source{
2733 {
2734 Type: utils.AggregateSource,
2735 Returns: promParser.ValueTypeVector,
2736 Operation: "sum",
2737 Selectors: []*promParser.VectorSelector{
2738 mustParseVector(`foo`, 5),
2739 },
2740 FixedLabels: true,
2741 ExcludeReason: map[string]utils.ExcludedLabel{
2742 "": {
2743 Reason: "Query is using aggregation that removes all labels.",
2744 Fragment: `sum(foo or vector(1))`,
2745 },
2746 },
2747 },
2748 {
2749 Type: utils.AggregateSource,
2750 Returns: promParser.ValueTypeVector,
2751 Operation: "sum",
2752 FixedLabels: true,
2753 AlwaysReturns: true,
2754 ReturnedNumbers: []float64{1},
2755 IsDead: true,
2756 ExcludeReason: map[string]utils.ExcludedLabel{
2757 "": {
2758 Reason: "Query is using aggregation that removes all labels.",
2759 Fragment: "sum(foo or vector(1))",
2760 },
2761 },
2762 },
2763 },
2764 },
2765 {
2766 expr: `(sum(foo or vector(1)) > 0) != 2`,
2767 output: []utils.Source{
2768 {
2769 Type: utils.AggregateSource,
2770 Returns: promParser.ValueTypeVector,
2771 Operation: "sum",
2772 Selectors: []*promParser.VectorSelector{
2773 mustParseVector(`foo`, 5),
2774 },
2775 FixedLabels: true,
2776 ExcludeReason: map[string]utils.ExcludedLabel{
2777 "": {
2778 Reason: "Query is using aggregation that removes all labels.",
2779 Fragment: `sum(foo or vector(1))`,
2780 },
2781 },
2782 },
2783 {
2784 Type: utils.AggregateSource,
2785 Returns: promParser.ValueTypeVector,
2786 Operation: "sum",
2787 FixedLabels: true,
2788 AlwaysReturns: true,
2789 ReturnedNumbers: []float64{1},
2790 ExcludeReason: map[string]utils.ExcludedLabel{
2791 "": {
2792 Reason: "Query is using aggregation that removes all labels.",
2793 Fragment: "sum(foo or vector(1))",
2794 },
2795 },
2796 },
2797 },
2798 },
2799 {
2800 expr: `(sum(foo or vector(2)) > 0) != 2`,
2801 output: []utils.Source{
2802 {
2803 Type: utils.AggregateSource,
2804 Returns: promParser.ValueTypeVector,
2805 Operation: "sum",
2806 Selectors: []*promParser.VectorSelector{
2807 mustParseVector(`foo`, 5),
2808 },
2809 FixedLabels: true,
2810 ExcludeReason: map[string]utils.ExcludedLabel{
2811 "": {
2812 Reason: "Query is using aggregation that removes all labels.",
2813 Fragment: `sum(foo or vector(2))`,
2814 },
2815 },
2816 },
2817 {
2818 Type: utils.AggregateSource,
2819 Returns: promParser.ValueTypeVector,
2820 Operation: "sum",
2821 FixedLabels: true,
2822 AlwaysReturns: true,
2823 ReturnedNumbers: []float64{2},
2824 IsDead: true,
2825 ExcludeReason: map[string]utils.ExcludedLabel{
2826 "": {
2827 Reason: "Query is using aggregation that removes all labels.",
2828 Fragment: "sum(foo or vector(2))",
2829 },
2830 },
2831 },
2832 },
2833 },
2834 }
2835
2836 for _, tc := range testCases {
2837 t.Run(tc.expr, func(t *testing.T) {
2838 n, err := parser.DecodeExpr(tc.expr)
2839 if err != nil {
2840 t.Error(err)
2841 t.FailNow()
2842 }
2843 output := utils.LabelsSource(tc.expr, n.Expr)
2844 require.Len(t, output, len(tc.output))
2845 for i := range len(tc.output) {
2846 require.EqualExportedValues(t, tc.output[i], output[i], "Mismatch at index %d", i)
2847 }
2848 })
2849 }
2850}
2851
2852func TestLabelsSourceCallCoverage(t *testing.T) {
2853 for name, def := range promParser.Functions {
2854 t.Run(name, func(t *testing.T) {
2855 if def.Experimental {
2856 t.SkipNow()
2857 }
2858
2859 var b strings.Builder
2860 b.WriteString(name)
2861 b.WriteRune('(')
2862 for i, at := range def.ArgTypes {
2863 if i > 0 {
2864 b.WriteString(", ")
2865 }
2866 switch at {
2867 case promParser.ValueTypeNone:
2868 case promParser.ValueTypeScalar:
2869 b.WriteRune('1')
2870 case promParser.ValueTypeVector:
2871 b.WriteString("http_requests_total")
2872 case promParser.ValueTypeMatrix:
2873 b.WriteString("http_requests_total[2m]")
2874 case promParser.ValueTypeString:
2875 b.WriteString(`"foo"`)
2876 }
2877 }
2878 b.WriteRune(')')
2879
2880 n, err := parser.DecodeExpr(b.String())
2881 if err != nil {
2882 t.Error(err)
2883 t.FailNow()
2884 }
2885 output := utils.LabelsSource(b.String(), n.Expr)
2886 require.Len(t, output, 1)
2887 require.NotNil(t, output[0].Call, "no call detected in: %q ~> %+v", b.String(), output)
2888 require.Equal(t, name, output[0].Operation)
2889 require.Equal(t, def.ReturnType, output[0].Returns, "incorrect return type on Source{}")
2890 })
2891 }
2892}
2893
2894func TestLabelsSourceCallCoverageFail(t *testing.T) {
2895 n := &parser.PromQLNode{
2896 Expr: &promParser.Call{
2897 Func: &promParser.Function{
2898 Name: "fake_call",
2899 },
2900 },
2901 }
2902 output := utils.LabelsSource("fake_call()", n.Expr)
2903 require.Len(t, output, 1)
2904 require.Nil(t, output[0].Call, "no call should have been detected in fake function")
2905}
2906