cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.80.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/discovery/glob_test.go

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