cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.57.3

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/discovery/git_branch_test.go

918lines · modecode

1package discovery_test
2
3import (
4 "encoding/json"
5 "fmt"
6 "os"
7 "regexp"
8 "strings"
9 "testing"
10
11 "github.com/google/go-cmp/cmp"
12 "github.com/prometheus/prometheus/model/rulefmt"
13 "github.com/stretchr/testify/require"
14
15 "github.com/cloudflare/pint/internal/discovery"
16 "github.com/cloudflare/pint/internal/git"
17 "github.com/cloudflare/pint/internal/parser"
18)
19
20func gitCommit(t *testing.T, message string) {
21 t.Setenv("GIT_AUTHOR_NAME", "pint")
22 t.Setenv("GIT_AUTHOR_EMAIL", "pint@example.com")
23 t.Setenv("GIT_COMMITTER_NAME", "pint")
24 t.Setenv("GIT_COMMITTER_EMAIL", "pint")
25 _, err := git.RunGit("commit", "-am", fmt.Sprintf("commit %s", message))
26 require.NoError(t, err, "git commit %s", message)
27}
28
29func commitFile(t *testing.T, path, content, message string) {
30 err := os.WriteFile(path, []byte(content), 0o644)
31 require.NoError(t, err, "write %s", path)
32 _, err = git.RunGit("add", path)
33 require.NoError(t, err, "git add")
34 gitCommit(t, message)
35}
36
37func TestGitBranchFinder(t *testing.T) {
38 includeAll := []*regexp.Regexp{regexp.MustCompile(".*")}
39
40 mustParse := func(offset int, s string) parser.Rule {
41 p := parser.NewParser()
42 r, err := p.Parse([]byte(strings.Repeat("\n", offset) + s))
43 if err != nil {
44 panic(fmt.Sprintf("failed to parse rule:\n---\n%s\n---\nerror: %s", s, err))
45 }
46 if len(r) != 1 {
47 panic(fmt.Sprintf("wrong number of rules returned: %d\n---\n%s\n---", len(r), s))
48 }
49 return r[0]
50 }
51
52 mustErr := func(s string) error {
53 _, errs := rulefmt.Parse([]byte(s))
54 if len(errs) == 0 {
55 panic(s)
56 }
57 return errs[0]
58 }
59
60 type setupFn func(t *testing.T)
61
62 type testCaseT struct {
63 setup setupFn
64 title string
65 err string
66 entries []discovery.Entry
67 finder discovery.GitBranchFinder
68 }
69
70 testCases := []testCaseT{
71 {
72 title: "git list PR commits error - main",
73 setup: func(_ *testing.T) {},
74 finder: discovery.NewGitBranchFinder(
75 func(args ...string) ([]byte, error) {
76 return nil, fmt.Errorf("mock git error: %v", args)
77 },
78 git.NewPathFilter(includeAll, nil, nil),
79 "main",
80 50,
81 ),
82 entries: nil,
83 err: "failed to get the list of commits to scan: mock git error: [log --format=%H --no-abbrev-commit --reverse main..HEAD]",
84 },
85 {
86 title: "git list PR commits error - master",
87 setup: func(_ *testing.T) {},
88 finder: discovery.NewGitBranchFinder(
89 func(args ...string) ([]byte, error) {
90 return nil, fmt.Errorf("mock git error: %v", args)
91 },
92 git.NewPathFilter(includeAll, nil, nil),
93 "master",
94 50,
95 ),
96 entries: nil,
97 err: "failed to get the list of commits to scan: mock git error: [log --format=%H --no-abbrev-commit --reverse master..HEAD]",
98 },
99 {
100 title: "too many commits",
101 setup: func(_ *testing.T) {},
102 finder: discovery.NewGitBranchFinder(
103 func(args ...string) ([]byte, error) {
104 switch strings.Join(args, " ") {
105 case "log --format=%H --no-abbrev-commit --reverse main..HEAD":
106 return []byte("c1\nc2\nc3\nc4\n"), nil
107 default:
108 return nil, fmt.Errorf("mock git error: %v", args)
109 }
110 },
111 git.NewPathFilter(includeAll, nil, nil),
112 "main",
113 3,
114 ),
115 entries: nil,
116 err: "number of commits to check (4) is higher than maxCommits (3), exiting",
117 },
118 {
119 title: "git list modified files error",
120 setup: func(_ *testing.T) {},
121 finder: discovery.NewGitBranchFinder(
122 func(args ...string) ([]byte, error) {
123 switch strings.Join(args, " ") {
124 case "log --format=%H --no-abbrev-commit --reverse main..HEAD":
125 return []byte("c1\nc2\nc3\nc4\n"), nil
126 default:
127 return nil, fmt.Errorf("mock git error: %v", args)
128 }
129 },
130 git.NewPathFilter(includeAll, nil, nil),
131 "main",
132 4,
133 ),
134 entries: nil,
135 err: "failed to get the list of modified files from git: mock git error: [log --reverse --no-merges --first-parent --format=%H --name-status c1^..c4]",
136 },
137 {
138 title: "git get commit message error",
139 setup: func(_ *testing.T) {},
140 finder: discovery.NewGitBranchFinder(
141 func(args ...string) ([]byte, error) {
142 switch strings.Join(args, " ") {
143 case "log --format=%H --no-abbrev-commit --reverse main..HEAD":
144 return []byte("c1\nc2\nc3\nc4\n"), nil
145 case "log --reverse --no-merges --first-parent --format=%H --name-status c1^..c4":
146 return []byte("c1\nA\trules.yml\n"), nil
147 default:
148 return nil, fmt.Errorf("mock git error: %v", args)
149 }
150 },
151 git.NewPathFilter(includeAll, nil, nil),
152 "main",
153 4,
154 ),
155 entries: nil,
156 err: "failed to get commit message for c1: mock git error: [show -s --format=%B c1]",
157 },
158 {
159 title: "git blame error",
160 setup: func(_ *testing.T) {},
161 finder: discovery.NewGitBranchFinder(
162 func(args ...string) ([]byte, error) {
163 switch strings.Join(args, " ") {
164 case "log --format=%H --no-abbrev-commit --reverse main..HEAD":
165 return []byte("c1\nc2\nc3\nc4\n"), nil
166 case "log --reverse --no-merges --first-parent --format=%H --name-status c1^..c4":
167 return []byte("c1\nA\trules.yml\n"), nil
168 case "ls-tree c1^ rules.yml":
169 return []byte("100644 blob c0\trules.yml"), nil
170 case "ls-tree c1 rules.yml":
171 return []byte("100644 blob c1\trules.yml"), nil
172 case "show -s --format=%B c1":
173 return []byte(""), nil
174 default:
175 return nil, fmt.Errorf("mock git error: %v", args)
176 }
177 },
178 git.NewPathFilter(includeAll, nil, nil),
179 "main",
180 4,
181 ),
182 entries: nil,
183 err: "failed to run git blame for rules.yml: mock git error: [blame --line-porcelain c1 -- rules.yml]",
184 },
185 {
186 title: "no rules in file",
187 setup: func(t *testing.T) {
188 commitFile(t, "rules.yml", "# v1\n", "v1")
189
190 _, err := git.RunGit("checkout", "-b", "v2")
191 require.NoError(t, err, "git checkout v2")
192
193 commitFile(t, "rules.yml", "# v2\n", "v2")
194 },
195 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
196 entries: nil,
197 },
198 {
199 title: "no rule changes",
200 setup: func(t *testing.T) {
201 commitFile(t, "rules.yml", `
202groups:
203- name: v1
204 rules:
205 - record: up:count
206 expr: count(up == 1)
207`, "v1")
208
209 _, err := git.RunGit("checkout", "-b", "v2")
210 require.NoError(t, err, "git checkout v2")
211
212 commitFile(t, "rules.yml", `
213groups:
214- name: v2
215 rules:
216 - record: up:count
217 expr: count(up == 1)
218`, "v2")
219 },
220 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
221 entries: []discovery.Entry{
222 {
223 State: discovery.Excluded,
224 ReportedPath: "rules.yml",
225 SourcePath: "rules.yml",
226 ModifiedLines: []int{},
227 Rule: mustParse(4, "- record: up:count\n expr: count(up == 1)\n"),
228 },
229 },
230 },
231 {
232 title: "rule changed - strict",
233 setup: func(t *testing.T) {
234 commitFile(t, "rules.yml", `
235groups:
236- name: v1
237 rules:
238 - record: up:count
239 expr: count(up)
240`, "v1")
241
242 _, err := git.RunGit("checkout", "-b", "v2")
243 require.NoError(t, err, "git checkout v2")
244
245 commitFile(t, "rules.yml", `
246groups:
247- name: v2
248 rules:
249 - record: up:count
250 expr: count(up == 1)
251`, "v2")
252 },
253 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
254 entries: []discovery.Entry{
255 {
256 State: discovery.Modified,
257 ReportedPath: "rules.yml",
258 SourcePath: "rules.yml",
259 ModifiedLines: []int{6},
260 Rule: mustParse(4, "- record: up:count\n expr: count(up == 1)\n"),
261 },
262 },
263 },
264 {
265 title: "rule changed - relaxed",
266 setup: func(t *testing.T) {
267 commitFile(t, "rules.yml", `
268- record: up:count
269 expr: count(up)
270`, "v1")
271
272 _, err := git.RunGit("checkout", "-b", "v2")
273 require.NoError(t, err, "git checkout v2")
274
275 commitFile(t, "rules.yml", `
276- record: up:count
277 expr: count(up == 1)
278`, "v2")
279 },
280 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
281 entries: []discovery.Entry{
282 {
283 State: discovery.Modified,
284 ReportedPath: "rules.yml",
285 SourcePath: "rules.yml",
286 ModifiedLines: []int{3},
287 Rule: mustParse(1, "- record: up:count\n expr: count(up == 1)\n"),
288 },
289 },
290 },
291 {
292 title: "rule changed - empty include list",
293 setup: func(t *testing.T) {
294 commitFile(t, "rules.yml", `
295- record: up:count
296 expr: count(up)
297`, "v1")
298
299 _, err := git.RunGit("checkout", "-b", "v2")
300 require.NoError(t, err, "git checkout v2")
301
302 commitFile(t, "rules.yml", `
303- record: up:count
304 expr: count(up == 1)
305`, "v2")
306 },
307 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(nil, nil, includeAll), "main", 4),
308 entries: []discovery.Entry{
309 {
310 State: discovery.Modified,
311 ReportedPath: "rules.yml",
312 SourcePath: "rules.yml",
313 ModifiedLines: []int{3},
314 Rule: mustParse(1, "- record: up:count\n expr: count(up == 1)\n"),
315 },
316 },
317 },
318 {
319 title: "rule changed but file excluded",
320 setup: func(t *testing.T) {
321 commitFile(t, "rules.yml", `
322groups:
323- name: v1
324 rules:
325 - record: up:count
326 expr: count(up)
327`, "v1")
328
329 _, err := git.RunGit("checkout", "-b", "v2")
330 require.NoError(t, err, "git checkout v2")
331
332 commitFile(t, "rules.yml", `
333groups:
334- name: v2
335 rules:
336 - record: up:count
337 expr: count(up == 1)
338`, "v2")
339 },
340 finder: discovery.NewGitBranchFinder(
341 git.RunGit,
342 git.NewPathFilter([]*regexp.Regexp{regexp.MustCompile("^foo#")}, nil, nil),
343 "main",
344 4,
345 ),
346 entries: nil,
347 },
348 {
349 title: "rule changed - [skip ci]",
350 setup: func(t *testing.T) {
351 commitFile(t, "rules.yml", `
352groups:
353- name: v1
354 rules:
355 - record: up:count
356 expr: count(up)
357`, "v1")
358
359 _, err := git.RunGit("checkout", "-b", "v2")
360 require.NoError(t, err, "git checkout v2")
361
362 commitFile(t, "rules.yml", `
363groups:
364- name: v2
365 rules:
366 - record: up:count
367 expr: count(up == 1)
368`, "v2\nskip this commit\n[skip ci]\n")
369 },
370 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
371 entries: nil,
372 },
373 {
374 title: "rule changed - [no ci]",
375 setup: func(t *testing.T) {
376 commitFile(t, "rules.yml", `
377groups:
378- name: v1
379 rules:
380 - record: up:count
381 expr: count(up)
382`, "v1")
383
384 _, err := git.RunGit("checkout", "-b", "v2")
385 require.NoError(t, err, "git checkout v2")
386
387 commitFile(t, "rules.yml", `
388groups:
389- name: v2
390 rules:
391 - record: up:count
392 expr: count(up == 1)
393`, "v2\nskip this commit\n[no ci]\n")
394 },
395 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
396 entries: nil,
397 },
398 {
399 title: "rule symlinked",
400 setup: func(t *testing.T) {
401 commitFile(t, "rules.yml", `
402- record: up:count
403 expr: count(up)
404`, "v1")
405
406 _, err := git.RunGit("checkout", "-b", "v2")
407 require.NoError(t, err, "git checkout v2")
408
409 err = os.Symlink("rules.yml", "symlink.yml")
410 require.NoError(t, err, "symlink")
411 _, err = git.RunGit("add", "symlink.yml")
412 require.NoError(t, err, "git add")
413 gitCommit(t, "v2")
414 },
415 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
416 entries: []discovery.Entry{
417 {
418 State: discovery.Added,
419 ReportedPath: "rules.yml",
420 SourcePath: "symlink.yml",
421 ModifiedLines: []int{2, 3},
422 Rule: mustParse(1, "- record: up:count\n expr: count(up)\n"),
423 },
424 },
425 },
426 {
427 title: "rule changed - multiple rules",
428 setup: func(t *testing.T) {
429 commitFile(t, "rules.yml", `
430groups:
431- name: v1
432 rules:
433 - record: up:count:1
434 expr: count(up)
435 - record: up:count:2
436 expr: count(up)
437 - record: up:count:3
438 expr: count(up)
439`, "v1")
440
441 _, err := git.RunGit("checkout", "-b", "v2")
442 require.NoError(t, err, "git checkout v2")
443
444 commitFile(t, "rules.yml", `
445groups:
446- name: v2
447 rules:
448 - record: up:count:1
449 expr: count(up == 1)
450 - record: up:count:2a
451 expr: count(up)
452 - record: up:count:3
453 expr: count(up)
454 - record: up:count:4
455 expr: count(up)
456`, "v2")
457 },
458 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
459 entries: []discovery.Entry{
460 {
461 State: discovery.Modified,
462 ReportedPath: "rules.yml",
463 SourcePath: "rules.yml",
464 ModifiedLines: []int{6},
465 Rule: mustParse(4, "- record: up:count:1\n expr: count(up == 1)\n"),
466 },
467 {
468 State: discovery.Added,
469 ReportedPath: "rules.yml",
470 SourcePath: "rules.yml",
471 ModifiedLines: []int{7},
472 Rule: mustParse(6, "- record: up:count:2a\n expr: count(up)\n"),
473 },
474 {
475 State: discovery.Excluded,
476 ReportedPath: "rules.yml",
477 SourcePath: "rules.yml",
478 ModifiedLines: []int{},
479 Rule: mustParse(8, "- record: up:count:3\n expr: count(up)\n"),
480 },
481 {
482 State: discovery.Added,
483 ReportedPath: "rules.yml",
484 SourcePath: "rules.yml",
485 ModifiedLines: []int{11, 12},
486 Rule: mustParse(10, "- record: up:count:4\n expr: count(up)\n"),
487 },
488 {
489 State: discovery.Removed,
490 ReportedPath: "rules.yml",
491 SourcePath: "rules.yml",
492 ModifiedLines: []int{7},
493 Rule: mustParse(6, "- record: up:count:2\n expr: count(up)\n"),
494 },
495 },
496 },
497 {
498 title: "rule changed - added extra line",
499 setup: func(t *testing.T) {
500 commitFile(t, "rules.yml", `
501- alert: rule1
502 expr: sum(foo) by(job)
503- alert: rule2
504 expr: sum(foo) by(job)
505 for: 0s
506`, "v1")
507
508 _, err := git.RunGit("checkout", "-b", "v2")
509 require.NoError(t, err, "git checkout v2")
510
511 commitFile(t, "rules.yml", `
512- alert: rule1
513 expr: sum(foo) by(job)
514 for: 0s
515- alert: rule2
516 expr: sum(foo) by(job)
517 for: 0s
518`, "v2")
519 },
520 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
521 entries: []discovery.Entry{
522 {
523 State: discovery.Modified,
524 ReportedPath: "rules.yml",
525 SourcePath: "rules.yml",
526 ModifiedLines: []int{4},
527 Rule: mustParse(1, "- alert: rule1\n expr: sum(foo) by(job)\n for: 0s\n"),
528 },
529 {
530 State: discovery.Excluded,
531 ReportedPath: "rules.yml",
532 SourcePath: "rules.yml",
533 ModifiedLines: []int{},
534 Rule: mustParse(4, "- alert: rule2\n expr: sum(foo) by(job)\n for: 0s\n"),
535 },
536 },
537 },
538 {
539 title: "rule removed - head",
540 setup: func(t *testing.T) {
541 commitFile(t, "rules.yml", `
542- alert: rule1
543 expr: sum(foo) by(job)
544- alert: rule2
545 expr: sum(foo) by(job)
546`, "v1")
547
548 _, err := git.RunGit("checkout", "-b", "v2")
549 require.NoError(t, err, "git checkout v2")
550
551 commitFile(t, "rules.yml", `
552- alert: rule2
553 expr: sum(foo) by(job)
554`, "v2")
555 },
556 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
557 entries: []discovery.Entry{
558 {
559 State: discovery.Excluded,
560 ReportedPath: "rules.yml",
561 SourcePath: "rules.yml",
562 ModifiedLines: []int{},
563 Rule: mustParse(1, "- alert: rule2\n expr: sum(foo) by(job)\n"),
564 },
565 {
566 State: discovery.Removed,
567 ReportedPath: "rules.yml",
568 SourcePath: "rules.yml",
569 ModifiedLines: []int{2, 3},
570 Rule: mustParse(1, "- alert: rule1\n expr: sum(foo) by(job)\n"),
571 },
572 },
573 },
574 {
575 title: "rule removed - tail",
576 setup: func(t *testing.T) {
577 commitFile(t, "rules.yml", `
578- alert: rule1
579 expr: sum(foo) by(job)
580- alert: rule2
581 expr: sum(foo) by(job)
582`, "v1")
583
584 _, err := git.RunGit("checkout", "-b", "v2")
585 require.NoError(t, err, "git checkout v2")
586
587 commitFile(t, "rules.yml", `
588- alert: rule1
589 expr: sum(foo) by(job)
590`, "v2")
591 },
592 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
593 entries: []discovery.Entry{
594 {
595 State: discovery.Excluded,
596 ReportedPath: "rules.yml",
597 SourcePath: "rules.yml",
598 ModifiedLines: []int{},
599 Rule: mustParse(1, "- alert: rule1\n expr: sum(foo) by(job)\n"),
600 },
601 {
602 State: discovery.Removed,
603 ReportedPath: "rules.yml",
604 SourcePath: "rules.yml",
605 ModifiedLines: []int{4, 5},
606 Rule: mustParse(3, "- alert: rule2\n expr: sum(foo) by(job)\n"),
607 },
608 },
609 },
610 {
611 title: "rule removed - middle",
612 setup: func(t *testing.T) {
613 commitFile(t, "rules.yml", `
614- alert: rule1
615 expr: sum(foo) by(job)
616- alert: rule2
617 expr: sum(foo) by(job)
618- alert: rule3
619 expr: sum(foo) by(job)
620`, "v1")
621
622 _, err := git.RunGit("checkout", "-b", "v2")
623 require.NoError(t, err, "git checkout v2")
624
625 commitFile(t, "rules.yml", `
626- alert: rule1
627 expr: sum(foo) by(job)
628- alert: rule3
629 expr: sum(foo) by(job)
630`, "v2")
631 },
632 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
633 entries: []discovery.Entry{
634 {
635 State: discovery.Excluded,
636 ReportedPath: "rules.yml",
637 SourcePath: "rules.yml",
638 ModifiedLines: []int{},
639 Rule: mustParse(1, "- alert: rule1\n expr: sum(foo) by(job)\n"),
640 },
641 {
642 State: discovery.Excluded,
643 ReportedPath: "rules.yml",
644 SourcePath: "rules.yml",
645 ModifiedLines: []int{},
646 Rule: mustParse(3, "- alert: rule3\n expr: sum(foo) by(job)\n"),
647 },
648 {
649 State: discovery.Removed,
650 ReportedPath: "rules.yml",
651 SourcePath: "rules.yml",
652 ModifiedLines: []int{4, 5},
653 Rule: mustParse(3, "- alert: rule2\n expr: sum(foo) by(job)\n"),
654 },
655 },
656 },
657 {
658 title: "rule fixed",
659 setup: func(t *testing.T) {
660 commitFile(t, "rules.yml", `
661groups:
662- name: v1
663 rules:
664 - record: up:count
665 expr: count(up)
666 expr: sum(up)
667`, "v1")
668
669 _, err := git.RunGit("checkout", "-b", "v2")
670 require.NoError(t, err, "git checkout v2")
671
672 commitFile(t, "rules.yml", `
673groups:
674- name: v2
675 rules:
676 - record: up:count
677 expr: count(up)
678`, "v2")
679 },
680 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, nil), "main", 4),
681 entries: []discovery.Entry{
682 {
683 State: discovery.Added,
684 ReportedPath: "rules.yml",
685 SourcePath: "rules.yml",
686 ModifiedLines: nil,
687 Rule: mustParse(4, "- record: up:count\n expr: count(up)\n"),
688 },
689 {
690 State: discovery.Removed,
691 ReportedPath: "rules.yml",
692 SourcePath: "rules.yml",
693 ModifiedLines: []int{3},
694 PathError: mustErr(`
695groups:
696- name: v2
697 rules:
698 - record: up:count
699 expr: count(up)
700 expr: sum(up)
701`),
702 },
703 },
704 },
705 {
706 title: "rules duplicated",
707 setup: func(t *testing.T) {
708 commitFile(t, "rules.yml", `
709- alert: rule1
710 expr: sum(foo) by(job)
711- alert: rule2
712 expr: sum(foo) by(job)
713`, "v1")
714
715 _, err := git.RunGit("checkout", "-b", "v2")
716 require.NoError(t, err, "git checkout v2")
717
718 commitFile(t, "rules.yml", `
719- alert: rule1
720 expr: sum(foo) by(job)
721- alert: rule2
722 expr: sum(foo) by(job)
723- alert: rule2
724 expr: sum(foo) by(job)
725- alert: rule1
726 expr: sum(foo) by(job)
727`, "v2")
728 },
729 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
730 entries: []discovery.Entry{
731 {
732 State: discovery.Excluded,
733 ReportedPath: "rules.yml",
734 SourcePath: "rules.yml",
735 ModifiedLines: []int{},
736 Rule: mustParse(1, "- alert: rule1\n expr: sum(foo) by(job)\n"),
737 },
738 {
739 State: discovery.Excluded,
740 ReportedPath: "rules.yml",
741 SourcePath: "rules.yml",
742 ModifiedLines: []int{},
743 Rule: mustParse(3, "- alert: rule2\n expr: sum(foo) by(job)\n"),
744 },
745 {
746 State: discovery.Added,
747 ReportedPath: "rules.yml",
748 SourcePath: "rules.yml",
749 ModifiedLines: []int{6, 7},
750 Rule: mustParse(5, "- alert: rule2\n expr: sum(foo) by(job)\n"),
751 },
752 {
753 State: discovery.Added,
754 ReportedPath: "rules.yml",
755 SourcePath: "rules.yml",
756 ModifiedLines: []int{8, 9},
757 Rule: mustParse(7, "- alert: rule1\n expr: sum(foo) by(job)\n"),
758 },
759 },
760 },
761 {
762 title: "rules duplicated with different query",
763 setup: func(t *testing.T) {
764 commitFile(t, "rules.yml", `
765- alert: rule1
766 expr: sum(foo) by(job)
767`, "v1")
768
769 _, err := git.RunGit("checkout", "-b", "v2")
770 require.NoError(t, err, "git checkout v2")
771
772 commitFile(t, "rules.yml", `
773- alert: rule1
774 expr: up == 0
775- alert: rule1
776 expr: up == 1
777- alert: rule1
778 expr: up != 0
779- alert: rule2
780 expr: sum(foo) by(job)
781`, "v2")
782 },
783 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
784 entries: []discovery.Entry{
785 {
786 State: discovery.Modified,
787 ReportedPath: "rules.yml",
788 SourcePath: "rules.yml",
789 ModifiedLines: []int{3},
790 Rule: mustParse(1, "- alert: rule1\n expr: up == 0\n"),
791 },
792 {
793 State: discovery.Added,
794 ReportedPath: "rules.yml",
795 SourcePath: "rules.yml",
796 ModifiedLines: []int{4, 5},
797 Rule: mustParse(3, "- alert: rule1\n expr: up == 1\n"),
798 },
799 {
800 State: discovery.Added,
801 ReportedPath: "rules.yml",
802 SourcePath: "rules.yml",
803 ModifiedLines: []int{6, 7},
804 Rule: mustParse(5, "- alert: rule1\n expr: up != 0\n"),
805 },
806 {
807 State: discovery.Added,
808 ReportedPath: "rules.yml",
809 SourcePath: "rules.yml",
810 ModifiedLines: []int{8},
811 Rule: mustParse(7, "- alert: rule2\n expr: sum(foo) by(job)\n"),
812 },
813 },
814 },
815 {
816 title: "rule changed - modified for and added extra lines",
817 setup: func(t *testing.T) {
818 commitFile(t, "rules.yml", `
819- alert: rule1
820 expr: sum(foo) by(job)
821 for: 1s
822- alert: rule2
823 expr: sum(foo) by(job)
824 for: 1s
825`, "v1")
826
827 _, err := git.RunGit("checkout", "-b", "v2")
828 require.NoError(t, err, "git checkout v2")
829
830 commitFile(t, "rules.yml", `
831- alert: rule1
832 expr: sum(foo) by(job)
833 for: 1s
834- alert: rule2
835 expr: sum(foo) by(job)
836 keep_firing_for: 5m
837 for: 0s
838 annotations:
839 foo: bar
840 labels:
841 foo: bar
842`, "v2")
843 },
844 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
845 entries: []discovery.Entry{
846 {
847 State: discovery.Excluded,
848 ReportedPath: "rules.yml",
849 SourcePath: "rules.yml",
850 ModifiedLines: []int{},
851 Rule: mustParse(1, "- alert: rule1\n expr: sum(foo) by(job)\n for: 1s\n"),
852 },
853 {
854 State: discovery.Modified,
855 ReportedPath: "rules.yml",
856 SourcePath: "rules.yml",
857 ModifiedLines: []int{7, 8, 9, 10, 11, 12},
858 Rule: mustParse(4, "- alert: rule2\n expr: sum(foo) by(job)\n keep_firing_for: 5m\n for: 0s\n annotations:\n foo: bar\n labels:\n foo: bar\n"),
859 },
860 },
861 },
862 {
863 title: "rule file moved",
864 setup: func(t *testing.T) {
865 commitFile(t, "a.yml", `
866- alert: rule
867 expr: up == 0
868`, "v1")
869
870 _, err := git.RunGit("checkout", "-b", "v2")
871 require.NoError(t, err, "git checkout v2")
872
873 _, err = git.RunGit("mv", "a.yml", "b.yml")
874 require.NoError(t, err, "git mv")
875
876 gitCommit(t, "v2")
877 },
878 finder: discovery.NewGitBranchFinder(git.RunGit, git.NewPathFilter(includeAll, nil, includeAll), "main", 4),
879 entries: []discovery.Entry{
880 {
881 State: discovery.Moved,
882 ReportedPath: "b.yml",
883 SourcePath: "b.yml",
884 ModifiedLines: []int{1, 2, 3},
885 Rule: mustParse(1, "- alert: rule\n expr: up == 0\n"),
886 },
887 },
888 },
889 }
890
891 for _, tc := range testCases {
892 t.Run(tc.title, func(t *testing.T) {
893 dir := t.TempDir()
894 err := os.Chdir(dir)
895 require.NoError(t, err, "chdir")
896
897 _, err = git.RunGit("init", "--initial-branch=main", ".")
898 require.NoError(t, err, "git init")
899
900 tc.setup(t)
901 entries, err := tc.finder.Find(nil)
902 if tc.err != "" {
903 require.EqualError(t, err, tc.err)
904 } else {
905 require.NoError(t, err, "tc.finder.Find()")
906
907 expected, err := json.MarshalIndent(tc.entries, "", " ")
908 require.NoError(t, err, "json(expected)")
909 got, err := json.MarshalIndent(entries, "", " ")
910 require.NoError(t, err, "json(got)")
911 if diff := cmp.Diff(string(expected), string(got)); diff != "" {
912 t.Errorf("tc.finder.Find()() returned wrong output (-want +got):\n%s", diff)
913 return
914 }
915 }
916 })
917 }
918}
919