cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.83.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models_test.go

529lines · modecode

1package parser_test
2
3import (
4 "errors"
5 "strconv"
6 "strings"
7 "testing"
8
9 "github.com/stretchr/testify/require"
10
11 "github.com/cloudflare/pint/internal/diags"
12 "github.com/cloudflare/pint/internal/parser"
13)
14
15func newMustRule(content string) parser.Rule {
16 p := parser.NewParser(parser.DefaultOptions)
17 file := p.Parse(strings.NewReader(content))
18 if file.Error.Err != nil {
19 panic(file.Error.Err)
20 }
21 for _, group := range file.Groups {
22 for _, rule := range group.Rules {
23 return rule
24 }
25 }
26 return parser.Rule{}
27}
28
29func TestRuleIsIdentical(t *testing.T) {
30 type testCaseT struct {
31 a parser.Rule
32 b parser.Rule
33 equal bool
34 }
35
36 testCases := []testCaseT{
37 {
38 a: parser.Rule{},
39 b: parser.Rule{},
40 equal: true,
41 },
42 {
43 a: newMustRule("- record: foo\n expr: bob\n"),
44 b: newMustRule("- record: foo\n expr: bob\n"),
45 equal: true,
46 },
47 {
48 a: newMustRule("- record: bob\n expr: bob\n"),
49 b: newMustRule("- record: foo\n expr: bob\n"),
50 equal: false,
51 },
52 {
53 a: newMustRule("- record: foo\n expr: bob\n"),
54 b: newMustRule("- record: foo\n expr: bob\n labels: {}\n"),
55 equal: true,
56 },
57 {
58 a: newMustRule("- record: foo\n expr: bob\n labels: {}\n"),
59 b: newMustRule("- record: foo\n expr: bob\n"),
60 equal: true,
61 },
62 {
63 a: newMustRule("- record: foo\n expr: bob\n"),
64 b: newMustRule("- expr: bob\n record: foo\n"),
65 equal: true,
66 },
67 {
68 a: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n"),
69 b: newMustRule("- record: foo\n expr: bob\n"),
70 equal: false,
71 },
72 {
73 a: newMustRule("- record: foo\n expr: bob\n"),
74 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n"),
75 equal: false,
76 },
77 {
78 a: newMustRule("- record: foo\n expr: bob\n labels:\n bar: bar\n"),
79 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n"),
80 equal: false,
81 },
82 {
83 a: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n extra: foo\n"),
84 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n"),
85 equal: false,
86 },
87 {
88 a: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n extra: foo\n"),
89 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n extra: bar\n"),
90 equal: false,
91 },
92 {
93 a: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n abc: foo\n"),
94 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n cba: foo\n"),
95 equal: false,
96 },
97 {
98 a: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n"),
99 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n extra: foo\n"),
100 equal: false,
101 },
102 {
103 a: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n extra: foo\n"),
104 b: newMustRule("- record: foo\n expr: bob\n labels:\n foo: bar\n extra: bar\n"),
105 equal: false,
106 },
107 {
108 a: newMustRule("- record: foo\n expr: bob\n"),
109 b: newMustRule("- alert: foo\n expr: bob\n"),
110 equal: false,
111 },
112 {
113 a: newMustRule("- record: foo\n expr: bob\n"),
114 b: newMustRule("- record: foo\n xxx: bob\n"),
115 equal: false,
116 },
117 {
118 a: newMustRule("- record: foo\n expr: bob\n"),
119 b: newMustRule("- record: foo\n expr: bob == 0\n"),
120 equal: false,
121 },
122 {
123 a: newMustRule("- alert: foo\n expr: bob\n"),
124 b: newMustRule("- alert: foo\n expr: bob\n for: 4m\n"),
125 equal: false,
126 },
127 {
128 a: newMustRule("- alert: foo\n expr: bob\n"),
129 b: newMustRule("- record: foo\n expr: bob\n"),
130 equal: false,
131 },
132 {
133 a: newMustRule("- alert: foo\n expr: bob\n"),
134 b: newMustRule("- alert: foo\n expr: bob\n"),
135 equal: true,
136 },
137 {
138 a: newMustRule("- alert: foo\n expr: bob\n"),
139 b: newMustRule("- alert: foo\n expr: bob(\n"),
140 equal: false,
141 },
142 {
143 a: newMustRule("- alert: foo\n expr: bob\n"),
144 b: newMustRule("- alert: foo1\n expr: bob\n"),
145 equal: false,
146 },
147 {
148 a: newMustRule("- alert: foo\n expr: bob\n"),
149 b: newMustRule("- alert: foo\n expr: bob1\n"),
150 equal: false,
151 },
152 {
153 a: newMustRule("- alert: foo\n expr: bob\n for: 4m\n"),
154 b: newMustRule("- alert: foo\n expr: bob\n for: 5m\n"),
155 equal: false,
156 },
157 {
158 a: newMustRule("- alert: foo\n expr: bob\n for: 4m\n"),
159 b: newMustRule("- alert: foo\n expr: bob\n keep_firing_for: 4m\n"),
160 equal: false,
161 },
162 {
163 a: newMustRule("- alert: foo\n expr: bob\n keep_firing_for: 4m\n"),
164 b: newMustRule("- alert: foo\n expr: bob\n for: 4m\n"),
165 equal: false,
166 },
167 {
168 a: newMustRule("- alert: foo\n expr: bob\n keep_firing_for: 3m\n"),
169 b: newMustRule("- alert: foo\n expr: bob\n keep_firing_for: 4m\n"),
170 equal: false,
171 },
172 {
173 a: newMustRule("- alert: foo\n expr: bob\n"),
174 b: newMustRule("- alert: foo\n expr: bob\n labels:\n foo: bar\n"),
175 equal: false,
176 },
177 {
178 a: newMustRule("- alert: foo\n expr: bob\n labels:\n bar: bar\n"),
179 b: newMustRule("- alert: foo\n expr: bob\n labels:\n foo: bar\n"),
180 equal: false,
181 },
182 {
183 a: newMustRule("- alert: foo\n expr: bob\n"),
184 b: newMustRule("- alert: foo\n expr: bob\n annotations:\n foo: bar\n"),
185 equal: false,
186 },
187 {
188 a: newMustRule("- alert: foo\n expr: bob\n annotations:\n bar: bar\n"),
189 b: newMustRule("- alert: foo\n expr: bob\n annotations:\n foo: bar\n"),
190 equal: false,
191 },
192 {
193 a: newMustRule("- alert: foo\n # pint disable promql/series\n expr: bob\n"),
194 b: newMustRule("- alert: foo\n expr: bob\n"),
195 equal: false,
196 },
197 {
198 a: newMustRule("- alert: foo\n expr: bob\n"),
199 b: newMustRule("- alert: foo\n # pint disable promql/series\n expr: bob\n"),
200 equal: false,
201 },
202 {
203 a: newMustRule("- record: colo:labels:equal\n expr: sum(foo) without(job)\n labels:\n same: yes\n"),
204 b: newMustRule("- record: colo:labels:equal\n expr: sum(foo) without(job)\n labels:\n same: yes\n"),
205 equal: true,
206 },
207 {
208 a: newMustRule("- record: foo\n expr: sum(foo)\n labels:\n same: yes\n a: b\n d: c\n"),
209 b: newMustRule("- record: foo\n expr: sum(foo)\n labels:\n same: yes\n a: b\n c: d\n"),
210 equal: false,
211 },
212 }
213
214 for i, tc := range testCases {
215 t.Run(strconv.Itoa(i+1), func(t *testing.T) {
216 equal := tc.a.IsIdentical(tc.b)
217 require.Equal(t, tc.equal, equal, tc.a)
218 })
219 }
220}
221
222func TestRuleIsSame(t *testing.T) {
223 type testCaseT struct {
224 a parser.Rule
225 b parser.Rule
226 same bool
227 }
228
229 testCases := []testCaseT{
230 // Both empty rules
231 {
232 a: parser.Rule{},
233 b: parser.Rule{},
234 same: true,
235 },
236 // Different rule types (alerting vs recording)
237 {
238 a: newMustRule("- alert: foo\n expr: bob\n"),
239 b: newMustRule("- record: foo\n expr: bob\n"),
240 same: false,
241 },
242 // Different rule types (recording vs alerting)
243 {
244 a: newMustRule("- record: foo\n expr: bob\n"),
245 b: newMustRule("- alert: foo\n expr: bob\n"),
246 same: false,
247 },
248 // One has RecordingRule, other has neither (AlertingRule matches as nil)
249 {
250 a: parser.Rule{
251 RecordingRule: &parser.RecordingRule{},
252 },
253 b: parser.Rule{},
254 same: false,
255 },
256 // Same alerting rules
257 {
258 a: newMustRule("- alert: foo\n expr: bob\n"),
259 b: newMustRule("- alert: foo\n expr: bob\n"),
260 same: true,
261 },
262 // Same recording rules
263 {
264 a: newMustRule("- record: foo\n expr: bob\n"),
265 b: newMustRule("- record: foo\n expr: bob\n"),
266 same: true,
267 },
268 // Different line ranges - First line differs
269 {
270 a: parser.Rule{
271 Lines: diags.LineRange{First: 1, Last: 3},
272 },
273 b: parser.Rule{
274 Lines: diags.LineRange{First: 2, Last: 3},
275 },
276 same: false,
277 },
278 // Different line ranges - Last line differs
279 {
280 a: parser.Rule{
281 Lines: diags.LineRange{First: 1, Last: 3},
282 },
283 b: parser.Rule{
284 Lines: diags.LineRange{First: 1, Last: 4},
285 },
286 same: false,
287 },
288 // Different error lines
289 {
290 a: parser.Rule{
291 Error: parser.ParseError{Line: 1, Err: nil},
292 },
293 b: parser.Rule{
294 Error: parser.ParseError{Line: 2, Err: nil},
295 },
296 same: false,
297 },
298 // Different error values
299 {
300 a: parser.Rule{
301 Error: parser.ParseError{
302 Line: 1,
303 Err: errors.New("foo"),
304 },
305 },
306 b: parser.Rule{
307 Error: parser.ParseError{
308 Line: 1,
309 Err: errors.New("bar"),
310 },
311 },
312 same: false,
313 },
314 }
315
316 for i, tc := range testCases {
317 t.Run(strconv.Itoa(i+1), func(t *testing.T) {
318 same := tc.a.IsSame(tc.b)
319 require.Equal(t, tc.same, same)
320 })
321 }
322}
323
324func TestRuleLastKey(t *testing.T) {
325 type testCaseT struct {
326 expectedKey string
327 rule parser.Rule
328 expectedLine int
329 }
330
331 testCases := []testCaseT{
332 // Recording rule - record is last key
333 {
334 rule: newMustRule("- record: foo\n expr: bob\n"),
335 expectedKey: "bob",
336 expectedLine: 2,
337 },
338 // Recording rule - expr is last (comes after record in YAML)
339 {
340 rule: newMustRule("- expr: bob\n record: foo\n"),
341 expectedKey: "foo",
342 expectedLine: 2,
343 },
344 // Recording rule with labels - label key is last
345 {
346 rule: newMustRule("- record: foo\n expr: bob\n labels:\n severity: critical\n"),
347 expectedKey: "severity",
348 expectedLine: 4,
349 },
350 // Alerting rule - alert is last key
351 {
352 rule: newMustRule("- alert: foo\n expr: bob\n"),
353 expectedKey: "bob",
354 expectedLine: 2,
355 },
356 // Alerting rule with for
357 {
358 rule: newMustRule("- alert: foo\n expr: bob\n for: 5m\n"),
359 expectedKey: "5m",
360 expectedLine: 3,
361 },
362 // Alerting rule with keep_firing_for
363 {
364 rule: newMustRule("- alert: foo\n expr: bob\n keep_firing_for: 10m\n"),
365 expectedKey: "10m",
366 expectedLine: 3,
367 },
368 // Alerting rule with labels
369 {
370 rule: newMustRule("- alert: foo\n expr: bob\n labels:\n severity: critical\n"),
371 expectedKey: "severity",
372 expectedLine: 4,
373 },
374 // Alerting rule with annotations
375 {
376 rule: newMustRule("- alert: foo\n expr: bob\n annotations:\n summary: test\n"),
377 expectedKey: "summary",
378 expectedLine: 4,
379 },
380 // Alerting rule with both labels and annotations - annotations last
381 {
382 rule: newMustRule("- alert: foo\n expr: bob\n labels:\n severity: critical\n annotations:\n summary: test\n"),
383 expectedKey: "summary",
384 expectedLine: 6,
385 },
386 // Alerting rule with for, keep_firing_for, labels, annotations - annotations last
387 {
388 rule: newMustRule("- alert: foo\n expr: bob\n for: 5m\n keep_firing_for: 10m\n labels:\n severity: critical\n annotations:\n summary: test\n"),
389 expectedKey: "summary",
390 expectedLine: 8,
391 },
392 }
393
394 for i, tc := range testCases {
395 t.Run(strconv.Itoa(i+1), func(t *testing.T) {
396 lastKey := tc.rule.LastKey()
397 require.NotNil(t, lastKey)
398 require.Equal(t, tc.expectedKey, lastKey.Value)
399 require.Equal(t, tc.expectedLine, lastKey.Pos.Lines().Last)
400 })
401 }
402}
403
404func TestAlertingRuleIsIdenticalNilCases(t *testing.T) {
405 // Both nil
406 var nilA *parser.AlertingRule
407 var nilB *parser.AlertingRule
408 require.True(t, nilA.IsIdentical(nilB))
409
410 // One nil, one not
411 rule := newMustRule("- alert: foo\n expr: bob\n")
412 require.False(t, nilA.IsIdentical(rule.AlertingRule))
413 require.False(t, rule.AlertingRule.IsIdentical(nilB))
414}
415
416func TestRecordingRuleIsIdenticalNilCases(t *testing.T) {
417 // Both nil
418 var nilA *parser.RecordingRule
419 var nilB *parser.RecordingRule
420 require.True(t, nilA.IsIdentical(nilB))
421
422 // One nil, one not
423 rule := newMustRule("- record: foo\n expr: bob\n")
424 require.False(t, nilA.IsIdentical(rule.RecordingRule))
425 require.False(t, rule.RecordingRule.IsIdentical(nilB))
426}
427
428func TestYamlNodeIsIdentical(t *testing.T) {
429 type testCaseT struct {
430 a *parser.YamlNode
431 b *parser.YamlNode
432 equal bool
433 }
434
435 testCases := []testCaseT{
436 // Both nil
437 {a: nil, b: nil, equal: true},
438 // One nil, one not
439 {a: nil, b: &parser.YamlNode{Value: "foo"}, equal: false},
440 {a: &parser.YamlNode{Value: "foo"}, b: nil, equal: false},
441 // Both non-nil, same value
442 {a: &parser.YamlNode{Value: "foo"}, b: &parser.YamlNode{Value: "foo"}, equal: true},
443 // Both non-nil, different value
444 {a: &parser.YamlNode{Value: "foo"}, b: &parser.YamlNode{Value: "bar"}, equal: false},
445 }
446
447 for i, tc := range testCases {
448 t.Run(strconv.Itoa(i+1), func(t *testing.T) {
449 equal := tc.a.IsIdentical(tc.b)
450 require.Equal(t, tc.equal, equal)
451 })
452 }
453}
454
455func TestMergeMaps(t *testing.T) {
456 type testCaseT struct {
457 a *parser.YamlMap
458 b *parser.YamlMap
459 output *parser.YamlMap
460 }
461
462 testCases := []testCaseT{
463 {
464 a: nil,
465 b: nil,
466 output: nil,
467 },
468 {
469 a: &parser.YamlMap{},
470 b: nil,
471 output: &parser.YamlMap{},
472 },
473 {
474 a: nil,
475 b: &parser.YamlMap{},
476 output: &parser.YamlMap{},
477 },
478 {
479 a: &parser.YamlMap{},
480 b: &parser.YamlMap{},
481 output: &parser.YamlMap{},
482 },
483 {
484 a: &parser.YamlMap{
485 Key: &parser.YamlNode{Value: "a"},
486 Items: []*parser.YamlKeyValue{
487 {
488 Key: &parser.YamlNode{Value: "1"},
489 },
490 {
491 Key: &parser.YamlNode{Value: "2"},
492 },
493 },
494 },
495 b: &parser.YamlMap{
496 Key: &parser.YamlNode{Value: "b"},
497 Items: []*parser.YamlKeyValue{
498 {
499 Key: &parser.YamlNode{Value: "2"},
500 },
501 {
502 Key: &parser.YamlNode{Value: "3"},
503 },
504 },
505 },
506 output: &parser.YamlMap{
507 Key: &parser.YamlNode{Value: "a"},
508 Items: []*parser.YamlKeyValue{
509 {
510 Key: &parser.YamlNode{Value: "1"},
511 },
512 {
513 Key: &parser.YamlNode{Value: "2"},
514 },
515 {
516 Key: &parser.YamlNode{Value: "3"},
517 },
518 },
519 },
520 },
521 }
522
523 for i, tc := range testCases {
524 t.Run(strconv.Itoa(i+1), func(t *testing.T) {
525 output := parser.MergeMaps(tc.a, tc.b)
526 require.Equal(t, tc.output, output)
527 })
528 }
529}
530