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