cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.56.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/reporter/github_test.go

363lines · modecode

1package reporter_test
2
3import (
4 "fmt"
5 "log/slog"
6 "net/http"
7 "net/http/httptest"
8 "testing"
9 "time"
10
11 "github.com/neilotoole/slogt"
12 "github.com/stretchr/testify/require"
13
14 "github.com/cloudflare/pint/internal/checks"
15 "github.com/cloudflare/pint/internal/git"
16 "github.com/cloudflare/pint/internal/parser"
17 "github.com/cloudflare/pint/internal/reporter"
18)
19
20func TestGithubReporter(t *testing.T) {
21 type testCaseT struct {
22 description string
23 reports []reporter.Report
24 httpHandler http.Handler
25 error func(uri string) string
26 gitCmd git.CommandRunner
27
28 owner string
29 repo string
30 token string
31 prNum int
32 timeout time.Duration
33 }
34
35 p := parser.NewParser()
36 mockRules, _ := p.Parse([]byte(`
37- record: target is down
38 expr: up == 0
39- record: sum errors
40 expr: sum(errors) by (job)
41`))
42
43 blameLine := func(sha string, line int, filename, content string) string {
44 return fmt.Sprintf(`%s %d %d 1
45filename %s
46 %s
47`, sha, line, line, filename, content)
48 }
49
50 for _, tc := range []testCaseT{
51 {
52 description: "timeout errors out",
53 owner: "foo",
54 repo: "bar",
55 token: "something",
56 prNum: 123,
57 httpHandler: http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
58 time.Sleep(1 * time.Second)
59 _, _ = w.Write([]byte("OK"))
60 }),
61 timeout: 100 * time.Millisecond,
62 gitCmd: func(args ...string) ([]byte, error) {
63 if args[0] == "rev-parse" {
64 return []byte("fake-commit-id"), nil
65 }
66 if args[0] == "blame" {
67 content := blameLine("fake-commit-id", 2, "foo.txt", "up == 0")
68 return []byte(content), nil
69 }
70 return nil, nil
71 },
72 error: func(_ string) string {
73 return "failed to list pull request reviews: context deadline exceeded"
74 },
75 reports: []reporter.Report{
76 {
77 SourcePath: "foo.txt",
78 ModifiedLines: []int{2},
79 Rule: mockRules[1],
80 Problem: checks.Problem{
81 Lines: parser.LineRange{
82 First: 2,
83 Last: 2,
84 },
85 Reporter: "mock",
86 Text: "syntax error",
87 Severity: checks.Fatal,
88 },
89 },
90 },
91 },
92 {
93 description: "list reviews error",
94 owner: "foo",
95 repo: "bar",
96 token: "something",
97 prNum: 123,
98 timeout: time.Second,
99 gitCmd: func(args ...string) ([]byte, error) {
100 if args[0] == "rev-parse" {
101 return []byte("fake-commit-id"), nil
102 }
103 if args[0] == "blame" {
104 content := blameLine("fake-commit-id", 2, "foo.txt", "up == 0")
105 return []byte(content), nil
106 }
107 return nil, nil
108 },
109 httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
110 if r.Method == http.MethodGet && r.URL.Path == "/api/v3/repos/foo/bar/pulls/123/reviews" {
111 w.WriteHeader(http.StatusBadRequest)
112 _, _ = w.Write([]byte("Error"))
113 return
114 }
115 _, _ = w.Write([]byte(""))
116 }),
117 error: func(uri string) string {
118 return fmt.Sprintf("failed to list pull request reviews: GET %s/api/v3/repos/foo/bar/pulls/123/reviews: 400 []", uri)
119 },
120 reports: []reporter.Report{
121 {
122 SourcePath: "foo.txt",
123 ModifiedLines: []int{2},
124 Rule: mockRules[1],
125 Problem: checks.Problem{
126 Lines: parser.LineRange{
127 First: 2,
128 Last: 2,
129 },
130 Reporter: "mock",
131 Text: "syntax error",
132 Details: "syntax details",
133 Severity: checks.Fatal,
134 },
135 },
136 },
137 },
138 {
139 description: "happy path",
140 owner: "foo",
141 repo: "bar",
142 token: "something",
143 prNum: 123,
144 timeout: time.Second,
145 gitCmd: func(args ...string) ([]byte, error) {
146 if args[0] == "rev-parse" {
147 return []byte("fake-commit-id"), nil
148 }
149 if args[0] == "blame" {
150 content := blameLine("fake-commit-id", 2, "foo.txt", "up == 0")
151 return []byte(content), nil
152 }
153 return nil, nil
154 },
155 reports: []reporter.Report{
156 {
157 SourcePath: "foo.txt",
158 ModifiedLines: []int{2},
159 Rule: mockRules[1],
160 Problem: checks.Problem{
161 Lines: parser.LineRange{
162 First: 2,
163 Last: 2,
164 },
165 Reporter: "mock",
166 Text: "syntax error",
167 Details: "syntax details",
168 Severity: checks.Fatal,
169 },
170 },
171 },
172 },
173 {
174 description: "error crating review",
175 owner: "foo",
176 repo: "bar",
177 token: "something",
178 prNum: 123,
179 timeout: time.Second,
180 gitCmd: func(args ...string) ([]byte, error) {
181 if args[0] == "rev-parse" {
182 return []byte("fake-commit-id"), nil
183 }
184 if args[0] == "blame" {
185 content := blameLine("fake-commit-id", 2, "foo.txt", "up == 0")
186 return []byte(content), nil
187 }
188 return nil, nil
189 },
190 httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
191 if r.Method == http.MethodPost && r.URL.Path == "/api/v3/repos/foo/bar/pulls/123/reviews" {
192 w.WriteHeader(http.StatusBadGateway)
193 _, _ = w.Write([]byte("Error"))
194 return
195 }
196 _, _ = w.Write([]byte(""))
197 }),
198 error: func(uri string) string {
199 return fmt.Sprintf("failed to create pull request review: POST %s/api/v3/repos/foo/bar/pulls/123/reviews: 502 []", uri)
200 },
201 reports: []reporter.Report{
202 {
203 SourcePath: "foo.txt",
204 ModifiedLines: []int{2},
205 Rule: mockRules[1],
206 Problem: checks.Problem{
207 Lines: parser.LineRange{
208 First: 2,
209 Last: 2,
210 },
211 Reporter: "mock",
212 Text: "syntax error",
213 Details: "syntax details",
214 Severity: checks.Fatal,
215 },
216 },
217 },
218 },
219 {
220 description: "error updating existing review",
221 owner: "foo",
222 repo: "bar",
223 token: "something",
224 prNum: 123,
225 timeout: time.Second,
226 gitCmd: func(args ...string) ([]byte, error) {
227 if args[0] == "rev-parse" {
228 return []byte("fake-commit-id"), nil
229 }
230 if args[0] == "blame" {
231 content := blameLine("fake-commit-id", 2, "foo.txt", "up == 0")
232 return []byte(content), nil
233 }
234 return nil, nil
235 },
236 httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
237 if r.Method == http.MethodGet && r.URL.Path == "/api/v3/repos/foo/bar/pulls/123/reviews" {
238 _, _ = w.Write([]byte(`[{"id":1,"body":"### This pull request was validated by [pint](https://github.com/cloudflare/pint).\nxxxx"}]`))
239 return
240 }
241 if r.Method == http.MethodPut && r.URL.Path == "/api/v3/repos/foo/bar/pulls/123/reviews/1" {
242 w.WriteHeader(http.StatusBadGateway)
243 _, _ = w.Write([]byte("Error"))
244 return
245 }
246 _, _ = w.Write([]byte(""))
247 }),
248 error: func(uri string) string {
249 return fmt.Sprintf("failed to update pull request review: PUT %s/api/v3/repos/foo/bar/pulls/123/reviews/1: 502 []", uri)
250 },
251 reports: []reporter.Report{
252 {
253 SourcePath: "foo.txt",
254 ModifiedLines: []int{2},
255 Rule: mockRules[1],
256 Problem: checks.Problem{
257 Lines: parser.LineRange{
258 First: 2,
259 Last: 2,
260 },
261 Reporter: "mock",
262 Text: "syntax error",
263 Details: "syntax details",
264 Severity: checks.Fatal,
265 },
266 },
267 },
268 },
269 {
270 description: "update existing review",
271 owner: "foo",
272 repo: "bar",
273 token: "something",
274 prNum: 123,
275 timeout: time.Second,
276 gitCmd: func(args ...string) ([]byte, error) {
277 if args[0] == "rev-parse" {
278 return []byte("fake-commit-id"), nil
279 }
280 if args[0] == "blame" {
281 content := blameLine("fake-commit-id", 2, "foo.txt", "up == 0")
282 return []byte(content), nil
283 }
284 return nil, nil
285 },
286 httpHandler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
287 if r.Method == http.MethodGet && r.URL.Path == "/api/v3/repos/foo/bar/pulls/123/reviews" {
288 _, _ = w.Write([]byte(`[{"id":1,"body":"### This pull request was validated by [pint](https://github.com/cloudflare/pint).\nxxxx"}]`))
289 return
290 }
291 if r.Method == http.MethodGet && r.URL.Path == "/api/v3/repos/foo/bar/pulls/123/comments" {
292 _, _ = w.Write([]byte(`[{"id":1,"commit_id":"fake-commit-id","path":"foo.txt","line":2,"body":":stop_sign: [mock](https://cloudflare.github.io/pint/checks/mock.html): syntax error\n\nsyntax details"}]`))
293 return
294 }
295 _, _ = w.Write([]byte(""))
296 }),
297 reports: []reporter.Report{
298 {
299 SourcePath: "foo.txt",
300 ModifiedLines: []int{2},
301 Rule: mockRules[1],
302 Problem: checks.Problem{
303 Lines: parser.LineRange{
304 First: 2,
305 Last: 2,
306 },
307 Reporter: "mock",
308 Text: "syntax error",
309 Details: "syntax details",
310 Severity: checks.Fatal,
311 },
312 },
313 },
314 },
315 } {
316 t.Run(tc.description, func(t *testing.T) {
317 slog.SetDefault(slogt.New(t))
318
319 var handler http.Handler
320 if tc.httpHandler != nil {
321 handler = tc.httpHandler
322 } else {
323 // Handler that checks for token.
324 handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
325 auth := r.Header["Authorization"]
326 if len(auth) == 0 {
327 w.WriteHeader(500)
328 _, _ = w.Write([]byte("No token"))
329 t.Fatal("got a request with no token")
330 return
331 }
332 token := auth[0]
333 if token != fmt.Sprintf("Bearer %s", tc.token) {
334 w.WriteHeader(500)
335 _, _ = w.Write([]byte("Invalid token"))
336 t.Fatalf("got a request with invalid token (got %s)", token)
337 }
338 })
339 }
340 srv := httptest.NewServer(handler)
341 defer srv.Close()
342 r, err := reporter.NewGithubReporter(
343 "v0.0.0",
344 srv.URL,
345 srv.URL,
346 tc.timeout,
347 tc.token,
348 tc.owner,
349 tc.repo,
350 tc.prNum,
351 tc.gitCmd,
352 )
353 require.NoError(t, err)
354
355 err = r.Submit(reporter.NewSummary(tc.reports))
356 if tc.error == nil {
357 require.NoError(t, err)
358 } else {
359 require.EqualError(t, err, tc.error(srv.URL))
360 }
361 })
362 }
363}
364