cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.71.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/discovery/discovery_test.go

375lines · modecode

1package discovery
2
3import (
4 "bytes"
5 "encoding/json"
6 "fmt"
7 "io"
8 "strings"
9 "testing"
10
11 "github.com/prometheus/common/model"
12 "github.com/stretchr/testify/require"
13
14 "github.com/cloudflare/pint/internal/diags"
15 "github.com/cloudflare/pint/internal/parser"
16)
17
18type failingReader struct {
19 err error
20}
21
22func (r failingReader) Read(_ []byte) (int, error) {
23 return 0, r.err
24}
25
26func TestReadRules(t *testing.T) {
27 mustParse := func(offset int, s string) parser.Rule {
28 p := parser.NewParser(false, parser.PrometheusSchema, model.UTF8Validation)
29 r, err := p.Parse([]byte(strings.Repeat("\n", offset) + s))
30 if err != nil {
31 panic(fmt.Sprintf("failed to parse rule:\n---\n%s\n---\nerror: %s", s, err))
32 }
33 if len(r) != 1 {
34 panic(fmt.Sprintf("wrong number of rules returned: %d\n---\n%s\n---", len(r), s))
35 }
36 return r[0]
37 }
38
39 type testCaseT struct {
40 sourceFunc func(t *testing.T) io.Reader
41 title string
42 reportedPath string
43 sourcePath string
44 err string
45 entries []Entry
46 isStrict bool
47 }
48
49 testCases := []testCaseT{
50 {
51 title: "nil input",
52 reportedPath: "rules.yml",
53 sourcePath: "rules.yml",
54 sourceFunc: func(_ *testing.T) io.Reader {
55 return bytes.NewBuffer(nil)
56 },
57 isStrict: false,
58 },
59 {
60 title: "nil input",
61 reportedPath: "rules.yml",
62 sourcePath: "rules.yml",
63 sourceFunc: func(_ *testing.T) io.Reader {
64 return bytes.NewBuffer(nil)
65 },
66 isStrict: true,
67 },
68 {
69 title: "empty input",
70 reportedPath: "rules.yml",
71 sourcePath: "rules.yml",
72 sourceFunc: func(_ *testing.T) io.Reader {
73 return bytes.NewBuffer([]byte(" "))
74 },
75 isStrict: false,
76 },
77 {
78 title: "empty input",
79 reportedPath: "rules.yml",
80 sourcePath: "rules.yml",
81 sourceFunc: func(_ *testing.T) io.Reader {
82 return bytes.NewBuffer([]byte(" "))
83 },
84 isStrict: true,
85 },
86 {
87 title: "reader error",
88 reportedPath: "rules.yml",
89 sourcePath: "rules.yml",
90 sourceFunc: func(_ *testing.T) io.Reader {
91 return failingReader{
92 err: io.ErrClosedPipe,
93 }
94 },
95 isStrict: false,
96 err: io.ErrClosedPipe.Error(),
97 },
98 {
99 title: "reader error",
100 reportedPath: "rules.yml",
101 sourcePath: "rules.yml",
102 sourceFunc: func(_ *testing.T) io.Reader {
103 return failingReader{
104 err: io.ErrClosedPipe,
105 }
106 },
107 isStrict: true,
108 err: io.ErrClosedPipe.Error(),
109 },
110 {
111 title: "no rules, just a comment",
112 reportedPath: "rules.yml",
113 sourcePath: "rules.yml",
114 sourceFunc: func(_ *testing.T) io.Reader {
115 return bytes.NewBuffer([]byte("\n\n # pint file/disable xxx \n\n"))
116 },
117 isStrict: false,
118 },
119 {
120 title: "file/disable comment",
121 reportedPath: "rules.yml",
122 sourcePath: "rules.yml",
123 sourceFunc: func(_ *testing.T) io.Reader {
124 return bytes.NewBuffer([]byte(`
125# pint file/disable promql/series
126
127- record: foo
128 expr: bar
129`))
130 },
131 isStrict: false,
132 entries: []Entry{
133 {
134 State: Unknown,
135 Path: Path{
136 Name: "rules.yml",
137 SymlinkTarget: "rules.yml",
138 },
139 ModifiedLines: []int{4, 5},
140 Rule: mustParse(3, "- record: foo\n expr: bar\n"),
141 DisabledChecks: []string{"promql/series"},
142 },
143 },
144 },
145 {
146 title: "file/disable comment",
147 reportedPath: "rules.yml",
148 sourcePath: "rules.yml",
149 sourceFunc: func(_ *testing.T) io.Reader {
150 return bytes.NewBuffer([]byte(`
151# pint file/disable promql/series
152
153groups:
154- name: foo
155 rules:
156 - record: foo
157 expr: bar
158`))
159 },
160 isStrict: true,
161 entries: []Entry{
162 {
163 State: Unknown,
164 Path: Path{
165 Name: "rules.yml",
166 SymlinkTarget: "rules.yml",
167 },
168 ModifiedLines: []int{7, 8},
169 Rule: mustParse(6, " - record: foo\n expr: bar\n"),
170 DisabledChecks: []string{"promql/series"},
171 },
172 },
173 },
174 {
175 title: "single expired snooze comment",
176 reportedPath: "rules.yml",
177 sourcePath: "rules.yml",
178 sourceFunc: func(_ *testing.T) io.Reader {
179 return bytes.NewBuffer([]byte(`
180# pint file/snooze 2000-01-01T00:00:00Z promql/series
181
182- record: foo
183 expr: bar
184`))
185 },
186 isStrict: false,
187 entries: []Entry{
188 {
189 State: Unknown,
190 Path: Path{
191 Name: "rules.yml",
192 SymlinkTarget: "rules.yml",
193 },
194 ModifiedLines: []int{4, 5},
195 Rule: mustParse(3, "- record: foo\n expr: bar\n"),
196 },
197 },
198 },
199 {
200 title: "single expired snooze comment",
201 reportedPath: "rules.yml",
202 sourcePath: "rules.yml",
203 sourceFunc: func(_ *testing.T) io.Reader {
204 return bytes.NewBuffer([]byte(`
205# pint file/snooze 2000-01-01T00:00:00Z promql/series
206
207groups:
208- name: foo
209 rules:
210 - record: foo
211 expr: bar
212`))
213 },
214 isStrict: true,
215 entries: []Entry{
216 {
217 State: Unknown,
218 Path: Path{
219 Name: "rules.yml",
220 SymlinkTarget: "rules.yml",
221 },
222 ModifiedLines: []int{7, 8},
223 Rule: mustParse(6, " - record: foo\n expr: bar\n"),
224 },
225 },
226 },
227 {
228 title: "single valid snooze comment",
229 reportedPath: "rules.yml",
230 sourcePath: "rules.yml",
231 sourceFunc: func(_ *testing.T) io.Reader {
232 return bytes.NewBuffer([]byte(`
233# pint file/snooze 2099-01-01T00:00:00Z promql/series
234
235- record: foo
236 expr: bar
237`))
238 },
239 isStrict: false,
240 entries: []Entry{
241 {
242 State: Unknown,
243 Path: Path{
244 Name: "rules.yml",
245 SymlinkTarget: "rules.yml",
246 },
247 ModifiedLines: []int{4, 5},
248 Rule: mustParse(3, "- record: foo\n expr: bar\n"),
249 DisabledChecks: []string{"promql/series"},
250 },
251 },
252 },
253 {
254 title: "single valid snooze comment",
255 reportedPath: "rules.yml",
256 sourcePath: "rules.yml",
257 sourceFunc: func(_ *testing.T) io.Reader {
258 return bytes.NewBuffer([]byte(`
259# pint file/snooze 2099-01-01T00:00:00Z promql/series
260
261groups:
262- name: foo
263 rules:
264 - record: foo
265 expr: bar
266`))
267 },
268 isStrict: true,
269 entries: []Entry{
270 {
271 State: Unknown,
272 Path: Path{
273 Name: "rules.yml",
274 SymlinkTarget: "rules.yml",
275 },
276 ModifiedLines: []int{7, 8},
277 Rule: mustParse(6, " - record: foo\n expr: bar\n"),
278 DisabledChecks: []string{"promql/series"},
279 },
280 },
281 },
282 {
283 title: "ignore/file",
284 reportedPath: "rules.yml",
285 sourcePath: "rules.yml",
286 sourceFunc: func(_ *testing.T) io.Reader {
287 return bytes.NewBuffer([]byte(`
288# pint ignore/file
289
290- record: foo
291 expr: bar
292`))
293 },
294 isStrict: false,
295 entries: []Entry{
296 {
297 State: Unknown,
298 Path: Path{
299 Name: "rules.yml",
300 SymlinkTarget: "rules.yml",
301 },
302 ModifiedLines: []int{1, 2, 3, 4, 5},
303 PathError: FileIgnoreError{
304 Diagnostic: diags.Diagnostic{
305 Message: "This file was excluded from pint checks.",
306 Pos: diags.PositionRanges{
307 {Line: 2, FirstColumn: 1, LastColumn: 18},
308 },
309 FirstColumn: 1,
310 LastColumn: 18,
311 },
312 },
313 },
314 },
315 },
316 {
317 title: "ignore/file",
318 reportedPath: "rules.yml",
319 sourcePath: "rules.yml",
320 sourceFunc: func(_ *testing.T) io.Reader {
321 return bytes.NewBuffer([]byte(`
322# pint ignore/file
323
324groups:
325- name: foo
326 rules:
327 - record: foo
328 expr: bar
329`))
330 },
331 isStrict: true,
332 entries: []Entry{
333 {
334 State: Unknown,
335 Path: Path{
336 Name: "rules.yml",
337 SymlinkTarget: "rules.yml",
338 },
339 ModifiedLines: []int{1, 2, 3, 4, 5, 6, 7, 8},
340 PathError: FileIgnoreError{
341 Diagnostic: diags.Diagnostic{
342 Message: "This file was excluded from pint checks.",
343 Pos: diags.PositionRanges{
344 {Line: 2, FirstColumn: 1, LastColumn: 18},
345 },
346 FirstColumn: 1,
347 LastColumn: 18,
348 },
349 },
350 },
351 },
352 },
353 }
354
355 for _, tc := range testCases {
356 t.Run(
357 fmt.Sprintf("rPath=%s sPath=%s strict=%v title=%s", tc.reportedPath, tc.sourcePath, tc.isStrict, tc.title),
358 func(t *testing.T) {
359 r := tc.sourceFunc(t)
360 p := parser.NewParser(tc.isStrict, parser.PrometheusSchema, model.UTF8Validation)
361 entries, err := readRules(tc.reportedPath, tc.sourcePath, r, p, nil)
362 if tc.err != "" {
363 require.EqualError(t, err, tc.err)
364 } else {
365 require.NoError(t, err)
366
367 expected, err := json.MarshalIndent(tc.entries, "", " ")
368 require.NoError(t, err, "json(expected)")
369 got, err := json.MarshalIndent(entries, "", " ")
370 require.NoError(t, err, "json(got)")
371 require.Equal(t, string(expected), string(got))
372 }
373 })
374 }
375}
376