github.com/mistwind/reviewdog@v0.0.0-20230322024206-9cfa11856d58/cmd/reviewdog/doghouse_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "context" 6 "fmt" 7 "os" 8 "path/filepath" 9 "strings" 10 "testing" 11 12 "github.com/google/go-cmp/cmp" 13 "golang.org/x/oauth2" 14 "google.golang.org/protobuf/testing/protocmp" 15 16 "github.com/mistwind/reviewdog" 17 "github.com/mistwind/reviewdog/cienv" 18 "github.com/mistwind/reviewdog/doghouse" 19 "github.com/mistwind/reviewdog/doghouse/client" 20 "github.com/mistwind/reviewdog/filter" 21 "github.com/mistwind/reviewdog/project" 22 "github.com/mistwind/reviewdog/proto/rdf" 23 ) 24 25 func setupEnvs(testEnvs map[string]string) (cleanup func()) { 26 saveEnvs := make(map[string]string) 27 for key, value := range testEnvs { 28 saveEnvs[key] = os.Getenv(key) 29 if value == "" { 30 os.Unsetenv(key) 31 } else { 32 os.Setenv(key, value) 33 } 34 } 35 return func() { 36 for key, value := range saveEnvs { 37 os.Setenv(key, value) 38 } 39 } 40 } 41 42 func TestNewDoghouseCli_returnGitHubClient(t *testing.T) { 43 cleanup := setupEnvs(map[string]string{ 44 "REVIEWDOG_TOKEN": "", 45 "GITHUB_ACTIONS": "xxx", 46 "REVIEWDOG_GITHUB_API_TOKEN": "xxx", 47 }) 48 defer cleanup() 49 cli, err := newDoghouseCli(context.Background()) 50 if err != nil { 51 t.Fatalf("failed to create new client: %v", err) 52 } 53 if _, ok := cli.(*client.GitHubClient); !ok { 54 t.Errorf("got %T client, want *client.GitHubClient client", cli) 55 } 56 } 57 58 func TestNewDoghouseCli_returnErrorForGitHubClient(t *testing.T) { 59 cleanup := setupEnvs(map[string]string{ 60 "REVIEWDOG_TOKEN": "", 61 "GITHUB_ACTIONS": "true", 62 "REVIEWDOG_GITHUB_API_TOKEN": "", // missing 63 }) 64 defer cleanup() 65 if _, err := newDoghouseCli(context.Background()); err == nil { 66 t.Error("got no error but want REVIEWDOG_GITHUB_API_TOKEN missing error") 67 } 68 } 69 70 func TestNewDoghouseCli_returnDogHouseClientWithReviewdogToken(t *testing.T) { 71 cleanup := setupEnvs(map[string]string{ 72 "REVIEWDOG_TOKEN": "xxx", 73 "GITHUB_ACTIONS": "true", 74 "REVIEWDOG_GITHUB_API_TOKEN": "xxx", 75 }) 76 defer cleanup() 77 cli, err := newDoghouseCli(context.Background()) 78 if err != nil { 79 t.Fatalf("failed to create new client: %v", err) 80 } 81 if _, ok := cli.(*client.DogHouseClient); !ok { 82 t.Errorf("got %T client, want *client.DogHouseClient client", cli) 83 } 84 } 85 86 func TestNewDoghouseCli_returnDogHouseClient(t *testing.T) { 87 cleanup := setupEnvs(map[string]string{ 88 "REVIEWDOG_TOKEN": "", 89 "GITHUB_ACTIONS": "", 90 "REVIEWDOG_GITHUB_API_TOKEN": "", 91 }) 92 defer cleanup() 93 cli, err := newDoghouseCli(context.Background()) 94 if err != nil { 95 t.Fatalf("failed to create new client: %v", err) 96 } 97 if _, ok := cli.(*client.DogHouseClient); !ok { 98 t.Errorf("got %T client, want *client.DogHouseClient client", cli) 99 } 100 } 101 102 func TestNewDoghouseServerCli(t *testing.T) { 103 if _, ok := newDoghouseServerCli(context.Background()).Client.Transport.(*oauth2.Transport); ok { 104 t.Error("got oauth2 http client, want default client") 105 } 106 107 cleanup := setupEnvs(map[string]string{ 108 "REVIEWDOG_TOKEN": "xxx", 109 }) 110 defer cleanup() 111 112 if _, ok := newDoghouseServerCli(context.Background()).Client.Transport.(*oauth2.Transport); !ok { 113 t.Error("w/ TOKEN: got unexpected http client, want oauth client") 114 } 115 } 116 117 func TestDiagnosticResultSet_Project(t *testing.T) { 118 defer func(f func(ctx context.Context, conf *project.Config, runners map[string]bool, level string, tee bool) (*reviewdog.ResultMap, error)) { 119 projectRunAndParse = f 120 }(projectRunAndParse) 121 122 var wantDiagnosticResult reviewdog.ResultMap 123 wantDiagnosticResult.Store("name1", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{ 124 { 125 Location: &rdf.Location{ 126 Range: &rdf.Range{Start: &rdf.Position{ 127 Line: 1, 128 Column: 14, 129 }}, 130 Path: "reviewdog.go", 131 }, 132 Message: "msg", 133 }, 134 }}) 135 136 projectRunAndParse = func(ctx context.Context, conf *project.Config, runners map[string]bool, level string, tee bool) (*reviewdog.ResultMap, error) { 137 return &wantDiagnosticResult, nil 138 } 139 140 tmp, err := os.CreateTemp("", "") 141 if err != nil { 142 t.Fatal(err) 143 } 144 defer os.Remove(tmp.Name()) 145 146 got, err := checkResultSet(context.Background(), nil, &option{conf: tmp.Name()}, true) 147 if err != nil { 148 t.Fatal(err) 149 } 150 151 if got.Len() != wantDiagnosticResult.Len() { 152 t.Errorf("length of results is different. got = %d, want = %d\n", got.Len(), wantDiagnosticResult.Len()) 153 } 154 got.Range(func(k string, r *reviewdog.Result) { 155 w, _ := wantDiagnosticResult.Load(k) 156 if diff := cmp.Diff(r, w, protocmp.Transform()); diff != "" { 157 t.Errorf("result has diff:\n%s", diff) 158 } 159 }) 160 } 161 162 func TestDiagnosticResultSet_NonProject(t *testing.T) { 163 opt := &option{ 164 f: "golint", 165 } 166 input := `reviewdog.go:14:14: test message` 167 got, err := checkResultSet(context.Background(), strings.NewReader(input), opt, false) 168 if err != nil { 169 t.Fatal(err) 170 } 171 var want reviewdog.ResultMap 172 want.Store("golint", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{ 173 { 174 Location: &rdf.Location{ 175 Range: &rdf.Range{Start: &rdf.Position{ 176 Line: 14, 177 Column: 14, 178 }}, 179 Path: "reviewdog.go", 180 }, 181 Message: "test message", 182 OriginalOutput: input, 183 }, 184 }}) 185 186 if got.Len() != want.Len() { 187 t.Errorf("length of results is different. got = %d, want = %d\n", got.Len(), want.Len()) 188 } 189 got.Range(func(k string, r *reviewdog.Result) { 190 w, _ := want.Load(k) 191 if diff := cmp.Diff(r, w, protocmp.Transform()); diff != "" { 192 t.Errorf("result has diff:\n%s", diff) 193 } 194 }) 195 } 196 197 type fakeDoghouseServerCli struct { 198 client.DogHouseClientInterface 199 FakeCheck func(context.Context, *doghouse.CheckRequest) (*doghouse.CheckResponse, error) 200 } 201 202 func (f *fakeDoghouseServerCli) Check(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) { 203 return f.FakeCheck(ctx, req) 204 } 205 206 func TestPostResultSet_withReportURL(t *testing.T) { 207 const ( 208 owner = "haya14busa" 209 repo = "reviewdog" 210 prNum = 14 211 sha = "1414" 212 ) 213 214 fakeCli := &fakeDoghouseServerCli{} 215 fakeCli.FakeCheck = func(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) { 216 if req.Owner != owner { 217 t.Errorf("req.Owner = %q, want %q", req.Owner, owner) 218 } 219 if req.Repo != repo { 220 t.Errorf("req.Repo = %q, want %q", req.Repo, repo) 221 } 222 if req.SHA != sha { 223 t.Errorf("req.SHA = %q, want %q", req.SHA, sha) 224 } 225 if req.PullRequest != prNum { 226 t.Errorf("req.PullRequest = %d, want %d", req.PullRequest, prNum) 227 } 228 switch req.Name { 229 case "name1": 230 if diff := cmp.Diff(req.Annotations, []*doghouse.Annotation{ 231 { 232 Diagnostic: &rdf.Diagnostic{ 233 Message: "name1: test 1", 234 Location: &rdf.Location{ 235 Path: "cmd/mistwind/reviewdog.go", 236 Range: &rdf.Range{ 237 Start: &rdf.Position{Line: 14}, 238 }, 239 }, 240 OriginalOutput: "L1\nL2", 241 }, 242 }, 243 { 244 Diagnostic: &rdf.Diagnostic{ 245 Message: "name1: test 2", 246 Location: &rdf.Location{ 247 Path: "cmd/mistwind/reviewdog.go", 248 }, 249 }, 250 }, 251 }, protocmp.Transform()); diff != "" { 252 t.Errorf("%s: req.Annotation have diff:\n%s", req.Name, diff) 253 } 254 case "name2": 255 if diff := cmp.Diff(req.Annotations, []*doghouse.Annotation{ 256 { 257 Diagnostic: &rdf.Diagnostic{ 258 Message: "name2: test 1", 259 Location: &rdf.Location{ 260 Path: "cmd/reviewdog/doghouse.go", 261 Range: &rdf.Range{ 262 Start: &rdf.Position{Line: 14}, 263 }, 264 }, 265 }, 266 }, 267 }, protocmp.Transform()); diff != "" { 268 t.Errorf("%s: req.Annotation have diff:\n%s", req.Name, diff) 269 } 270 default: 271 t.Errorf("unexpected req.Name: %s", req.Name) 272 } 273 return &doghouse.CheckResponse{ReportURL: "xxx"}, nil 274 } 275 276 // It assumes the current dir is ./cmd/reviewdog/ 277 var resultSet reviewdog.ResultMap 278 resultSet.Store("name1", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{ 279 { 280 Location: &rdf.Location{ 281 Range: &rdf.Range{Start: &rdf.Position{ 282 Line: 14, 283 }}, 284 Path: "reviewdog.go", // test relative path 285 }, 286 Message: "name1: test 1", 287 OriginalOutput: "L1\nL2", 288 }, 289 { 290 Location: &rdf.Location{ 291 Path: absPath(t, "reviewdog.go"), // test abs path 292 }, 293 Message: "name1: test 2", 294 }, 295 }}) 296 resultSet.Store("name2", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{ 297 { 298 Location: &rdf.Location{ 299 Range: &rdf.Range{Start: &rdf.Position{ 300 Line: 14, 301 }}, 302 Path: "doghouse.go", 303 }, 304 Message: "name2: test 1", 305 }, 306 }}) 307 308 ghInfo := &cienv.BuildInfo{ 309 Owner: owner, 310 Repo: repo, 311 PullRequest: prNum, 312 SHA: sha, 313 } 314 315 opt := &option{filterMode: filter.ModeAdded} 316 if _, err := postResultSet(context.Background(), &resultSet, ghInfo, fakeCli, opt); err != nil { 317 t.Fatal(err) 318 } 319 } 320 321 func TestPostResultSet_withoutReportURL(t *testing.T) { 322 const ( 323 owner = "haya14busa" 324 repo = "reviewdog" 325 prNum = 14 326 sha = "1414" 327 ) 328 329 wantResults := []*filter.FilteredDiagnostic{{ShouldReport: true}} 330 fakeCli := &fakeDoghouseServerCli{} 331 fakeCli.FakeCheck = func(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) { 332 return &doghouse.CheckResponse{CheckedResults: wantResults}, nil 333 } 334 335 var resultSet reviewdog.ResultMap 336 resultSet.Store("name1", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{}}) 337 338 ghInfo := &cienv.BuildInfo{Owner: owner, Repo: repo, PullRequest: prNum, SHA: sha} 339 340 opt := &option{filterMode: filter.ModeAdded} 341 resp, err := postResultSet(context.Background(), &resultSet, ghInfo, fakeCli, opt) 342 if err != nil { 343 t.Fatal(err) 344 } 345 if resp.Len() == 0 { 346 t.Fatal("result should not be empty") 347 } 348 results, err := resp.Load("name1") 349 if err != nil { 350 t.Fatalf("should have result for name1: %v", err) 351 } 352 if diff := cmp.Diff(results.FilteredDiagnostic, wantResults, protocmp.Transform()); diff != "" { 353 t.Errorf("results has diff:\n%s", diff) 354 } 355 } 356 357 func TestPostResultSet_conclusion(t *testing.T) { 358 const ( 359 owner = "haya14busa" 360 repo = "reviewdog" 361 prNum = 14 362 sha = "1414" 363 ) 364 365 fakeCli := &fakeDoghouseServerCli{} 366 var resultSet reviewdog.ResultMap 367 resultSet.Store("name1", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{}}) 368 ghInfo := &cienv.BuildInfo{Owner: owner, Repo: repo, PullRequest: prNum, SHA: sha} 369 370 tests := []struct { 371 conclusion string 372 failOnError bool 373 wantErr bool 374 }{ 375 {conclusion: "failure", failOnError: true, wantErr: true}, 376 {conclusion: "neutral", failOnError: true, wantErr: false}, 377 {conclusion: "success", failOnError: true, wantErr: false}, 378 {conclusion: "", failOnError: true, wantErr: false}, 379 {conclusion: "failure", failOnError: false, wantErr: false}, 380 } 381 382 for _, tt := range tests { 383 tt := tt 384 fakeCli.FakeCheck = func(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) { 385 return &doghouse.CheckResponse{ReportURL: "xxx", Conclusion: tt.conclusion}, nil 386 } 387 opt := &option{filterMode: filter.ModeAdded, failOnError: tt.failOnError} 388 id := fmt.Sprintf("[conclusion=%s, failOnError=%v]", tt.conclusion, tt.failOnError) 389 _, err := postResultSet(context.Background(), &resultSet, ghInfo, fakeCli, opt) 390 if tt.wantErr && err == nil { 391 t.Errorf("[%s] want err, but got nil.", id) 392 } else if !tt.wantErr && err != nil { 393 t.Errorf("[%s] got unexpected error: %v", id, err) 394 } 395 } 396 } 397 398 func TestPostResultSet_withEmptyResponse(t *testing.T) { 399 const ( 400 owner = "haya14busa" 401 repo = "reviewdog" 402 prNum = 14 403 sha = "1414" 404 ) 405 406 fakeCli := &fakeDoghouseServerCli{} 407 fakeCli.FakeCheck = func(ctx context.Context, req *doghouse.CheckRequest) (*doghouse.CheckResponse, error) { 408 return &doghouse.CheckResponse{}, nil 409 } 410 411 var resultSet reviewdog.ResultMap 412 resultSet.Store("name1", &reviewdog.Result{Diagnostics: []*rdf.Diagnostic{}}) 413 414 ghInfo := &cienv.BuildInfo{Owner: owner, Repo: repo, PullRequest: prNum, SHA: sha} 415 416 opt := &option{filterMode: filter.ModeAdded} 417 if _, err := postResultSet(context.Background(), &resultSet, ghInfo, fakeCli, opt); err == nil { 418 t.Error("got no error but want report missing error") 419 } 420 } 421 422 func TestReportResults(t *testing.T) { 423 cleanup := setupEnvs(map[string]string{ 424 "GITHUB_ACTIONS": "", 425 "GITHUB_EVENT_PATH": "", 426 }) 427 defer cleanup() 428 filteredResultSet := new(reviewdog.FilteredResultMap) 429 filteredResultSet.Store("name1", &reviewdog.FilteredResult{ 430 FilteredDiagnostic: []*filter.FilteredDiagnostic{ 431 { 432 Diagnostic: &rdf.Diagnostic{ 433 OriginalOutput: "name1-L1\nname1-L2", 434 }, 435 ShouldReport: true, 436 }, 437 { 438 Diagnostic: &rdf.Diagnostic{ 439 OriginalOutput: "name1.2-L1\nname1.2-L2", 440 }, 441 ShouldReport: false, 442 }, 443 }, 444 }) 445 filteredResultSet.Store("name2", &reviewdog.FilteredResult{ 446 FilteredDiagnostic: []*filter.FilteredDiagnostic{ 447 { 448 Diagnostic: &rdf.Diagnostic{ 449 OriginalOutput: "name1-L1\nname1-L2", 450 }, 451 ShouldReport: false, 452 }, 453 }, 454 }) 455 stdout := new(bytes.Buffer) 456 foundResultShouldReport := reportResults(stdout, filteredResultSet) 457 if !foundResultShouldReport { 458 t.Errorf("foundResultShouldReport = %v, want true", foundResultShouldReport) 459 } 460 want := `reviewdog: Reporting results for "name1" 461 name1-L1 462 name1-L2 463 reviewdog: Reporting results for "name2" 464 reviewdog: No results found for "name2". 1 results found outside diff. 465 ` 466 if got := stdout.String(); got != want { 467 t.Errorf("diff found for report:\ngot:\n%s\nwant:\n%s", got, want) 468 } 469 } 470 471 func TestReportResults_inGitHubAction(t *testing.T) { 472 cleanup := setupEnvs(map[string]string{ 473 "GITHUB_ACTIONS": "true", 474 "GITHUB_EVENT_PATH": "", 475 }) 476 defer cleanup() 477 filteredResultSet := new(reviewdog.FilteredResultMap) 478 filteredResultSet.Store("name1", &reviewdog.FilteredResult{ 479 FilteredDiagnostic: []*filter.FilteredDiagnostic{ 480 { 481 Diagnostic: &rdf.Diagnostic{ 482 OriginalOutput: "name1-L1\nname1-L2", 483 }, 484 ShouldReport: true, 485 }, 486 }, 487 }) 488 stdout := new(bytes.Buffer) 489 _ = reportResults(stdout, filteredResultSet) 490 want := `reviewdog: Reporting results for "name1" 491 ` 492 if got := stdout.String(); got != want { 493 t.Errorf("diff found for report:\ngot:\n%s\nwant:\n%s", got, want) 494 } 495 } 496 497 func TestReportResults_noResultsShouldReport(t *testing.T) { 498 cleanup := setupEnvs(map[string]string{ 499 "GITHUB_ACTIONS": "", 500 "GITHUB_EVENT_PATH": "", 501 }) 502 defer cleanup() 503 filteredResultSet := new(reviewdog.FilteredResultMap) 504 filteredResultSet.Store("name1", &reviewdog.FilteredResult{ 505 FilteredDiagnostic: []*filter.FilteredDiagnostic{ 506 { 507 Diagnostic: &rdf.Diagnostic{ 508 OriginalOutput: "name1-L1\nname1-L2", 509 }, 510 ShouldReport: false, 511 }, 512 { 513 Diagnostic: &rdf.Diagnostic{ 514 OriginalOutput: "name1.2-L1\nname1.2-L2", 515 }, 516 ShouldReport: false, 517 }, 518 }, 519 }) 520 filteredResultSet.Store("name2", &reviewdog.FilteredResult{ 521 FilteredDiagnostic: []*filter.FilteredDiagnostic{ 522 { 523 Diagnostic: &rdf.Diagnostic{ 524 OriginalOutput: "name1-L1\nname1-L2", 525 }, 526 ShouldReport: false, 527 }, 528 }, 529 }) 530 stdout := new(bytes.Buffer) 531 foundResultShouldReport := reportResults(stdout, filteredResultSet) 532 if foundResultShouldReport { 533 t.Errorf("foundResultShouldReport = %v, want false", foundResultShouldReport) 534 } 535 want := `reviewdog: Reporting results for "name1" 536 reviewdog: No results found for "name1". 2 results found outside diff. 537 reviewdog: Reporting results for "name2" 538 reviewdog: No results found for "name2". 1 results found outside diff. 539 ` 540 if got := stdout.String(); got != want { 541 t.Errorf("diff found for report:\ngot:\n%s\nwant:\n%s", got, want) 542 } 543 } 544 545 func absPath(t *testing.T, path string) string { 546 p, err := filepath.Abs(path) 547 if err != nil { 548 t.Errorf("filepath.Abs(%q) failed: %v", path, err) 549 } 550 return p 551 }