cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.79.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/discovery/glob_test.go

421lines · modecode

1package discovery_test
2
3import (
4 "encoding/json"
5 "errors"
6 "os"
7 "path"
8 "regexp"
9 "strconv"
10 "strings"
11 "testing"
12
13 "github.com/prometheus/common/model"
14 "github.com/stretchr/testify/require"
15
16 "github.com/cloudflare/pint/internal/discovery"
17 "github.com/cloudflare/pint/internal/git"
18 "github.com/cloudflare/pint/internal/parser"
19)
20
21func TestGlobPathFinder(t *testing.T) {
22 type testCaseT struct {
23 setup func(t *testing.T)
24 files map[string]string
25 symlinks map[string]string
26 err string
27 entries []*discovery.Entry
28 finder discovery.GlobFinder
29 }
30
31 p := parser.NewParser(false, parser.PrometheusSchema, model.UTF8Validation)
32 testRuleBody := "# pint file/owner bob\n\n- record: foo\n expr: sum(foo)\n"
33 testFile := p.Parse(strings.NewReader(testRuleBody))
34 require.NoError(t, testFile.Error.Err)
35
36 testCases := []testCaseT{
37 {
38 files: map[string]string{},
39 finder: discovery.NewGlobFinder([]string{"[]"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
40 err: "failed to expand file path pattern []: syntax error in pattern",
41 },
42 {
43 files: map[string]string{},
44 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
45 err: "no matching files",
46 },
47 {
48 files: map[string]string{
49 ".git/config": "test",
50 "bar.yml": testRuleBody,
51 },
52 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
53 entries: []*discovery.Entry{
54 {
55 State: discovery.Noop,
56 Path: discovery.Path{
57 Name: "bar.yml",
58 SymlinkTarget: "bar.yml",
59 },
60 Rule: testFile.Groups[0].Rules[0],
61 ModifiedLines: testFile.Groups[0].Rules[0].Lines.Expand(),
62 Owner: "bob",
63 },
64 },
65 },
66 {
67 files: map[string]string{
68 "bar.yml": testRuleBody,
69 },
70 symlinks: map[string]string{
71 ".git": "/nonexistent/target",
72 },
73 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
74 err: ".git is a symlink but target file cannot be evaluated: lstat /nonexistent: no such file or directory",
75 },
76 {
77 files: map[string]string{},
78 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
79 err: "no matching files",
80 },
81 {
82 files: map[string]string{},
83 finder: discovery.NewGlobFinder([]string{"foo/*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
84 err: "no matching files",
85 },
86 {
87 files: map[string]string{"bar.yml": testRuleBody},
88 finder: discovery.NewGlobFinder([]string{"foo/*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
89 err: "no matching files",
90 },
91 {
92 files: map[string]string{"bar.yml": testRuleBody},
93 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
94 entries: []*discovery.Entry{
95 {
96 State: discovery.Noop,
97 Path: discovery.Path{
98 Name: "bar.yml",
99 SymlinkTarget: "bar.yml",
100 },
101 Rule: testFile.Groups[0].Rules[0],
102 ModifiedLines: testFile.Groups[0].Rules[0].Lines.Expand(),
103 Owner: "bob",
104 },
105 },
106 },
107 {
108 files: map[string]string{"foo/bar.yml": testRuleBody + "\n\n# pint file/owner alice\n"},
109 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
110 entries: []*discovery.Entry{
111 {
112 State: discovery.Noop,
113 Path: discovery.Path{
114 Name: "foo/bar.yml",
115 SymlinkTarget: "foo/bar.yml",
116 },
117 Rule: testFile.Groups[0].Rules[0],
118 ModifiedLines: testFile.Groups[0].Rules[0].Lines.Expand(),
119 Owner: "alice",
120 },
121 },
122 },
123 {
124 files: map[string]string{"bar.yml": testRuleBody},
125 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
126 entries: []*discovery.Entry{
127 {
128 State: discovery.Noop,
129 Path: discovery.Path{
130 Name: "bar.yml",
131 SymlinkTarget: "bar.yml",
132 },
133 PathError: parser.ParseError{
134 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
135 Line: 3,
136 },
137 ModifiedLines: []int{1, 2, 3, 4},
138 Owner: "bob",
139 },
140 },
141 },
142 {
143 files: map[string]string{"bar.yml": "record:::{}\n expr: sum(foo)\n\n# pint file/owner bob\n"},
144 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
145 entries: []*discovery.Entry{
146 {
147 State: discovery.Noop,
148 Path: discovery.Path{
149 Name: "bar.yml",
150 SymlinkTarget: "bar.yml",
151 },
152 PathError: parser.ParseError{
153 Err: errors.New("mapping values are not allowed in this context"),
154 Line: 2,
155 },
156 ModifiedLines: []int{1, 2, 3, 4},
157 Owner: "bob",
158 },
159 },
160 },
161 {
162 files: map[string]string{"bar.yml": testRuleBody},
163 symlinks: map[string]string{"link.yml": "bar.yml"},
164 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
165 entries: []*discovery.Entry{
166 {
167 State: discovery.Noop,
168 Path: discovery.Path{
169 Name: "bar.yml",
170 SymlinkTarget: "bar.yml",
171 },
172 PathError: parser.ParseError{
173 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
174 Line: 3,
175 },
176 ModifiedLines: []int{1, 2, 3, 4},
177 Owner: "bob",
178 },
179 {
180 State: discovery.Noop,
181 Path: discovery.Path{
182 Name: "link.yml",
183 SymlinkTarget: "bar.yml",
184 },
185 PathError: parser.ParseError{
186 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
187 Line: 3,
188 },
189 ModifiedLines: []int{1, 2, 3, 4},
190 Owner: "bob",
191 },
192 },
193 },
194 {
195 files: map[string]string{"a/bar.yml": testRuleBody},
196 symlinks: map[string]string{
197 "b/link.yml": "../a/bar.yml",
198 "b/c/link.yml": "../../a/bar.yml",
199 },
200 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
201 entries: []*discovery.Entry{
202 {
203 State: discovery.Noop,
204 Path: discovery.Path{
205 Name: "a/bar.yml",
206 SymlinkTarget: "a/bar.yml",
207 },
208 PathError: parser.ParseError{
209 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
210 Line: 3,
211 },
212 ModifiedLines: []int{1, 2, 3, 4},
213 Owner: "bob",
214 },
215 {
216 State: discovery.Noop,
217 Path: discovery.Path{
218 Name: "b/c/link.yml",
219 SymlinkTarget: "a/bar.yml",
220 },
221 PathError: parser.ParseError{
222 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
223 Line: 3,
224 },
225 ModifiedLines: []int{1, 2, 3, 4},
226 Owner: "bob",
227 },
228 {
229 State: discovery.Noop,
230 Path: discovery.Path{
231 Name: "b/link.yml",
232 SymlinkTarget: "a/bar.yml",
233 },
234 PathError: parser.ParseError{
235 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
236 Line: 3,
237 },
238 ModifiedLines: []int{1, 2, 3, 4},
239 Owner: "bob",
240 },
241 },
242 },
243 {
244 files: map[string]string{"a/bar.yml": testRuleBody},
245 symlinks: map[string]string{
246 "b/link.yml": "../a/bar.yml",
247 "b/c/link.yml": "../a/bar.yml",
248 },
249 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
250 err: "b/c/link.yml is a symlink but target file cannot be evaluated: lstat b/a: no such file or directory",
251 },
252 {
253 files: map[string]string{"a/bar.yml": "xxx:\n"},
254 symlinks: map[string]string{
255 "b/c/link.yml": "../../a/bar.yml",
256 },
257 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
258 },
259 {
260 files: map[string]string{"a/bar.yml": "xxx:\nyyy:\n"},
261 symlinks: map[string]string{
262 "b/c/link.yml": "../../a/bar.yml",
263 },
264 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
265 entries: []*discovery.Entry{
266 {
267 State: discovery.Noop,
268 Path: discovery.Path{
269 Name: "a/bar.yml",
270 SymlinkTarget: "a/bar.yml",
271 },
272 PathError: parser.ParseError{
273 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
274 Line: 1,
275 },
276 ModifiedLines: []int{1, 2},
277 Owner: "",
278 },
279 {
280 State: discovery.Noop,
281 Path: discovery.Path{
282 Name: "b/c/link.yml",
283 SymlinkTarget: "a/bar.yml",
284 },
285 PathError: parser.ParseError{
286 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
287 Line: 1,
288 },
289 ModifiedLines: []int{1, 2},
290 Owner: "",
291 },
292 },
293 },
294 {
295 files: map[string]string{"a/bar.yml": "xxx:\nyyy:\n"},
296 symlinks: map[string]string{
297 "b/c/link.yml": "../../a/bar.yml",
298 },
299 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
300 },
301 {
302 files: map[string]string{"a/bar.yml": "xxx:\nyyy:\n"},
303 symlinks: map[string]string{
304 "b/c/d": "../../a",
305 },
306 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, []*regexp.Regexp{regexp.MustCompile(".*")}), parser.PrometheusSchema, model.UTF8Validation, nil),
307 },
308 {
309 files: map[string]string{"a/bar.yml": testRuleBody},
310 symlinks: map[string]string{
311 "b/c/link.yml": "../../a/bar.yml",
312 },
313 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
314 entries: []*discovery.Entry{
315 {
316 State: discovery.Noop,
317 Path: discovery.Path{
318 Name: "a/bar.yml",
319 SymlinkTarget: "a/bar.yml",
320 },
321 PathError: parser.ParseError{
322 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
323 Line: 3,
324 },
325 ModifiedLines: []int{1, 2, 3, 4},
326 Owner: "bob",
327 },
328 {
329 State: discovery.Noop,
330 Path: discovery.Path{
331 Name: "b/c/link.yml",
332 SymlinkTarget: "a/bar.yml",
333 },
334 PathError: parser.ParseError{
335 Err: errors.New("YAML list is not allowed here, expected a YAML mapping"),
336 Line: 3,
337 },
338 ModifiedLines: []int{1, 2, 3, 4},
339 Owner: "bob",
340 },
341 },
342 },
343 {
344 symlinks: map[string]string{
345 "input.yml": "/xx/ccc/fdd",
346 },
347 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
348 err: "input.yml is a symlink but target file cannot be evaluated: lstat /xx: no such file or directory",
349 },
350 {
351 files: map[string]string{
352 "bar.yml": testRuleBody,
353 },
354 setup: func(_ *testing.T) {
355 _ = os.Chmod("bar.yml", 0o000)
356 },
357 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
358 err: "open bar.yml: permission denied",
359 },
360 {
361 files: map[string]string{
362 "subdir/bar.yml": testRuleBody,
363 },
364 symlinks: map[string]string{
365 "subdir/broken.yml": "/nonexistent/target",
366 },
367 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
368 err: "subdir/broken.yml is a symlink but target file cannot be evaluated: lstat /nonexistent: no such file or directory",
369 },
370 {
371 files: map[string]string{
372 "subdir/bar.yml": testRuleBody,
373 },
374 setup: func(t *testing.T) {
375 require.NoError(t, os.Chmod("subdir", 0o000))
376 t.Cleanup(func() { _ = os.Chmod("subdir", 0o755) })
377 },
378 finder: discovery.NewGlobFinder([]string{"*"}, git.NewPathFilter(nil, nil, nil), parser.PrometheusSchema, model.UTF8Validation, nil),
379 err: "open subdir: permission denied",
380 },
381 }
382
383 for i, tc := range testCases {
384 t.Run(strconv.Itoa(i), func(t *testing.T) {
385 workdir := t.TempDir()
386 t.Chdir(workdir)
387
388 for p, content := range tc.files {
389 if strings.Contains(p, "/") {
390 err := os.MkdirAll(path.Dir(p), 0o755)
391 require.NoError(t, err)
392 }
393 err := os.WriteFile(p, []byte(content), 0o644)
394 require.NoError(t, err)
395 }
396 for symlink, target := range tc.symlinks {
397 if strings.Contains(symlink, "/") {
398 err := os.MkdirAll(path.Dir(symlink), 0o755)
399 require.NoError(t, err)
400 }
401 require.NoError(t, os.Symlink(target, symlink))
402 }
403 if tc.setup != nil {
404 tc.setup(t)
405 }
406
407 entries, err := tc.finder.Find()
408 if tc.err != "" {
409 require.EqualError(t, err, tc.err)
410 } else {
411 require.NoError(t, err)
412
413 expected, err := json.MarshalIndent(tc.entries, "", " ")
414 require.NoError(t, err, "json(expected)")
415 got, err := json.MarshalIndent(entries, "", " ")
416 require.NoError(t, err, "json(got)")
417 require.Equal(t, string(expected), string(got))
418 }
419 })
420 }
421}
422