github.com/covergates/covergates@v0.2.2-0.20201009050117-42ef8a19fb95/routers/api/report/report_test.go (about)

     1  package report
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"io/ioutil"
     9  	"mime/multipart"
    10  	"net/http"
    11  	"net/http/httptest"
    12  	"os"
    13  	"path/filepath"
    14  	"reflect"
    15  	"testing"
    16  
    17  	"github.com/covergates/covergates/core"
    18  	"github.com/covergates/covergates/mock"
    19  	"github.com/covergates/covergates/modules/charts"
    20  	"github.com/covergates/covergates/routers/api/request"
    21  	"github.com/gin-gonic/gin"
    22  	"github.com/golang/mock/gomock"
    23  	"github.com/jinzhu/gorm"
    24  	log "github.com/sirupsen/logrus"
    25  )
    26  
    27  func testRequest(r *gin.Engine, req *http.Request, f func(w *httptest.ResponseRecorder)) {
    28  	w := httptest.NewRecorder()
    29  	r.ServeHTTP(w, req)
    30  	f(w)
    31  }
    32  
    33  func encodeJSON(v interface{}) string {
    34  	data, err := json.Marshal(v)
    35  	if err != nil {
    36  		return ""
    37  	}
    38  	return string(data)
    39  }
    40  
    41  func addFormFile(w *multipart.Writer, k, name string, r io.Reader) {
    42  	writer, err := w.CreateFormFile(k, name)
    43  	if err != nil {
    44  		log.Fatal(err)
    45  	}
    46  	_, err = io.Copy(writer, r)
    47  	if err != nil {
    48  		log.Fatal(err)
    49  	}
    50  }
    51  
    52  func createForm(writer io.Writer, m map[string]string) *multipart.Writer {
    53  	w := multipart.NewWriter(writer)
    54  	for k, v := range m {
    55  		w.WriteField(k, v)
    56  	}
    57  	return w
    58  }
    59  
    60  func TestUpload(t *testing.T) {
    61  	ctrl := gomock.NewController(t)
    62  	defer ctrl.Finish()
    63  	mockCoverageService := mock.NewMockCoverageService(ctrl)
    64  	mockReportStore := mock.NewMockReportStore(ctrl)
    65  
    66  	t.Run("basic", func(t *testing.T) {
    67  		coverage := &core.CoverageReport{
    68  			Type: core.ReportPerl,
    69  		}
    70  		report := &core.Report{
    71  			ReportID: "1234",
    72  			Coverages: []*core.CoverageReport{
    73  				coverage,
    74  			},
    75  			Commit:    "abcdef",
    76  			Reference: "bear",
    77  			Files:     []string{"a"},
    78  		}
    79  
    80  		mockCoverageService.EXPECT().Report(
    81  			gomock.Any(),
    82  			gomock.Eq(core.ReportPerl),
    83  			gomock.Any(),
    84  		).Return(coverage, nil)
    85  
    86  		mockCoverageService.EXPECT().TrimFileNames(
    87  			gomock.Any(),
    88  			gomock.Eq(coverage),
    89  			gomock.Any(),
    90  		).Return(nil)
    91  
    92  		mockCoverageService.EXPECT().TrimFileNamePrefix(
    93  			gomock.Any(),
    94  			gomock.Eq(coverage),
    95  			gomock.Any(),
    96  		).Return(nil)
    97  
    98  		mockReportStore.EXPECT().Upload(
    99  			gomock.Eq(report),
   100  		).Return(nil)
   101  		r := gin.Default()
   102  		r.Use(func(c *gin.Context) {
   103  			WithSetting(c, &core.RepoSetting{})
   104  		})
   105  		r.POST("/reports/:id", HandleUpload(
   106  			mockCoverageService,
   107  			mockReportStore,
   108  		))
   109  		buffer := bytes.NewBuffer([]byte{})
   110  		w := createForm(
   111  			buffer,
   112  			map[string]string{
   113  				"commit": "abcdef",
   114  				"type":   "perl",
   115  				"ref":    "bear",
   116  				"files":  encodeJSON(report.Files),
   117  			},
   118  		)
   119  		addFormFile(w, "file", "cover_db.zip", bytes.NewBuffer([]byte("mock")))
   120  		w.Close()
   121  
   122  		req, _ := http.NewRequest("POST", "/reports/1234", buffer)
   123  		req.Header.Set("Content-Type", w.FormDataContentType())
   124  		testRequest(r, req, func(w *httptest.ResponseRecorder) {
   125  			rst := w.Result()
   126  			if rst.StatusCode != 200 {
   127  				t.Fail()
   128  			}
   129  		})
   130  	})
   131  
   132  	t.Run("test empty post", func(t *testing.T) {
   133  		r := gin.Default()
   134  		r.Use(func(c *gin.Context) {
   135  			WithSetting(c, &core.RepoSetting{})
   136  		})
   137  		r.POST("/reports/:id", HandleUpload(
   138  			mockCoverageService,
   139  			mockReportStore,
   140  		))
   141  		req, _ := http.NewRequest("POST", "/reports/1234", nil)
   142  		testRequest(r, req, func(w *httptest.ResponseRecorder) {
   143  			rst := w.Result()
   144  			if rst.StatusCode != 400 {
   145  				t.Fail()
   146  			}
   147  		})
   148  	})
   149  }
   150  
   151  func TestProtectReport(t *testing.T) {
   152  	ctrl := gomock.NewController(t)
   153  	defer ctrl.Finish()
   154  
   155  	mockRepoStore := mock.NewMockRepoStore(ctrl)
   156  	mockSCMService := mock.NewMockSCMService(ctrl)
   157  
   158  	t.Run("test protected report", func(t *testing.T) {
   159  		r := gin.Default()
   160  		r.POST("/",
   161  			func(c *gin.Context) {
   162  				WithSetting(c, &core.RepoSetting{
   163  					Protected: true,
   164  				})
   165  			},
   166  			ProtectReport(func(c *gin.Context) {
   167  				c.String(401, "")
   168  				c.Abort()
   169  			}, mockRepoStore, mockSCMService),
   170  		)
   171  		request, _ := http.NewRequest("POST", "/", nil)
   172  		testRequest(r, request, func(w *httptest.ResponseRecorder) {
   173  			response := w.Result()
   174  			if response.StatusCode != 401 {
   175  				t.Fatal()
   176  			}
   177  		})
   178  	})
   179  
   180  	t.Run("test unprotected report", func(t *testing.T) {
   181  		r := gin.Default()
   182  		r.POST("/",
   183  			func(c *gin.Context) {
   184  				WithSetting(c, &core.RepoSetting{
   185  					Protected: false,
   186  				})
   187  			},
   188  			ProtectReport(func(c *gin.Context) {
   189  				c.String(401, "")
   190  				c.Abort()
   191  			}, mockRepoStore, mockSCMService),
   192  		)
   193  		request, _ := http.NewRequest("POST", "/", nil)
   194  		testRequest(r, request, func(w *httptest.ResponseRecorder) {
   195  			response := w.Result()
   196  			if response.StatusCode != 200 {
   197  				t.Fatal()
   198  			}
   199  		})
   200  	})
   201  }
   202  
   203  func TestGetRepo(t *testing.T) {
   204  	ctrl := gomock.NewController(t)
   205  	defer ctrl.Finish()
   206  	store := mock.NewMockRepoStore(ctrl)
   207  	repo := &core.Repo{
   208  		ReportID: "1234",
   209  	}
   210  	store.EXPECT().Find(gomock.Eq(&core.Repo{
   211  		ReportID: "1234",
   212  	})).Return(repo, nil)
   213  
   214  	r := gin.Default()
   215  	r.GET("/reports/:id/repo", HandleRepo(store))
   216  	req, _ := http.NewRequest("GET", "/reports/1234/repo", nil)
   217  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   218  		rst := w.Result()
   219  		if rst.StatusCode != 200 {
   220  			t.Fail()
   221  		}
   222  		defer rst.Body.Close()
   223  		data, _ := ioutil.ReadAll(rst.Body)
   224  		rtnRepo := &core.Repo{}
   225  		json.Unmarshal(data, rtnRepo)
   226  		if !reflect.DeepEqual(repo, rtnRepo) {
   227  			t.Fail()
   228  		}
   229  	})
   230  }
   231  
   232  func TestGet(t *testing.T) {
   233  	ctrl := gomock.NewController(t)
   234  	defer ctrl.Finish()
   235  
   236  	repo := &core.Repo{
   237  		Branch:    "master",
   238  		Name:      "repo",
   239  		NameSpace: "org",
   240  		ReportID:  "1234",
   241  		SCM:       core.Github,
   242  	}
   243  
   244  	report := &core.Report{
   245  		ReportID:  "1234",
   246  		Reference: "master",
   247  	}
   248  
   249  	reportStore := mock.NewMockReportStore(ctrl)
   250  	repoStore := mock.NewMockRepoStore(ctrl)
   251  	service := mock.NewMockSCMService(ctrl)
   252  
   253  	repoStore.EXPECT().Find(gomock.Eq(&core.Repo{
   254  		ReportID: repo.ReportID,
   255  	})).AnyTimes().Return(repo, nil)
   256  	reportStore.EXPECT().Find(gomock.Eq(&core.Report{
   257  		ReportID:  report.ReportID,
   258  		Reference: repo.Branch,
   259  	})).Return(report, nil)
   260  	r := gin.Default()
   261  	r.GET("/reports/:id", HandleGet(reportStore, repoStore, service))
   262  
   263  	req, _ := http.NewRequest("GET", "/reports/1234", nil)
   264  	query := req.URL.Query()
   265  	query.Set("latest", "1")
   266  	req.URL.RawQuery = query.Encode()
   267  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   268  		rst := w.Result()
   269  		if rst.StatusCode != 200 {
   270  			t.Fail()
   271  		}
   272  		var reports []*core.Report
   273  		data, _ := ioutil.ReadAll(rst.Body)
   274  		json.Unmarshal(data, &reports)
   275  		if len(reports) < 1 || reports[0].ReportID != "1234" {
   276  			t.Fail()
   277  		}
   278  	})
   279  }
   280  
   281  func TestGetPrivate(t *testing.T) {
   282  	ctrl := gomock.NewController(t)
   283  	defer ctrl.Finish()
   284  	repo := &core.Repo{
   285  		Branch:    "master",
   286  		Name:      "repo",
   287  		NameSpace: "org",
   288  		ReportID:  "1234",
   289  		SCM:       core.Github,
   290  		Private:   true,
   291  	}
   292  	reportStore := mock.NewMockReportStore(ctrl)
   293  	repoStore := mock.NewMockRepoStore(ctrl)
   294  	service := mock.NewMockSCMService(ctrl)
   295  	client := mock.NewMockClient(ctrl)
   296  	repoService := mock.NewMockGitRepoService(ctrl)
   297  
   298  	repoStore.EXPECT().Find(
   299  		gomock.Eq(&core.Repo{ReportID: repo.ReportID}),
   300  	).AnyTimes().Return(repo, nil)
   301  
   302  	service.EXPECT().Client(
   303  		gomock.Eq(repo.SCM),
   304  	).Return(client, nil)
   305  
   306  	client.EXPECT().Repositories().Return(repoService)
   307  
   308  	repoService.EXPECT().Find(
   309  		gomock.Any(),
   310  		gomock.Any(),
   311  		gomock.Eq(repo.FullName()),
   312  	).Return(repo, fmt.Errorf(""))
   313  
   314  	// test if no user login
   315  	r := gin.Default()
   316  	r.GET("/reports/:id", HandleGet(reportStore, repoStore, service))
   317  
   318  	req, _ := http.NewRequest("GET", "/reports/1234", nil)
   319  
   320  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   321  		rst := w.Result()
   322  		if rst.StatusCode != 401 {
   323  			t.Fail()
   324  		}
   325  	})
   326  
   327  	// test if user login but without repository access right
   328  	r = gin.Default()
   329  	r.Use(func(c *gin.Context) {
   330  		request.WithUser(c, &core.User{})
   331  	})
   332  	r.GET("/reports/:id", HandleGet(reportStore, repoStore, service))
   333  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   334  		rst := w.Result()
   335  		if rst.StatusCode != 401 {
   336  			t.Fail()
   337  		}
   338  	})
   339  
   340  }
   341  
   342  func TestGetNotFound(t *testing.T) {
   343  	ctrl := gomock.NewController(t)
   344  	defer ctrl.Finish()
   345  	repo := &core.Repo{
   346  		ReportID: "1234",
   347  		SCM:      core.Github,
   348  	}
   349  
   350  	repoStore := mock.NewMockRepoStore(ctrl)
   351  	reportStore := mock.NewMockReportStore(ctrl)
   352  	service := mock.NewMockSCMService(ctrl)
   353  
   354  	repoStore.EXPECT().Find(gomock.Eq(&core.Repo{
   355  		ReportID: repo.ReportID,
   356  	})).AnyTimes().Return(repo, nil)
   357  
   358  	reportStore.EXPECT().Find(gomock.Any()).Return(nil, gorm.ErrRecordNotFound)
   359  
   360  	r := gin.Default()
   361  	r.GET("/reports/:id", HandleGet(reportStore, repoStore, service))
   362  
   363  	req, _ := http.NewRequest("GET", "/reports/1234", nil)
   364  	query := req.URL.Query()
   365  	query.Set("latest", "1")
   366  	req.URL.RawQuery = query.Encode()
   367  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   368  		rst := w.Result()
   369  		if rst.StatusCode != 404 {
   370  			t.Fail()
   371  		}
   372  	})
   373  }
   374  
   375  func TestGetTreeMap(t *testing.T) {
   376  	ctrl := gomock.NewController(t)
   377  	defer ctrl.Finish()
   378  	reportStore := mock.NewMockReportStore(ctrl)
   379  	repoStore := mock.NewMockRepoStore(ctrl)
   380  	chartService := mock.NewMockChartService(ctrl)
   381  	chart := mock.NewMockChart(ctrl)
   382  	reportID := "report_id"
   383  	repo := &core.Repo{
   384  		ReportID: reportID,
   385  		Branch:   "master",
   386  	}
   387  	old := &core.Report{
   388  		Coverages: []*core.CoverageReport{
   389  			{
   390  				Type: core.ReportGo,
   391  			},
   392  		},
   393  		ReportID:  reportID,
   394  		Reference: "master",
   395  		Commit:    "old",
   396  	}
   397  	new := &core.Report{
   398  		Coverages: []*core.CoverageReport{
   399  			{
   400  				Type: core.ReportGo,
   401  			},
   402  		},
   403  		ReportID:  reportID,
   404  		Reference: "new",
   405  		Commit:    "new",
   406  	}
   407  
   408  	repoStore.EXPECT().Find(gomock.Eq(&core.Repo{
   409  		ReportID: reportID,
   410  	})).Return(repo, nil)
   411  
   412  	reportStore.EXPECT().Find(gomock.Eq(
   413  		&core.Report{
   414  			Commit:   new.Reference,
   415  			ReportID: new.ReportID,
   416  		},
   417  	)).Return(nil, fmt.Errorf(""))
   418  
   419  	reportStore.EXPECT().Find(gomock.Eq(&core.Report{
   420  		ReportID:  reportID,
   421  		Reference: repo.Branch,
   422  	})).Return(old, nil)
   423  
   424  	reportStore.EXPECT().Find(gomock.Eq(&core.Report{
   425  		ReportID:  reportID,
   426  		Reference: new.Reference,
   427  	})).Return(new, nil)
   428  	chartService.EXPECT().CoverageDiffTreeMap(
   429  		gomock.Eq(old),
   430  		gomock.Eq(new),
   431  	).Return(chart)
   432  	chart.EXPECT().Render(gomock.Any()).Do(
   433  		func(w io.Writer) {
   434  			file, _ := os.Open(filepath.Join("testdata", "treemap.svg"))
   435  			defer file.Close()
   436  			io.Copy(w, file)
   437  		},
   438  	).Return(nil)
   439  
   440  	r := gin.Default()
   441  	r.GET("/reports/:id/treemap/*ref", HandleGetTreeMap(
   442  		reportStore,
   443  		repoStore,
   444  		chartService,
   445  	))
   446  
   447  	req, _ := http.NewRequest("GET", fmt.Sprintf(
   448  		"/reports/%s/treemap/%s",
   449  		reportID,
   450  		new.Reference,
   451  	), nil)
   452  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   453  		rst := w.Result()
   454  		if rst.StatusCode != 200 {
   455  			t.Fail()
   456  		}
   457  		file, _ := os.Open(filepath.Join("testdata", "treemap.svg"))
   458  		defer file.Close()
   459  		expect, _ := ioutil.ReadAll(file)
   460  		data, _ := ioutil.ReadAll(rst.Body)
   461  		if len(data) <= 0 || bytes.Compare(data, expect) != 0 {
   462  			t.Fail()
   463  		}
   464  	})
   465  }
   466  
   467  func TestGetCard(t *testing.T) {
   468  	ctrl := gomock.NewController(t)
   469  	defer ctrl.Finish()
   470  
   471  	mockRepo := mock.NewMockRepoStore(ctrl)
   472  	mockReport := mock.NewMockReportStore(ctrl)
   473  	mockChart := mock.NewMockChartService(ctrl)
   474  
   475  	repo := &core.Repo{
   476  		Branch:   "master",
   477  		ReportID: "report_id",
   478  	}
   479  	report := &core.Report{
   480  		ReportID: "report_id",
   481  	}
   482  
   483  	mockRepo.EXPECT().Find(
   484  		gomock.Eq(&core.Repo{ReportID: repo.ReportID}),
   485  	).Return(repo, nil)
   486  	mockReport.EXPECT().Find(
   487  		gomock.Eq(&core.Report{ReportID: repo.ReportID, Reference: repo.Branch}),
   488  	).Return(report, nil)
   489  	mockChart.EXPECT().RepoCard(
   490  		gomock.Eq(repo),
   491  		gomock.Eq(report),
   492  	).Return(charts.NewRepoCard(repo, report))
   493  
   494  	r := gin.Default()
   495  	r.GET("/reports/:id/card", HandleGetCard(
   496  		mockRepo,
   497  		mockReport,
   498  		mockChart,
   499  	))
   500  
   501  	req, _ := http.NewRequest("GET", fmt.Sprintf(
   502  		"/reports/%s/card",
   503  		repo.ReportID,
   504  	), nil)
   505  
   506  	testRequest(r, req, func(w *httptest.ResponseRecorder) {
   507  		result := w.Result()
   508  		if result.StatusCode != 200 {
   509  			t.Fatal()
   510  		}
   511  	})
   512  }