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  }