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 }