cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.49.2

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/checks/alerts_count_test.go

815lines · modecode

1package checks_test
2
3import (
4 "fmt"
5 "net/url"
6 "testing"
7 "time"
8
9 "github.com/prometheus/common/model"
10
11 "github.com/cloudflare/pint/internal/checks"
12 "github.com/cloudflare/pint/internal/promapi"
13)
14
15func newAlertsCheck(prom *promapi.FailoverGroup) checks.RuleChecker {
16 return checks.NewAlertsCheck(prom, time.Hour*24, time.Minute, time.Minute*5, 0, checks.Information)
17}
18
19func alertsText(name, uri string, count int, since string) string {
20 return fmt.Sprintf("`%s` Prometheus server at %s would trigger %d alert(s) in the last %s.", name, uri, count, since)
21}
22
23func alertsDetails(uri, query, since string) string {
24 return fmt.Sprintf(
25 `To get a preview of the alerts that would fire please [click here](%s/graph?g0.expr=%s&g0.range_input=%s).`,
26 uri, url.QueryEscape(query), since,
27 )
28}
29
30func TestAlertsCountCheck(t *testing.T) {
31 content := "- alert: Foo Is Down\n expr: up{job=\"foo\"} == 0\n"
32
33 testCases := []checkTest{
34 {
35 description: "ignores recording rules",
36 content: "- record: foo\n expr: up == 0\n",
37 checker: newAlertsCheck,
38 prometheus: newSimpleProm,
39 problems: noProblems,
40 },
41 {
42 description: "ignores rules with syntax errors",
43 content: "- alert: Foo Is Down\n expr: sum(\n",
44 checker: newAlertsCheck,
45 prometheus: newSimpleProm,
46 problems: noProblems,
47 },
48 {
49 description: "bad request",
50 content: content,
51 checker: newAlertsCheck,
52 prometheus: newSimpleProm,
53 problems: func(uri string) []checks.Problem {
54 return []checks.Problem{
55 {
56 Fragment: `up{job="foo"} == 0`,
57 Lines: []int{2},
58 Reporter: "alerts/count",
59 Text: checkErrorBadData("prom", uri, "bad_data: bad input data"),
60 Severity: checks.Bug,
61 },
62 }
63 },
64 mocks: []*prometheusMock{
65 {
66 conds: []requestCondition{
67 requireRangeQueryPath,
68 formCond{key: "query", value: `up{job="foo"} == 0`},
69 },
70 resp: respondWithBadData(),
71 },
72 },
73 },
74 {
75 description: "connection refused / upstream not required / warning",
76 content: content,
77 checker: newAlertsCheck,
78 prometheus: func(s string) *promapi.FailoverGroup {
79 return simpleProm("prom", "http://127.0.0.1:1111", time.Second*5, false)
80 },
81 problems: func(uri string) []checks.Problem {
82 return []checks.Problem{
83 {
84 Fragment: `up{job="foo"} == 0`,
85 Lines: []int{2},
86 Reporter: "alerts/count",
87 Text: checkErrorUnableToRun(checks.AlertsCheckName, "prom", "http://127.0.0.1:1111", `connection refused`),
88 Severity: checks.Warning,
89 },
90 }
91 },
92 },
93 {
94 description: "empty response",
95 content: content,
96 checker: newAlertsCheck,
97 prometheus: newSimpleProm,
98 problems: func(uri string) []checks.Problem {
99 return []checks.Problem{
100 {
101 Fragment: `up{job="foo"} == 0`,
102 Lines: []int{2},
103 Reporter: "alerts/count",
104 Text: alertsText("prom", uri, 0, "1d"),
105 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
106 Severity: checks.Information,
107 },
108 }
109 },
110 mocks: []*prometheusMock{
111 {
112 conds: []requestCondition{
113 requireRangeQueryPath,
114 formCond{key: "query", value: `up{job="foo"} == 0`},
115 },
116 resp: respondWithEmptyMatrix(),
117 },
118 },
119 },
120 {
121 description: "multiple alerts",
122 content: content,
123 checker: newAlertsCheck,
124 prometheus: newSimpleProm,
125 problems: func(uri string) []checks.Problem {
126 return []checks.Problem{
127 {
128 Fragment: `up{job="foo"} == 0`,
129 Lines: []int{2},
130 Reporter: "alerts/count",
131 Text: alertsText("prom", uri, 7, "1d"),
132 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
133 Severity: checks.Information,
134 },
135 }
136 },
137 mocks: []*prometheusMock{
138 {
139 conds: []requestCondition{
140 requireRangeQueryPath,
141 formCond{key: "query", value: `up{job="foo"} == 0`},
142 },
143 resp: matrixResponse{
144 samples: []*model.SampleStream{
145 // 7m
146 generateSampleStream(
147 map[string]string{"job": "foo"},
148 time.Now().Add(time.Hour*-24),
149 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
150 time.Minute,
151 ),
152 // 7m
153 generateSampleStream(
154 map[string]string{"job": "foo"},
155 time.Now().Add(time.Hour*-23),
156 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
157 time.Minute,
158 ),
159 // 2m
160 generateSampleStream(
161 map[string]string{"job": "foo"},
162 time.Now().Add(time.Hour*-22),
163 time.Now().Add(time.Hour*-22).Add(time.Minute),
164 time.Minute,
165 ),
166 // 17m
167 generateSampleStream(
168 map[string]string{"job": "foo"},
169 time.Now().Add(time.Hour*-21),
170 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
171 time.Minute,
172 ),
173 // 37m
174 generateSampleStream(
175 map[string]string{"job": "foo"},
176 time.Now().Add(time.Hour*-20),
177 time.Now().Add(time.Hour*-20).Add(time.Minute*36),
178 time.Minute,
179 ),
180 // 37m
181 generateSampleStream(
182 map[string]string{"job": "foo"},
183 time.Now().Add(time.Hour*-19),
184 time.Now().Add(time.Hour*-19).Add(time.Minute*36),
185 time.Minute,
186 ),
187 // 2h1m
188 generateSampleStream(
189 map[string]string{"job": "foo"},
190 time.Now().Add(time.Hour*-10),
191 time.Now().Add(time.Hour*-10).Add(time.Hour*2),
192 time.Minute,
193 ),
194 },
195 },
196 },
197 {
198 conds: []requestCondition{
199 requireRangeQueryPath,
200 formCond{key: "query", value: `count(up)`},
201 },
202 resp: respondWithSingleRangeVector1D(),
203 },
204 },
205 },
206 {
207 description: "for: 10m",
208 content: "- alert: Foo Is Down\n for: 10m\n expr: up{job=\"foo\"} == 0\n",
209 checker: newAlertsCheck,
210 prometheus: newSimpleProm,
211 problems: func(uri string) []checks.Problem {
212 return []checks.Problem{
213 {
214 Fragment: `up{job="foo"} == 0`,
215 Lines: []int{2, 3},
216 Reporter: "alerts/count",
217 Text: alertsText("prom", uri, 2, "1d"),
218 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
219 Severity: checks.Information,
220 },
221 }
222 },
223 mocks: []*prometheusMock{
224 {
225 conds: []requestCondition{
226 requireRangeQueryPath,
227 formCond{key: "query", value: `up{job="foo"} == 0`},
228 },
229 resp: matrixResponse{
230 samples: []*model.SampleStream{
231 generateSampleStream(
232 map[string]string{"job": "foo"},
233 time.Now().Add(time.Hour*-24),
234 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
235 time.Minute,
236 ),
237 generateSampleStream(
238 map[string]string{"job": "foo"},
239 time.Now().Add(time.Hour*-23),
240 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
241 time.Minute,
242 ),
243 generateSampleStream(
244 map[string]string{"job": "foo"},
245 time.Now().Add(time.Hour*-22),
246 time.Now().Add(time.Hour*-22).Add(time.Minute),
247 time.Minute,
248 ),
249 generateSampleStream(
250 map[string]string{"job": "foo"},
251 time.Now().Add(time.Hour*-21),
252 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
253 time.Minute,
254 ),
255 generateSampleStream(
256 map[string]string{"job": "foo"},
257 time.Now().Add(time.Hour*-20),
258 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
259 time.Minute,
260 ),
261 generateSampleStream(
262 map[string]string{"job": "foo"},
263 time.Now().Add(time.Hour*-18),
264 time.Now().Add(time.Hour*-18).Add(time.Hour*2),
265 time.Minute,
266 ),
267 },
268 },
269 },
270 {
271 conds: []requestCondition{
272 requireRangeQueryPath,
273 formCond{key: "query", value: `count(up)`},
274 },
275 resp: respondWithSingleRangeVector1D(),
276 },
277 },
278 },
279 {
280 description: "minCount=2",
281 content: "- alert: Foo Is Down\n for: 10m\n expr: up{job=\"foo\"} == 0\n",
282 checker: func(prom *promapi.FailoverGroup) checks.RuleChecker {
283 return checks.NewAlertsCheck(prom, time.Hour*24, time.Minute, time.Minute*5, 2, checks.Information)
284 },
285 prometheus: newSimpleProm,
286 problems: func(uri string) []checks.Problem {
287 return []checks.Problem{
288 {
289 Fragment: `up{job="foo"} == 0`,
290 Lines: []int{2, 3},
291 Reporter: "alerts/count",
292 Text: alertsText("prom", uri, 2, "1d"),
293 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
294 Severity: checks.Information,
295 },
296 }
297 },
298 mocks: []*prometheusMock{
299 {
300 conds: []requestCondition{
301 requireRangeQueryPath,
302 formCond{key: "query", value: `up{job="foo"} == 0`},
303 },
304 resp: matrixResponse{
305 samples: []*model.SampleStream{
306 generateSampleStream(
307 map[string]string{"job": "foo"},
308 time.Now().Add(time.Hour*-24),
309 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
310 time.Minute,
311 ),
312 generateSampleStream(
313 map[string]string{"job": "foo"},
314 time.Now().Add(time.Hour*-23),
315 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
316 time.Minute,
317 ),
318 generateSampleStream(
319 map[string]string{"job": "foo"},
320 time.Now().Add(time.Hour*-22),
321 time.Now().Add(time.Hour*-22).Add(time.Minute),
322 time.Minute,
323 ),
324 generateSampleStream(
325 map[string]string{"job": "foo"},
326 time.Now().Add(time.Hour*-21),
327 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
328 time.Minute,
329 ),
330 generateSampleStream(
331 map[string]string{"job": "foo"},
332 time.Now().Add(time.Hour*-20),
333 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
334 time.Minute,
335 ),
336 generateSampleStream(
337 map[string]string{"job": "foo"},
338 time.Now().Add(time.Hour*-18),
339 time.Now().Add(time.Hour*-18).Add(time.Hour*2),
340 time.Minute,
341 ),
342 },
343 },
344 },
345 {
346 conds: []requestCondition{
347 requireRangeQueryPath,
348 formCond{key: "query", value: `count(up)`},
349 },
350 resp: respondWithSingleRangeVector1D(),
351 },
352 },
353 },
354 {
355 description: "minCount=2 severity=bug",
356 content: "- alert: Foo Is Down\n for: 10m\n expr: up{job=\"foo\"} == 0\n",
357 checker: func(prom *promapi.FailoverGroup) checks.RuleChecker {
358 return checks.NewAlertsCheck(prom, time.Hour*24, time.Minute, time.Minute*5, 2, checks.Bug)
359 },
360 prometheus: newSimpleProm,
361 problems: func(uri string) []checks.Problem {
362 return []checks.Problem{
363 {
364 Fragment: `up{job="foo"} == 0`,
365 Lines: []int{2, 3},
366 Reporter: "alerts/count",
367 Text: alertsText("prom", uri, 2, "1d"),
368 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
369 Severity: checks.Bug,
370 },
371 }
372 },
373 mocks: []*prometheusMock{
374 {
375 conds: []requestCondition{
376 requireRangeQueryPath,
377 formCond{key: "query", value: `up{job="foo"} == 0`},
378 },
379 resp: matrixResponse{
380 samples: []*model.SampleStream{
381 generateSampleStream(
382 map[string]string{"job": "foo"},
383 time.Now().Add(time.Hour*-24),
384 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
385 time.Minute,
386 ),
387 generateSampleStream(
388 map[string]string{"job": "foo"},
389 time.Now().Add(time.Hour*-23),
390 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
391 time.Minute,
392 ),
393 generateSampleStream(
394 map[string]string{"job": "foo"},
395 time.Now().Add(time.Hour*-22),
396 time.Now().Add(time.Hour*-22).Add(time.Minute),
397 time.Minute,
398 ),
399 generateSampleStream(
400 map[string]string{"job": "foo"},
401 time.Now().Add(time.Hour*-21),
402 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
403 time.Minute,
404 ),
405 generateSampleStream(
406 map[string]string{"job": "foo"},
407 time.Now().Add(time.Hour*-20),
408 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
409 time.Minute,
410 ),
411 generateSampleStream(
412 map[string]string{"job": "foo"},
413 time.Now().Add(time.Hour*-18),
414 time.Now().Add(time.Hour*-18).Add(time.Hour*2),
415 time.Minute,
416 ),
417 },
418 },
419 },
420 {
421 conds: []requestCondition{
422 requireRangeQueryPath,
423 formCond{key: "query", value: `count(up)`},
424 },
425 resp: respondWithSingleRangeVector1D(),
426 },
427 },
428 },
429 {
430 description: "minCount=10",
431 content: "- alert: Foo Is Down\n for: 10m\n expr: up{job=\"foo\"} == 0\n",
432 checker: func(prom *promapi.FailoverGroup) checks.RuleChecker {
433 return checks.NewAlertsCheck(prom, time.Hour*24, time.Minute, time.Minute*5, 10, checks.Information)
434 },
435 prometheus: newSimpleProm,
436 problems: noProblems,
437 mocks: []*prometheusMock{
438 {
439 conds: []requestCondition{
440 requireRangeQueryPath,
441 formCond{key: "query", value: `up{job="foo"} == 0`},
442 },
443 resp: matrixResponse{
444 samples: []*model.SampleStream{
445 generateSampleStream(
446 map[string]string{"job": "foo"},
447 time.Now().Add(time.Hour*-24),
448 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
449 time.Minute,
450 ),
451 generateSampleStream(
452 map[string]string{"job": "foo"},
453 time.Now().Add(time.Hour*-23),
454 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
455 time.Minute,
456 ),
457 generateSampleStream(
458 map[string]string{"job": "foo"},
459 time.Now().Add(time.Hour*-22),
460 time.Now().Add(time.Hour*-22).Add(time.Minute),
461 time.Minute,
462 ),
463 generateSampleStream(
464 map[string]string{"job": "foo"},
465 time.Now().Add(time.Hour*-21),
466 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
467 time.Minute,
468 ),
469 generateSampleStream(
470 map[string]string{"job": "foo"},
471 time.Now().Add(time.Hour*-20),
472 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
473 time.Minute,
474 ),
475 generateSampleStream(
476 map[string]string{"job": "foo"},
477 time.Now().Add(time.Hour*-18),
478 time.Now().Add(time.Hour*-18).Add(time.Hour*2),
479 time.Minute,
480 ),
481 },
482 },
483 },
484 {
485 conds: []requestCondition{
486 requireRangeQueryPath,
487 formCond{key: "query", value: `count(up)`},
488 },
489 resp: respondWithSingleRangeVector1D(),
490 },
491 },
492 },
493 {
494 description: "{__name__=}",
495 content: `
496- alert: foo
497 expr: '{__name__="up", job="foo"} == 0'
498`,
499 checker: newAlertsCheck,
500 prometheus: newSimpleProm,
501 problems: func(uri string) []checks.Problem {
502 return []checks.Problem{
503 {
504 Fragment: `{__name__="up", job="foo"} == 0`,
505 Lines: []int{3},
506 Reporter: "alerts/count",
507 Text: alertsText("prom", uri, 3, "1d"),
508 Details: alertsDetails(uri, `{__name__="up", job="foo"} == 0`, "1d"),
509 Severity: checks.Information,
510 },
511 }
512 },
513 mocks: []*prometheusMock{
514 {
515 conds: []requestCondition{
516 requireRangeQueryPath,
517 formCond{key: "query", value: `{__name__="up", job="foo"} == 0`},
518 },
519 resp: matrixResponse{
520 samples: []*model.SampleStream{
521 generateSampleStream(
522 map[string]string{"job": "foo"},
523 time.Now().Add(time.Hour*-23),
524 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
525 time.Minute,
526 ),
527 generateSampleStream(
528 map[string]string{"job": "foo"},
529 time.Now().Add(time.Hour*-22),
530 time.Now().Add(time.Hour*-22).Add(time.Minute*6),
531 time.Minute,
532 ),
533 generateSampleStream(
534 map[string]string{"job": "foo"},
535 time.Now().Add(time.Hour*-21),
536 time.Now().Add(time.Hour*-21).Add(time.Minute),
537 time.Minute,
538 ),
539 },
540 },
541 },
542 {
543 conds: []requestCondition{
544 requireRangeQueryPath,
545 formCond{key: "query", value: `count(up)`},
546 },
547 resp: respondWithSingleRangeVector1D(),
548 },
549 },
550 },
551 {
552 description: "{__name__=~}",
553 content: `
554- alert: foo
555 expr: '{__name__=~"(up|foo)", job="foo"} == 0'
556`,
557 checker: newAlertsCheck,
558 prometheus: newSimpleProm,
559 problems: func(uri string) []checks.Problem {
560 return []checks.Problem{
561 {
562 Fragment: `{__name__=~"(up|foo)", job="foo"} == 0`,
563 Lines: []int{3},
564 Reporter: "alerts/count",
565 Text: alertsText("prom", uri, 3, "1d"),
566 Details: alertsDetails(uri, `{__name__=~"(up|foo)", job="foo"} == 0`, "1d"),
567
568 Severity: checks.Information,
569 },
570 }
571 },
572 mocks: []*prometheusMock{
573 {
574 conds: []requestCondition{
575 requireRangeQueryPath,
576 formCond{key: "query", value: `{__name__=~"(up|foo)", job="foo"} == 0`},
577 },
578 resp: matrixResponse{
579 samples: []*model.SampleStream{
580 generateSampleStream(
581 map[string]string{"job": "foo"},
582 time.Now().Add(time.Hour*-21),
583 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
584 time.Minute,
585 ),
586 generateSampleStream(
587 map[string]string{"job": "foo"},
588 time.Now().Add(time.Hour*-20),
589 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
590 time.Minute,
591 ),
592 generateSampleStream(
593 map[string]string{"job": "foo"},
594 time.Now().Add(time.Hour*-10),
595 time.Now().Add(time.Hour*-10).Add(time.Hour*2),
596 time.Minute,
597 ),
598 },
599 },
600 },
601 {
602 conds: []requestCondition{
603 requireRangeQueryPath,
604 formCond{key: "query", value: `count(up)`},
605 },
606 resp: respondWithSingleRangeVector1D(),
607 },
608 },
609 },
610 {
611 description: "uptime query error",
612 content: "- alert: Foo Is Down\n expr: up{job=\"foo\"} == 0\n",
613 checker: newAlertsCheck,
614 prometheus: newSimpleProm,
615 problems: func(uri string) []checks.Problem {
616 return []checks.Problem{
617 {
618 Fragment: `up{job="foo"} == 0`,
619 Lines: []int{2},
620 Reporter: "alerts/count",
621 Text: alertsText("prom", uri, 3, "1d"),
622 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
623
624 Severity: checks.Information,
625 },
626 }
627 },
628 mocks: []*prometheusMock{
629 {
630 conds: []requestCondition{
631 requireRangeQueryPath,
632 formCond{key: "query", value: `up{job="foo"} == 0`},
633 },
634 resp: matrixResponse{
635 samples: []*model.SampleStream{
636 generateSampleStream(
637 map[string]string{"job": "foo"},
638 time.Now().Add(time.Hour*-23),
639 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
640 time.Minute,
641 ),
642 generateSampleStream(
643 map[string]string{"job": "foo"},
644 time.Now().Add(time.Hour*-22),
645 time.Now().Add(time.Hour*-22).Add(time.Minute*6),
646 time.Minute,
647 ),
648 generateSampleStream(
649 map[string]string{"job": "foo"},
650 time.Now().Add(time.Hour*-21),
651 time.Now().Add(time.Hour*-21).Add(time.Minute),
652 time.Minute,
653 ),
654 },
655 },
656 },
657 {
658 conds: []requestCondition{
659 requireRangeQueryPath,
660 formCond{key: "query", value: `count(up)`},
661 },
662 resp: respondWithInternalError(),
663 },
664 },
665 },
666 {
667 description: "keep_firing_for: 10m",
668 content: "- alert: Foo Is Down\n keep_firing_for: 10m\n expr: up{job=\"foo\"} == 0\n",
669 checker: newAlertsCheck,
670 prometheus: newSimpleProm,
671 problems: func(uri string) []checks.Problem {
672 return []checks.Problem{
673 {
674 Fragment: `up{job="foo"} == 0`,
675 Lines: []int{2, 3},
676 Reporter: "alerts/count",
677 Text: alertsText("prom", uri, 2, "1d"),
678 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
679 Severity: checks.Information,
680 },
681 }
682 },
683 mocks: []*prometheusMock{
684 {
685 conds: []requestCondition{
686 requireRangeQueryPath,
687 formCond{key: "query", value: `up{job="foo"} == 0`},
688 },
689 resp: matrixResponse{
690 samples: []*model.SampleStream{
691 generateSampleStream(
692 map[string]string{"job": "foo"},
693 time.Now().Add(time.Hour*-24),
694 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
695 time.Minute,
696 ),
697 generateSampleStream(
698 map[string]string{"job": "foo"},
699 time.Now().Add(time.Hour*-23),
700 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
701 time.Minute,
702 ),
703 generateSampleStream(
704 map[string]string{"job": "foo"},
705 time.Now().Add(time.Hour*-22),
706 time.Now().Add(time.Hour*-22).Add(time.Minute),
707 time.Minute,
708 ),
709 generateSampleStream(
710 map[string]string{"job": "foo"},
711 time.Now().Add(time.Hour*-21),
712 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
713 time.Minute,
714 ),
715 generateSampleStream(
716 map[string]string{"job": "foo"},
717 time.Now().Add(time.Hour*-20),
718 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
719 time.Minute,
720 ),
721 generateSampleStream(
722 map[string]string{"job": "foo"},
723 time.Now().Add(time.Hour*-18),
724 time.Now().Add(time.Hour*-18).Add(time.Hour*2),
725 time.Minute,
726 ),
727 },
728 },
729 },
730 {
731 conds: []requestCondition{
732 requireRangeQueryPath,
733 formCond{key: "query", value: `count(up)`},
734 },
735 resp: respondWithSingleRangeVector1D(),
736 },
737 },
738 },
739 {
740 description: "for: 10m + keep_firing_for: 10m",
741 content: "- alert: Foo Is Down\n for: 10m\n keep_firing_for: 10m\n expr: up{job=\"foo\"} == 0\n",
742 checker: newAlertsCheck,
743 prometheus: newSimpleProm,
744 problems: func(uri string) []checks.Problem {
745 return []checks.Problem{
746 {
747 Fragment: `up{job="foo"} == 0`,
748 Lines: []int{2, 3, 4},
749 Reporter: "alerts/count",
750 Text: alertsText("prom", uri, 1, "1d"),
751 Details: alertsDetails(uri, `up{job="foo"} == 0`, "1d"),
752 Severity: checks.Information,
753 },
754 }
755 },
756 mocks: []*prometheusMock{
757 {
758 conds: []requestCondition{
759 requireRangeQueryPath,
760 formCond{key: "query", value: `up{job="foo"} == 0`},
761 },
762 resp: matrixResponse{
763 samples: []*model.SampleStream{
764 generateSampleStream(
765 map[string]string{"job": "foo"},
766 time.Now().Add(time.Hour*-24),
767 time.Now().Add(time.Hour*-24).Add(time.Minute*6),
768 time.Minute,
769 ),
770 generateSampleStream(
771 map[string]string{"job": "foo"},
772 time.Now().Add(time.Hour*-23),
773 time.Now().Add(time.Hour*-23).Add(time.Minute*6),
774 time.Minute,
775 ),
776 generateSampleStream(
777 map[string]string{"job": "foo"},
778 time.Now().Add(time.Hour*-22),
779 time.Now().Add(time.Hour*-22).Add(time.Minute),
780 time.Minute,
781 ),
782 generateSampleStream(
783 map[string]string{"job": "foo"},
784 time.Now().Add(time.Hour*-21),
785 time.Now().Add(time.Hour*-21).Add(time.Minute*16),
786 time.Minute,
787 ),
788 generateSampleStream(
789 map[string]string{"job": "foo"},
790 time.Now().Add(time.Hour*-20),
791 time.Now().Add(time.Hour*-20).Add(time.Minute*9).Add(time.Second*59),
792 time.Minute,
793 ),
794 generateSampleStream(
795 map[string]string{"job": "foo"},
796 time.Now().Add(time.Hour*-18),
797 time.Now().Add(time.Hour*-18).Add(time.Hour*2),
798 time.Minute,
799 ),
800 },
801 },
802 },
803 {
804 conds: []requestCondition{
805 requireRangeQueryPath,
806 formCond{key: "query", value: `count(up)`},
807 },
808 resp: respondWithSingleRangeVector1D(),
809 },
810 },
811 },
812 }
813
814 runTests(t, testCases)
815}
816