github.com/alexey-mercari/reviewdog@v0.10.1-0.20200514053941-928943b10766/doghouse/server/doghouse_test.go (about) 1 package server 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "testing" 8 9 "github.com/google/go-cmp/cmp" 10 "github.com/google/go-github/v31/github" 11 12 "github.com/reviewdog/reviewdog/difffilter" 13 "github.com/reviewdog/reviewdog/doghouse" 14 ) 15 16 type fakeCheckerGitHubCli struct { 17 checkerGitHubClientInterface 18 FakeGetPullRequestDiff func(ctx context.Context, owner, repo string, number int) ([]byte, error) 19 FakeCreateCheckRun func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) 20 FakeUpdateCheckRun func(ctx context.Context, owner, repo string, checkID int64, opt github.UpdateCheckRunOptions) (*github.CheckRun, error) 21 } 22 23 func (f *fakeCheckerGitHubCli) GetPullRequestDiff(ctx context.Context, owner, repo string, number int) ([]byte, error) { 24 return f.FakeGetPullRequestDiff(ctx, owner, repo, number) 25 } 26 27 func (f *fakeCheckerGitHubCli) CreateCheckRun(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 28 return f.FakeCreateCheckRun(ctx, owner, repo, opt) 29 } 30 31 func (f *fakeCheckerGitHubCli) UpdateCheckRun(ctx context.Context, owner, repo string, checkID int64, opt github.UpdateCheckRunOptions) (*github.CheckRun, error) { 32 return f.FakeUpdateCheckRun(ctx, owner, repo, checkID, opt) 33 } 34 35 const sampleDiff = `--- a/sample.old.txt 2016-10-13 05:09:35.820791185 +0900 36 +++ b/sample.new.txt 2016-10-13 05:15:26.839245048 +0900 37 @@ -1,3 +1,4 @@ 38 unchanged, contextual line 39 -deleted line 40 +added line 41 +added line 42 unchanged, contextual line 43 --- a/nonewline.old.txt 2016-10-13 15:34:14.931778318 +0900 44 +++ b/nonewline.new.txt 2016-10-13 15:34:14.868444672 +0900 45 @@ -1,4 +1,4 @@ 46 " vim: nofixeol noendofline 47 No newline at end of both the old and new file 48 -a 49 -a 50 \ No newline at end of file 51 +b 52 +b 53 \ No newline at end of file 54 ` 55 56 func TestCheck_OK(t *testing.T) { 57 const ( 58 name = "haya14busa-linter" 59 owner = "haya14busa" 60 repo = "reviewdog" 61 prNum = 14 62 sha = "1414" 63 reportURL = "http://example.com/report_url" 64 conclusion = "neutral" 65 wantCheckID = 1414 66 ) 67 68 req := &doghouse.CheckRequest{ 69 Name: name, 70 Owner: owner, 71 Repo: repo, 72 PullRequest: prNum, 73 SHA: sha, 74 Annotations: []*doghouse.Annotation{ 75 { 76 Path: "sample.new.txt", 77 Line: 2, 78 Message: "test message", 79 RawMessage: "raw test message", 80 }, 81 { 82 Path: "sample.new.txt", 83 Line: 14, 84 Message: "test message outside diff", 85 RawMessage: "raw test message outside diff", 86 }, 87 }, 88 Level: "warning", 89 } 90 91 cli := &fakeCheckerGitHubCli{} 92 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 93 return []byte(sampleDiff), nil 94 } 95 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 96 if opt.Name != name { 97 t.Errorf("CreateCheckRunOptions.Name = %q, want %q", opt.Name, name) 98 } 99 if opt.HeadSHA != sha { 100 t.Errorf("CreateCheckRunOptions.HeadSHA = %q, want %q", opt.HeadSHA, sha) 101 } 102 return &github.CheckRun{ID: github.Int64(wantCheckID)}, nil 103 } 104 cli.FakeUpdateCheckRun = func(ctx context.Context, owner, repo string, checkID int64, opt github.UpdateCheckRunOptions) (*github.CheckRun, error) { 105 if checkID != wantCheckID { 106 t.Errorf("UpdateCheckRun: checkID = %d, want %d", checkID, wantCheckID) 107 } 108 if opt.Name != name { 109 t.Errorf("UpdateCheckRunOptions.Name = %q, want %q", opt.Name, name) 110 } 111 annotations := opt.Output.Annotations 112 if len(annotations) == 0 { 113 if *opt.Conclusion != conclusion { 114 t.Errorf("UpdateCheckRunOptions.Conclusion = %q, want %q", *opt.Conclusion, conclusion) 115 } 116 } else { 117 wantAnnotations := []*github.CheckRunAnnotation{ 118 { 119 Path: github.String("sample.new.txt"), 120 StartLine: github.Int(2), 121 EndLine: github.Int(2), 122 AnnotationLevel: github.String("warning"), 123 Message: github.String("test message"), 124 Title: github.String("[haya14busa-linter] sample.new.txt#L2"), 125 RawDetails: github.String("raw test message"), 126 }, 127 } 128 if d := cmp.Diff(annotations, wantAnnotations); d != "" { 129 t.Errorf("Annotation diff found:\n%s", d) 130 } 131 } 132 return &github.CheckRun{HTMLURL: github.String(reportURL)}, nil 133 } 134 checker := &Checker{req: req, gh: cli} 135 res, err := checker.Check(context.Background()) 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 if res.ReportURL != reportURL { 141 t.Errorf("res.reportURL = %q, want %q", res.ReportURL, reportURL) 142 } 143 } 144 145 func testOutsideDiff(t *testing.T, outsideDiff bool, filterMode difffilter.Mode) { 146 const ( 147 name = "haya14busa-linter" 148 owner = "haya14busa" 149 repo = "reviewdog" 150 prNum = 14 151 sha = "1414" 152 reportURL = "http://example.com/report_url" 153 conclusion = "neutral" 154 wantCheckID = 1414 155 ) 156 157 req := &doghouse.CheckRequest{ 158 Name: name, 159 Owner: owner, 160 Repo: repo, 161 PullRequest: prNum, 162 SHA: sha, 163 Annotations: []*doghouse.Annotation{ 164 { 165 Path: "sample.new.txt", 166 Line: 2, 167 Message: "test message", 168 RawMessage: "raw test message", 169 }, 170 { 171 Path: "sample.new.txt", 172 Line: 14, 173 Message: "test message outside diff", 174 RawMessage: "raw test message outside diff", 175 }, 176 }, 177 Level: "warning", 178 OutsideDiff: outsideDiff, 179 FilterMode: filterMode, 180 } 181 182 cli := &fakeCheckerGitHubCli{} 183 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 184 return []byte(sampleDiff), nil 185 } 186 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 187 return &github.CheckRun{ID: github.Int64(wantCheckID)}, nil 188 } 189 cli.FakeUpdateCheckRun = func(ctx context.Context, owner, repo string, checkID int64, opt github.UpdateCheckRunOptions) (*github.CheckRun, error) { 190 annotations := opt.Output.Annotations 191 if len(annotations) == 0 { 192 if *opt.Conclusion != conclusion { 193 t.Errorf("UpdateCheckRunOptions.Conclusion = %q, want %q", *opt.Conclusion, conclusion) 194 } 195 } else { 196 wantAnnotations := []*github.CheckRunAnnotation{ 197 { 198 Path: github.String("sample.new.txt"), 199 StartLine: github.Int(2), 200 EndLine: github.Int(2), 201 AnnotationLevel: github.String("warning"), 202 Message: github.String("test message"), 203 Title: github.String("[haya14busa-linter] sample.new.txt#L2"), 204 RawDetails: github.String("raw test message"), 205 }, 206 { 207 Path: github.String("sample.new.txt"), 208 StartLine: github.Int(14), 209 EndLine: github.Int(14), 210 AnnotationLevel: github.String("warning"), 211 Message: github.String("test message outside diff"), 212 Title: github.String("[haya14busa-linter] sample.new.txt#L14"), 213 RawDetails: github.String("raw test message outside diff"), 214 }, 215 } 216 if d := cmp.Diff(annotations, wantAnnotations); d != "" { 217 t.Errorf("Annotation diff found:\n%s", d) 218 } 219 } 220 return &github.CheckRun{HTMLURL: github.String(reportURL)}, nil 221 } 222 checker := &Checker{req: req, gh: cli} 223 if _, err := checker.Check(context.Background()); err != nil { 224 t.Fatal(err) 225 } 226 } 227 228 func TestCheck_OK_deprecated_outsidediff(t *testing.T) { 229 t.Run("deprecated: outside_diff", func(t *testing.T) { 230 testOutsideDiff(t, true, difffilter.ModeDefault) 231 }) 232 t.Run("filter-mode=NoFilter", func(t *testing.T) { 233 testOutsideDiff(t, false, difffilter.ModeNoFilter) 234 }) 235 } 236 237 func TestCheck_OK_multiple_update_runs(t *testing.T) { 238 const ( 239 name = "haya14busa-linter" 240 owner = "haya14busa" 241 repo = "reviewdog" 242 prNum = 14 243 sha = "1414" 244 reportURL = "http://example.com/report_url" 245 conclusion = "neutral" 246 wantCheckID = 1414 247 ) 248 249 req := &doghouse.CheckRequest{ 250 Name: name, 251 Owner: owner, 252 Repo: repo, 253 PullRequest: prNum, 254 SHA: sha, 255 Level: "warning", 256 } 257 for i := 0; i < 101; i++ { 258 req.Annotations = append(req.Annotations, &doghouse.Annotation{ 259 Path: "sample.new.txt", 260 Line: 2, 261 Message: "test message", 262 RawMessage: "raw test message", 263 }) 264 } 265 266 cli := &fakeCheckerGitHubCli{} 267 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 268 return []byte(sampleDiff), nil 269 } 270 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 271 if opt.Name != name { 272 t.Errorf("CreateCheckRunOptions.Name = %q, want %q", opt.Name, name) 273 } 274 if opt.HeadSHA != sha { 275 t.Errorf("CreateCheckRunOptions.HeadSHA = %q, want %q", opt.HeadSHA, sha) 276 } 277 return &github.CheckRun{ID: github.Int64(wantCheckID)}, nil 278 } 279 cli.FakeUpdateCheckRun = func(ctx context.Context, owner, repo string, checkID int64, opt github.UpdateCheckRunOptions) (*github.CheckRun, error) { 280 if checkID != wantCheckID { 281 t.Errorf("UpdateCheckRun: checkID = %d, want %d", checkID, wantCheckID) 282 } 283 annotations := opt.Output.Annotations 284 switch len(annotations) { 285 case 0: 286 if *opt.Conclusion != conclusion { 287 t.Errorf("UpdateCheckRunOptions.Conclusion = %q, want %q", *opt.Conclusion, conclusion) 288 } 289 case maxAnnotationsPerRequest, 1: // Expected 290 default: 291 t.Errorf("UpdateCheckRun: len(annotations) = %d, but it's unexpected", len(annotations)) 292 } 293 return &github.CheckRun{HTMLURL: github.String(reportURL)}, nil 294 } 295 checker := &Checker{req: req, gh: cli} 296 if _, err := checker.Check(context.Background()); err != nil { 297 t.Fatal(err) 298 } 299 } 300 301 func TestCheck_OK_nonPullRequests(t *testing.T) { 302 const ( 303 name = "haya14busa-linter" 304 owner = "haya14busa" 305 repo = "reviewdog" 306 sha = "1414" 307 reportURL = "http://example.com/report_url" 308 conclusion = "neutral" 309 wantCheckID = 1414 310 ) 311 312 req := &doghouse.CheckRequest{ 313 // Do not set PullRequest 314 Name: name, 315 Owner: owner, 316 Repo: repo, 317 SHA: sha, 318 Annotations: []*doghouse.Annotation{ 319 { 320 Path: "sample.new.txt", 321 Line: 2, 322 Message: "test message", 323 RawMessage: "raw test message", 324 }, 325 { 326 Path: "sample.new.txt", 327 Line: 14, 328 Message: "test message2", 329 RawMessage: "raw test message2", 330 }, 331 }, 332 Level: "warning", 333 } 334 335 cli := &fakeCheckerGitHubCli{} 336 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 337 t.Errorf("GetPullRequestDiff should not be called") 338 return nil, nil 339 } 340 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 341 return &github.CheckRun{ID: github.Int64(wantCheckID)}, nil 342 } 343 cli.FakeUpdateCheckRun = func(ctx context.Context, owner, repo string, checkID int64, opt github.UpdateCheckRunOptions) (*github.CheckRun, error) { 344 if checkID != wantCheckID { 345 t.Errorf("UpdateCheckRun: checkID = %d, want %d", checkID, wantCheckID) 346 } 347 annotations := opt.Output.Annotations 348 if len(annotations) == 0 { 349 if *opt.Conclusion != conclusion { 350 t.Errorf("UpdateCheckRunOptions.Conclusion = %q, want %q", *opt.Conclusion, conclusion) 351 } 352 } else { 353 wantAnnotations := []*github.CheckRunAnnotation{ 354 { 355 Path: github.String("sample.new.txt"), 356 StartLine: github.Int(2), 357 EndLine: github.Int(2), 358 AnnotationLevel: github.String("warning"), 359 Message: github.String("test message"), 360 Title: github.String("[haya14busa-linter] sample.new.txt#L2"), 361 RawDetails: github.String("raw test message"), 362 }, 363 { 364 Path: github.String("sample.new.txt"), 365 StartLine: github.Int(14), 366 EndLine: github.Int(14), 367 AnnotationLevel: github.String("warning"), 368 Message: github.String("test message2"), 369 Title: github.String("[haya14busa-linter] sample.new.txt#L14"), 370 RawDetails: github.String("raw test message2"), 371 }, 372 } 373 if d := cmp.Diff(annotations, wantAnnotations); d != "" { 374 t.Errorf("Annotation diff found:\n%s", d) 375 } 376 } 377 return &github.CheckRun{HTMLURL: github.String(reportURL)}, nil 378 } 379 checker := &Checker{req: req, gh: cli} 380 res, err := checker.Check(context.Background()) 381 if err != nil { 382 t.Fatal(err) 383 } 384 385 if res.ReportURL != reportURL { 386 t.Errorf("res.reportURL = %q, want %q", res.ReportURL, reportURL) 387 } 388 } 389 390 func TestCheck_fail_diff(t *testing.T) { 391 req := &doghouse.CheckRequest{PullRequest: 1} 392 cli := &fakeCheckerGitHubCli{} 393 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 394 return nil, errors.New("test diff failure") 395 } 396 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 397 return &github.CheckRun{}, nil 398 } 399 checker := &Checker{req: req, gh: cli} 400 401 if _, err := checker.Check(context.Background()); err == nil { 402 t.Fatalf("got no error, want some error") 403 } else { 404 t.Log(err) 405 } 406 } 407 408 func TestCheck_fail_invalid_diff(t *testing.T) { 409 t.Skip("Parse invalid diff function somehow doesn't return error") 410 req := &doghouse.CheckRequest{PullRequest: 1} 411 cli := &fakeCheckerGitHubCli{} 412 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 413 return []byte("invalid diff"), nil 414 } 415 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 416 return &github.CheckRun{}, nil 417 } 418 checker := &Checker{req: req, gh: cli} 419 420 if _, err := checker.Check(context.Background()); err == nil { 421 t.Fatalf("got no error, want some error") 422 } else { 423 t.Log(err) 424 } 425 } 426 427 func TestCheck_fail_check(t *testing.T) { 428 req := &doghouse.CheckRequest{PullRequest: 1} 429 cli := &fakeCheckerGitHubCli{} 430 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 431 return []byte(sampleDiff), nil 432 } 433 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 434 return nil, errors.New("test check failure") 435 } 436 checker := &Checker{req: req, gh: cli} 437 438 if _, err := checker.Check(context.Background()); err == nil { 439 t.Fatalf("got no error, want some error") 440 } else { 441 t.Log(err) 442 } 443 } 444 445 func TestCheck_fail_check_with_403(t *testing.T) { 446 req := &doghouse.CheckRequest{PullRequest: 1} 447 cli := &fakeCheckerGitHubCli{} 448 cli.FakeGetPullRequestDiff = func(ctx context.Context, owner, repo string, number int) ([]byte, error) { 449 return []byte(sampleDiff), nil 450 } 451 cli.FakeCreateCheckRun = func(ctx context.Context, owner, repo string, opt github.CreateCheckRunOptions) (*github.CheckRun, error) { 452 return nil, &github.ErrorResponse{ 453 Response: &http.Response{ 454 StatusCode: http.StatusForbidden, 455 }, 456 } 457 } 458 checker := &Checker{req: req, gh: cli} 459 460 resp, err := checker.Check(context.Background()) 461 if err != nil { 462 t.Fatalf("got unexpected error: %v", err) 463 } 464 if resp.CheckedResults == nil { 465 t.Error("resp.CheckedResults should not be nil") 466 } 467 }