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  }