cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.18.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/parser_test.go

889lines · modecode

1package parser_test
2
3import (
4 "fmt"
5 "strconv"
6 "testing"
7
8 "github.com/cloudflare/pint/internal/parser"
9
10 "github.com/google/go-cmp/cmp"
11 promparser "github.com/prometheus/prometheus/promql/parser"
12)
13
14func TestParse(t *testing.T) {
15 type testCaseT struct {
16 content []byte
17 output []parser.Rule
18 shouldError bool
19 }
20
21 testCases := []testCaseT{
22 {
23 content: nil,
24 output: nil,
25 shouldError: false,
26 },
27 {
28 content: []byte{},
29 output: nil,
30 shouldError: false,
31 },
32 {
33 content: []byte(string("! !00 \xf6")),
34 output: nil,
35 shouldError: true,
36 },
37 {
38 content: []byte(string("- 0: 0\n 00000000: 000000\n 000000:00000000000: 00000000\n 00000000000:000000: 0000000000000000000000000000000000\n 000000: 0000000\n expr: |")),
39 output: []parser.Rule{
40 {Error: parser.ParseError{Err: fmt.Errorf("incomplete rule, no alert or record key"), Line: 6}},
41 },
42 },
43 {
44 content: []byte("- record: |\n multiline\n"),
45 output: []parser.Rule{
46 {Error: parser.ParseError{Err: fmt.Errorf("missing expr key"), Line: 1}},
47 },
48 },
49 {
50 content: []byte("- expr: foo\n"),
51 output: []parser.Rule{
52 {Error: parser.ParseError{Err: fmt.Errorf("incomplete rule, no alert or record key"), Line: 1}},
53 },
54 },
55 {
56 content: []byte("- alert: foo\n"),
57 output: []parser.Rule{
58 {Error: parser.ParseError{Err: fmt.Errorf("missing expr key"), Line: 1}},
59 },
60 },
61 {
62 content: []byte("- alert: foo\n record: foo\n"),
63 output: []parser.Rule{
64 {Error: parser.ParseError{Err: fmt.Errorf("got both record and alert keys in a single rule"), Line: 1}},
65 },
66 },
67 {
68 content: []byte("- record: foo\n labels:\n foo: bar\n"),
69 output: []parser.Rule{
70 {Error: parser.ParseError{Err: fmt.Errorf("missing expr key"), Line: 1}},
71 },
72 },
73 {
74 content: []byte("- record: - foo\n"),
75 shouldError: true,
76 },
77 {
78 content: []byte("- record: foo expr: sum(\n"),
79 shouldError: true,
80 },
81 {
82 content: []byte("- record\n\texpr: foo\n"),
83 shouldError: true,
84 },
85 {
86 content: []byte(`
87- record: foo
88 expr: bar
89 expr: bar
90`),
91 output: []parser.Rule{
92 {Error: parser.ParseError{Err: fmt.Errorf("duplicated expr key"), Line: 4}},
93 },
94 },
95 {
96 content: []byte(`
97- record: foo
98 expr: bar
99 record: bar
100`),
101 output: []parser.Rule{
102 {Error: parser.ParseError{Err: fmt.Errorf("duplicated record key"), Line: 4}},
103 },
104 },
105 {
106 content: []byte(`
107- alert: foo
108 alert: bar
109 expr: bar
110`),
111 output: []parser.Rule{
112 {Error: parser.ParseError{Err: fmt.Errorf("duplicated alert key"), Line: 3}},
113 },
114 },
115 {
116 content: []byte(`
117- alert: foo
118 for: 5m
119 expr: bar
120 for: 1m
121`),
122 output: []parser.Rule{
123 {Error: parser.ParseError{Err: fmt.Errorf("duplicated for key"), Line: 5}},
124 },
125 },
126 {
127 content: []byte(`
128- alert: foo
129 labels: {}
130 expr: bar
131 labels: {}
132`),
133 output: []parser.Rule{
134 {Error: parser.ParseError{Err: fmt.Errorf("duplicated labels key"), Line: 5}},
135 },
136 },
137 {
138 content: []byte(`
139- record: foo
140 labels: {}
141 expr: bar
142 labels: {}
143`),
144 output: []parser.Rule{
145 {Error: parser.ParseError{Err: fmt.Errorf("duplicated labels key"), Line: 5}},
146 },
147 },
148 {
149 content: []byte(`
150- alert: foo
151 annotations: {}
152 expr: bar
153 annotations: {}
154`),
155 output: []parser.Rule{
156 {Error: parser.ParseError{Err: fmt.Errorf("duplicated annotations key"), Line: 5}},
157 },
158 },
159 {
160 content: []byte("- record: foo\n expr: foo\n extra: true\n"),
161 output: []parser.Rule{
162 {Error: parser.ParseError{Err: fmt.Errorf("invalid key(s) found: extra"), Line: 3}},
163 },
164 },
165 {
166 content: []byte("- record: foo\n expr: foo offset 10m\n"),
167 output: []parser.Rule{
168 {
169 RecordingRule: &parser.RecordingRule{
170 Record: parser.YamlKeyValue{
171 Key: &parser.YamlNode{
172 Position: parser.FilePosition{Lines: []int{1}},
173 Value: "record",
174 },
175 Value: &parser.YamlNode{
176 Position: parser.FilePosition{Lines: []int{1}},
177 Value: "foo",
178 },
179 },
180 Expr: parser.PromQLExpr{
181 Key: &parser.YamlNode{
182 Position: parser.FilePosition{Lines: []int{2}},
183 Value: "expr",
184 },
185 Value: &parser.YamlNode{
186 Position: parser.FilePosition{Lines: []int{2}},
187 Value: "foo offset 10m",
188 },
189 Query: &parser.PromQLNode{
190 Expr: "foo offset 10m",
191 },
192 },
193 },
194 },
195 },
196 },
197 {
198 content: []byte("- record: foo\n expr: foo offset -10m\n"),
199 output: []parser.Rule{
200 {
201 RecordingRule: &parser.RecordingRule{
202 Record: parser.YamlKeyValue{
203 Key: &parser.YamlNode{
204 Position: parser.FilePosition{Lines: []int{1}},
205 Value: "record",
206 },
207 Value: &parser.YamlNode{
208 Position: parser.FilePosition{Lines: []int{1}},
209 Value: "foo",
210 },
211 },
212 Expr: parser.PromQLExpr{
213 Key: &parser.YamlNode{
214 Position: parser.FilePosition{Lines: []int{2}},
215 Value: "expr",
216 },
217 Value: &parser.YamlNode{
218 Position: parser.FilePosition{Lines: []int{2}},
219 Value: "foo offset -10m",
220 },
221 Query: &parser.PromQLNode{
222 Expr: "foo offset -10m",
223 },
224 },
225 },
226 },
227 },
228 },
229 {
230 content: []byte(`
231# head comment
232- record: foo # record comment
233 expr: foo offset 10m # expr comment
234 # pre-labels comment
235 labels:
236 # pre-foo comment
237 foo: bar
238 # post-foo comment
239 bob: alice
240# foot comment
241`),
242 output: []parser.Rule{
243 {
244 RecordingRule: &parser.RecordingRule{
245 Record: parser.YamlKeyValue{
246 Key: &parser.YamlNode{
247 Position: parser.FilePosition{Lines: []int{3}},
248 Value: "record",
249 Comments: []string{"# head comment"},
250 },
251 Value: &parser.YamlNode{
252 Position: parser.FilePosition{Lines: []int{3}},
253 Value: "foo",
254 Comments: []string{"# record comment"},
255 },
256 },
257 Expr: parser.PromQLExpr{
258 Key: &parser.YamlNode{
259 Position: parser.FilePosition{Lines: []int{4}},
260 Value: "expr",
261 },
262 Value: &parser.YamlNode{
263 Position: parser.FilePosition{Lines: []int{4}},
264 Value: "foo offset 10m",
265 Comments: []string{"# expr comment"},
266 },
267 Query: &parser.PromQLNode{
268 Expr: "foo offset 10m",
269 },
270 },
271 Labels: &parser.YamlMap{
272 Key: &parser.YamlNode{
273 Position: parser.FilePosition{Lines: []int{6}},
274 Value: "labels",
275 Comments: []string{"# pre-labels comment"},
276 },
277 Items: []*parser.YamlKeyValue{
278 {
279 Key: &parser.YamlNode{
280 Position: parser.FilePosition{Lines: []int{8}},
281 Value: "foo",
282 Comments: []string{"# pre-foo comment"},
283 },
284 Value: &parser.YamlNode{
285 Position: parser.FilePosition{Lines: []int{8}},
286 Value: "bar",
287 },
288 },
289 {
290 Key: &parser.YamlNode{
291 Position: parser.FilePosition{Lines: []int{10}},
292 Value: "bob",
293 Comments: []string{"# post-foo comment"},
294 },
295 Value: &parser.YamlNode{
296 Position: parser.FilePosition{Lines: []int{10}},
297 Value: "alice",
298 },
299 },
300 },
301 },
302 },
303 },
304 },
305 },
306 {
307 content: []byte("- record: foo\n expr: foo[5m] offset 10m\n"),
308 output: []parser.Rule{
309 {
310 RecordingRule: &parser.RecordingRule{
311 Record: parser.YamlKeyValue{
312 Key: &parser.YamlNode{
313 Position: parser.FilePosition{Lines: []int{1}},
314 Value: "record",
315 },
316 Value: &parser.YamlNode{
317 Position: parser.FilePosition{Lines: []int{1}},
318 Value: "foo",
319 },
320 },
321 Expr: parser.PromQLExpr{
322 Key: &parser.YamlNode{
323 Position: parser.FilePosition{Lines: []int{2}},
324 Value: "expr",
325 },
326 Value: &parser.YamlNode{
327 Position: parser.FilePosition{Lines: []int{2}},
328 Value: "foo[5m] offset 10m",
329 },
330 Query: &parser.PromQLNode{
331 Expr: "foo[5m] offset 10m",
332 Children: []*parser.PromQLNode{
333 {Expr: "foo offset 10m"},
334 },
335 },
336 },
337 },
338 },
339 },
340 },
341 {
342 content: []byte(`
343- record: name
344 expr: sum(foo)
345 labels:
346 foo: bar
347 bob: alice
348`),
349 output: []parser.Rule{
350 {
351 RecordingRule: &parser.RecordingRule{
352 Record: parser.YamlKeyValue{
353 Key: &parser.YamlNode{
354 Position: parser.FilePosition{Lines: []int{2}},
355 Value: "record",
356 },
357 Value: &parser.YamlNode{
358 Position: parser.FilePosition{Lines: []int{2}},
359 Value: "name",
360 },
361 },
362 Expr: parser.PromQLExpr{
363 Key: &parser.YamlNode{
364 Position: parser.FilePosition{Lines: []int{3}},
365 Value: "expr",
366 },
367 Value: &parser.YamlNode{
368 Position: parser.FilePosition{Lines: []int{3}},
369 Value: "sum(foo)",
370 },
371 Query: &parser.PromQLNode{
372 Expr: "sum(foo)",
373 Children: []*parser.PromQLNode{
374 {Expr: "foo"},
375 },
376 },
377 },
378 Labels: &parser.YamlMap{
379 Key: &parser.YamlNode{
380 Position: parser.FilePosition{Lines: []int{4}},
381 Value: "labels",
382 },
383 Items: []*parser.YamlKeyValue{
384 {
385 Key: &parser.YamlNode{
386 Position: parser.FilePosition{Lines: []int{5}},
387 Value: "foo",
388 },
389 Value: &parser.YamlNode{
390 Position: parser.FilePosition{Lines: []int{5}},
391 Value: "bar",
392 },
393 },
394 {
395 Key: &parser.YamlNode{
396 Position: parser.FilePosition{Lines: []int{6}},
397 Value: "bob",
398 },
399 Value: &parser.YamlNode{
400 Position: parser.FilePosition{Lines: []int{6}},
401 Value: "alice",
402 },
403 },
404 },
405 },
406 },
407 },
408 },
409 shouldError: false,
410 },
411 {
412 content: []byte(`
413groups:
414- name: custom_rules
415 rules:
416 - record: name
417 expr: sum(foo)
418 labels:
419 foo: bar
420 bob: alice
421`),
422 output: []parser.Rule{
423 {
424 RecordingRule: &parser.RecordingRule{
425 Record: parser.YamlKeyValue{
426 Key: &parser.YamlNode{
427 Position: parser.FilePosition{Lines: []int{5}},
428 Value: "record",
429 },
430 Value: &parser.YamlNode{
431 Position: parser.FilePosition{Lines: []int{5}},
432 Value: "name",
433 },
434 },
435 Expr: parser.PromQLExpr{
436 Key: &parser.YamlNode{
437 Position: parser.FilePosition{Lines: []int{6}},
438 Value: "expr",
439 },
440 Value: &parser.YamlNode{
441 Position: parser.FilePosition{Lines: []int{6}},
442 Value: "sum(foo)",
443 },
444 Query: &parser.PromQLNode{
445 Expr: "sum(foo)",
446 Children: []*parser.PromQLNode{
447 {Expr: "foo"},
448 },
449 },
450 },
451 Labels: &parser.YamlMap{
452 Key: &parser.YamlNode{
453 Position: parser.FilePosition{Lines: []int{7}},
454 Value: "labels",
455 },
456 Items: []*parser.YamlKeyValue{
457 {
458 Key: &parser.YamlNode{
459 Position: parser.FilePosition{Lines: []int{8}},
460 Value: "foo",
461 },
462 Value: &parser.YamlNode{
463 Position: parser.FilePosition{Lines: []int{8}},
464 Value: "bar",
465 },
466 },
467 {
468 Key: &parser.YamlNode{
469 Position: parser.FilePosition{Lines: []int{9}},
470 Value: "bob",
471 },
472 Value: &parser.YamlNode{
473 Position: parser.FilePosition{Lines: []int{9}},
474 Value: "alice",
475 },
476 },
477 },
478 },
479 },
480 },
481 },
482 shouldError: false,
483 },
484 {
485 content: []byte(`- alert: Down
486 expr: |
487 up == 0
488 for: |+
489 11m
490 labels:
491 severity: critical
492 annotations:
493 uri: https://docs.example.com/down.html
494
495- record: >
496 foo
497 expr: |-
498 bar
499 /
500 baz > 1
501 labels: {}
502`),
503 output: []parser.Rule{
504 {
505 AlertingRule: &parser.AlertingRule{
506 Alert: parser.YamlKeyValue{
507 Key: &parser.YamlNode{
508 Position: parser.FilePosition{Lines: []int{1}},
509 Value: "alert",
510 },
511 Value: &parser.YamlNode{
512 Position: parser.FilePosition{Lines: []int{1}},
513 Value: "Down",
514 },
515 },
516 Expr: parser.PromQLExpr{
517 Key: &parser.YamlNode{
518 Position: parser.FilePosition{Lines: []int{2}},
519 Value: "expr",
520 },
521 Value: &parser.YamlNode{
522 Position: parser.FilePosition{Lines: []int{3}},
523 Value: "up == 0\n",
524 },
525 Query: &parser.PromQLNode{
526 Expr: "up == 0\n",
527 Children: []*parser.PromQLNode{
528 {Expr: "up"},
529 {Expr: "0"},
530 },
531 },
532 },
533 For: &parser.YamlKeyValue{
534 Key: &parser.YamlNode{
535 Position: parser.FilePosition{Lines: []int{4}},
536 Value: "for",
537 },
538 Value: &parser.YamlNode{
539 Position: parser.FilePosition{Lines: []int{5}},
540 Value: "11m\n",
541 },
542 },
543 Labels: &parser.YamlMap{
544 Key: &parser.YamlNode{
545 Position: parser.FilePosition{Lines: []int{6}},
546 Value: "labels",
547 },
548 Items: []*parser.YamlKeyValue{
549 {
550 Key: &parser.YamlNode{
551 Position: parser.FilePosition{Lines: []int{7}},
552 Value: "severity",
553 },
554 Value: &parser.YamlNode{
555 Position: parser.FilePosition{Lines: []int{7}},
556 Value: "critical",
557 },
558 },
559 },
560 },
561 Annotations: &parser.YamlMap{
562 Key: &parser.YamlNode{
563 Position: parser.FilePosition{Lines: []int{8}},
564 Value: "annotations",
565 },
566 Items: []*parser.YamlKeyValue{
567 {
568 Key: &parser.YamlNode{
569 Position: parser.FilePosition{Lines: []int{9}},
570 Value: "uri",
571 },
572 Value: &parser.YamlNode{
573 Position: parser.FilePosition{Lines: []int{9}},
574 Value: "https://docs.example.com/down.html",
575 },
576 },
577 },
578 },
579 },
580 },
581 {
582 RecordingRule: &parser.RecordingRule{
583 Record: parser.YamlKeyValue{
584 Key: &parser.YamlNode{
585 Position: parser.FilePosition{Lines: []int{11}},
586 Value: "record",
587 },
588 Value: &parser.YamlNode{
589 Position: parser.FilePosition{Lines: []int{12}},
590 Value: "foo\n",
591 },
592 },
593 Expr: parser.PromQLExpr{
594 Key: &parser.YamlNode{
595 Position: parser.FilePosition{Lines: []int{13}},
596 Value: "expr",
597 },
598 Value: &parser.YamlNode{
599 Position: parser.FilePosition{Lines: []int{14, 15, 16}},
600 Value: "bar\n/\nbaz > 1",
601 },
602 Query: &parser.PromQLNode{
603 Expr: "bar\n/\nbaz > 1",
604 Children: []*parser.PromQLNode{
605 {
606 Expr: "bar / baz", Children: []*parser.PromQLNode{
607 {Expr: "bar"},
608 {Expr: "baz"},
609 },
610 },
611 {Expr: "1"},
612 },
613 },
614 },
615 Labels: &parser.YamlMap{
616 Key: &parser.YamlNode{
617 Position: parser.FilePosition{Lines: []int{17}},
618 Value: "labels",
619 },
620 },
621 },
622 },
623 },
624 shouldError: false,
625 },
626 {
627 content: []byte(`- alert: Foo
628 expr:
629 (
630 xxx
631 -
632 yyy
633 ) * bar > 0
634 and on(instance, device) baz
635 for: 30m
636`),
637 output: []parser.Rule{
638 {
639 AlertingRule: &parser.AlertingRule{
640 Alert: parser.YamlKeyValue{
641 Key: &parser.YamlNode{
642 Position: parser.FilePosition{Lines: []int{1}},
643 Value: "alert",
644 },
645 Value: &parser.YamlNode{
646 Position: parser.FilePosition{Lines: []int{1}},
647 Value: "Foo",
648 },
649 },
650 Expr: parser.PromQLExpr{
651 Key: &parser.YamlNode{
652 Position: parser.FilePosition{Lines: []int{2}},
653 Value: "expr",
654 },
655 Value: &parser.YamlNode{
656 Position: parser.FilePosition{Lines: []int{3, 4, 5, 6, 7, 8}},
657 Value: "( xxx - yyy ) * bar > 0 and on(instance, device) baz",
658 },
659 Query: &parser.PromQLNode{
660 Expr: "( xxx - yyy ) * bar > 0 and on(instance, device) baz",
661 Children: []*parser.PromQLNode{
662 {
663 Expr: "(xxx - yyy) * bar > 0",
664 Children: []*parser.PromQLNode{
665 {
666 Expr: "(xxx - yyy) * bar",
667 Children: []*parser.PromQLNode{
668 {
669 Expr: "(xxx - yyy)",
670 Children: []*parser.PromQLNode{
671 {
672 Expr: "xxx - yyy",
673 Children: []*parser.PromQLNode{
674 {Expr: "xxx"},
675 {Expr: "yyy"},
676 },
677 },
678 },
679 },
680 {
681 Expr: "bar",
682 },
683 },
684 },
685 {
686 Expr: "0",
687 },
688 },
689 },
690 {Expr: "baz"},
691 },
692 },
693 },
694 For: &parser.YamlKeyValue{
695 Key: &parser.YamlNode{
696 Position: parser.FilePosition{Lines: []int{9}},
697 Value: "for",
698 },
699 Value: &parser.YamlNode{
700 Position: parser.FilePosition{Lines: []int{9}},
701 Value: "30m",
702 },
703 },
704 },
705 },
706 },
707 },
708 {
709 content: []byte(`---
710kind: ConfigMap
711apiVersion: v1
712metadata:
713 name: example-app-alerts
714 labels:
715 app: example-app
716data:
717 alerts: |
718 groups:
719 - name: example-app-alerts
720 rules:
721 - alert: Example_Is_Down
722 expr: kube_deployment_status_replicas_available{namespace="example-app"} < 1
723 for: 5m
724 labels:
725 priority: "2"
726 environment: production
727 annotations:
728 summary: "No replicas for Example have been running for 5 minutes"
729
730 - alert: Example_High_Restart_Rate
731 expr: sum(rate(kube_pod_container_status_restarts_total{namespace="example-app"}[5m])) > ( 3/60 )
732`),
733 output: nil,
734 },
735 /*
736 FIXME https://github.com/cloudflare/pint/issues/20
737 {
738 content: []byte(`groups:
739 - name: "haproxy.api_server.rules"
740 rules:
741 - alert: HaproxyServerHealthcheckFailure
742 expr: increase(haproxy_server_check_failures_total[15m]) > 100
743 for: 5m
744 labels:
745 severity: 24x7
746 annotations:
747 summary: "HAProxy server healthcheck failure (instance {{ $labels.instance }})"
748 description: "Some server healthcheck are failing on {{ $labels.server }}\n VALUE = {{ $value }}\n LABELS: {{ $labels }}"
749 `),
750 output: []parser.Rule{
751 {
752 AlertingRule: &parser.AlertingRule{
753 Alert: parser.YamlKeyValue{
754 Key: &parser.YamlNode{
755 Position: parser.FilePosition{Lines: []int{4}},
756 Value: "alert",
757 },
758 Value: &parser.YamlNode{
759 Position: parser.FilePosition{Lines: []int{4}},
760 Value: "HaproxyServerHealthcheckFailure",
761 },
762 },
763 Expr: parser.PromQLExpr{
764 Key: &parser.YamlNode{
765 Position: parser.FilePosition{Lines: []int{5}},
766 Value: "expr",
767 },
768 Value: &parser.YamlNode{
769 Position: parser.FilePosition{Lines: []int{5}},
770 Value: "increase(haproxy_server_check_failures_total[15m]) > 100",
771 },
772 Query: &parser.PromQLNode{
773 Expr: "increase(haproxy_server_check_failures_total[15m]) > 100",
774 Children: []*parser.PromQLNode{
775 {
776 Expr: "increase(haproxy_server_check_failures_total[15m])",
777 Children: []*parser.PromQLNode{
778 {
779 Expr: "haproxy_server_check_failures_total[15m]",
780 Children: []*parser.PromQLNode{
781 {
782 Expr: "haproxy_server_check_failures_total",
783 },
784 },
785 },
786 },
787 },
788 {Expr: "100"},
789 },
790 },
791 },
792 For: &parser.YamlKeyValue{
793 Key: &parser.YamlNode{
794 Position: parser.FilePosition{Lines: []int{6}},
795 Value: "for",
796 },
797 Value: &parser.YamlNode{Position: parser.FilePosition{Lines: []int{6}},
798 Value: "5m",
799 },
800 },
801 Labels: &parser.YamlMap{
802 Key: &parser.YamlNode{
803 Position: parser.FilePosition{Lines: []int{7}},
804 Value: "labels",
805 },
806 Items: []*parser.YamlKeyValue{
807 {
808 Key: &parser.YamlNode{
809 Position: parser.FilePosition{Lines: []int{8}},
810 Value: "severity",
811 },
812 Value: &parser.YamlNode{
813 Position: parser.FilePosition{Lines: []int{8}},
814 Value: "24x7",
815 },
816 },
817 },
818 },
819 Annotations: &parser.YamlMap{
820 Key: &parser.YamlNode{
821 Position: parser.FilePosition{Lines: []int{9}},
822 Value: "annotations",
823 },
824 Items: []*parser.YamlKeyValue{
825 {
826 Key: &parser.YamlNode{
827 Position: parser.FilePosition{Lines: []int{10}},
828 Value: "summary",
829 },
830 Value: &parser.YamlNode{
831 Position: parser.FilePosition{Lines: []int{10}},
832 Value: "HAProxy server healthcheck failure (instance {{ $labels.instance }})",
833 },
834 },
835 {
836 Key: &parser.YamlNode{
837 Position: parser.FilePosition{Lines: []int{11}},
838 Value: "description",
839 },
840 Value: &parser.YamlNode{
841 Position: parser.FilePosition{Lines: []int{11}},
842 Value: `Some server healthcheck are failing on {{ $labels.server }}\n VALUE = {{ $value }}\n LABELS: {{ $labels }}`,
843 },
844 },
845 },
846 },
847 },
848 },
849 },
850 },
851 */
852 }
853
854 alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true })
855 ignorePrometheusExpr := cmp.FilterValues(func(x, y interface{}) bool {
856 _, xe := x.(promparser.Expr)
857 _, ye := y.(promparser.Expr)
858 return xe || ye
859 }, alwaysEqual)
860
861 cmpErrorText := cmp.Comparer(func(x, y interface{}) bool {
862 xe := x.(error)
863 ye := y.(error)
864 return xe.Error() == ye.Error()
865 })
866 sameErrorText := cmp.FilterValues(func(x, y interface{}) bool {
867 _, xe := x.(error)
868 _, ye := y.(error)
869 return xe && ye
870 }, cmpErrorText)
871
872 for i, tc := range testCases {
873 t.Run(strconv.Itoa(i+1), func(t *testing.T) {
874 p := parser.NewParser()
875 output, err := p.Parse(tc.content)
876
877 hadError := err != nil
878 if hadError != tc.shouldError {
879 t.Errorf("Parse() returned err=%v, expected=%v", err, tc.shouldError)
880 return
881 }
882
883 if diff := cmp.Diff(tc.output, output, ignorePrometheusExpr, sameErrorText); diff != "" {
884 t.Errorf("Parse() returned wrong output (-want +got):\n%s", diff)
885 return
886 }
887 })
888 }
889}
890