diff --git a/internal/api/gitea.go b/internal/api/gitea.go index c96ffbc..13660b1 100644 --- a/internal/api/gitea.go +++ b/internal/api/gitea.go @@ -12,6 +12,11 @@ import ( webhook "gitea-sonarqube-pr-bot/internal/webhooks/gitea" ) +type GiteaWebhookHandlerInferface interface { + HandleSynchronize(rw http.ResponseWriter, r *http.Request) + HandleComment(rw http.ResponseWriter, r *http.Request) +} + type GiteaWebhookHandler struct { giteaSdk giteaSdk.GiteaSdkInterface sqSdk sqSdk.SonarQubeSdkInterface @@ -88,7 +93,7 @@ func (h *GiteaWebhookHandler) HandleComment(rw http.ResponseWriter, r *http.Requ w.ProcessData(h.giteaSdk, h.sqSdk) } -func NewGiteaWebhookHandler(g giteaSdk.GiteaSdkInterface, sq sqSdk.SonarQubeSdkInterface) *GiteaWebhookHandler { +func NewGiteaWebhookHandler(g giteaSdk.GiteaSdkInterface, sq sqSdk.SonarQubeSdkInterface) GiteaWebhookHandlerInferface { return &GiteaWebhookHandler{ giteaSdk: g, sqSdk: sq, diff --git a/internal/api/main.go b/internal/api/main.go index aa92dfe..f71d4ef 100644 --- a/internal/api/main.go +++ b/internal/api/main.go @@ -12,20 +12,16 @@ import ( "github.com/urfave/cli/v2" ) -func addPingApi(r *gin.Engine) { - r.GET("/ping", func(c *gin.Context) { - c.JSON(http.StatusOK, gin.H{ - "message": "pong", - }) - }) -} +var ( + sonarQubeWebhookHandler SonarQubeWebhookHandlerInferface + giteaWebhookHandler GiteaWebhookHandlerInferface +) type validSonarQubeEndpointHeader struct { SonarQubeProject string `header:"X-SonarQube-Project" binding:"required"` } func addSonarQubeEndpoint(r *gin.Engine) { - webhookHandler := NewSonarQubeWebhookHandler(giteaSdk.New(), sqSdk.New()) r.POST("/hooks/sonarqube", func(c *gin.Context) { h := validSonarQubeEndpointHeader{} @@ -34,7 +30,7 @@ func addSonarQubeEndpoint(r *gin.Engine) { return } - webhookHandler.Handle(c.Writer, c.Request) + sonarQubeWebhookHandler.Handle(c.Writer, c.Request) }) } @@ -43,7 +39,6 @@ type validGiteaEndpointHeader struct { } func addGiteaEndpoint(r *gin.Engine) { - webhookHandler := NewGiteaWebhookHandler(giteaSdk.New(), sqSdk.New()) r.POST("/hooks/gitea", func(c *gin.Context) { h := validGiteaEndpointHeader{} @@ -54,9 +49,9 @@ func addGiteaEndpoint(r *gin.Engine) { switch h.GiteaEvent { case "pull_request": - webhookHandler.HandleSynchronize(c.Writer, c.Request) + giteaWebhookHandler.HandleSynchronize(c.Writer, c.Request) case "issue_comment": - webhookHandler.HandleComment(c.Writer, c.Request) + giteaWebhookHandler.HandleComment(c.Writer, c.Request) default: c.JSON(http.StatusOK, gin.H{ "message": "ignore unknown event", @@ -65,9 +60,7 @@ func addGiteaEndpoint(r *gin.Engine) { }) } -func Serve(c *cli.Context) error { - fmt.Println("Hi! I'm the Gitea-SonarQube-PR bot. At your service.") - +func setupRouter() *gin.Engine { r := gin.New() r.Use(gin.Recovery()) @@ -75,13 +68,28 @@ func Serve(c *cli.Context) error { SkipPaths: []string{"/ping", "/favicon.ico"}, })) - addPingApi(r) - addSonarQubeEndpoint(r) - addGiteaEndpoint(r) - + r.GET("/ping", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "message": "pong", + }) + }) r.GET("/favicon.ico", func(c *gin.Context) { c.Status(http.StatusNoContent) }) + addSonarQubeEndpoint(r) + addGiteaEndpoint(r) + + return r +} + +func Serve(c *cli.Context) error { + fmt.Println("Hi! I'm the Gitea-SonarQube-PR bot. At your service.") + + sonarQubeWebhookHandler = NewSonarQubeWebhookHandler(giteaSdk.New(), sqSdk.New()) + giteaWebhookHandler = NewGiteaWebhookHandler(giteaSdk.New(), sqSdk.New()) + + r := setupRouter() + return endless.ListenAndServe(":3000", r) } diff --git a/internal/api/main_test.go b/internal/api/main_test.go index 8b27e47..f4fc87f 100644 --- a/internal/api/main_test.go +++ b/internal/api/main_test.go @@ -1,26 +1,41 @@ package api import ( + "bytes" "io/ioutil" "log" + "net/http" + "net/http/httptest" "os" "testing" giteaSdk "gitea-sonarqube-pr-bot/internal/clients/gitea" sqSdk "gitea-sonarqube-pr-bot/internal/clients/sonarqube" "gitea-sonarqube-pr-bot/internal/settings" - webhook "gitea-sonarqube-pr-bot/internal/webhooks/sonarqube" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) -// Default SDK mocking -type HandlerPartialMock struct { +type SonarQubeHandlerMock struct { mock.Mock } -func (h *HandlerPartialMock) fetchDetails(w *webhook.Webhook) { - h.Called(w) +func (h *SonarQubeHandlerMock) Handle(rw http.ResponseWriter, r *http.Request) { + h.Called(rw, r) +} + +type GiteaHandlerMock struct { + mock.Mock +} + +func (h *GiteaHandlerMock) HandleSynchronize(rw http.ResponseWriter, r *http.Request) { + h.Called(rw, r) +} + +func (h *GiteaHandlerMock) HandleComment(rw http.ResponseWriter, r *http.Request) { + h.Called(rw, r) } type GiteaSdkMock struct { @@ -65,12 +80,116 @@ func (h *SQSdkMock) ComposeGiteaComment(data *sqSdk.CommentComposeData) (string, return "", nil } -func defaultMockPreparation(h *HandlerPartialMock) { - h.On("fetchDetails", mock.Anything).Return(nil) -} - // SETUP: mute logs func TestMain(m *testing.M) { + sonarQubeWebhookHandler = nil + giteaWebhookHandler = nil + + gin.SetMode(gin.TestMode) log.SetOutput(ioutil.Discard) os.Exit(m.Run()) } + +func TestNonAPIRoutes(t *testing.T) { + router := setupRouter() + + w := httptest.NewRecorder() + req, _ := http.NewRequest("GET", "/favicon.ico", nil) + router.ServeHTTP(w, req) + assert.Equal(t, http.StatusNoContent, w.Code) + + w = httptest.NewRecorder() + req, _ = http.NewRequest("GET", "/ping", nil) + router.ServeHTTP(w, req) + assert.Equal(t, http.StatusOK, w.Code) +} + +func TestSonarQubeAPIRouteMissingProjectHeader(t *testing.T) { + router := setupRouter() + + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/hooks/sonarqube", bytes.NewBuffer([]byte(`{}`))) + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusNotFound, w.Code) +} + +func TestSonarQubeAPIRouteProcessing(t *testing.T) { + router := setupRouter() + + sonarQubeHandlerMock := new(SonarQubeHandlerMock) + sonarQubeHandlerMock.On("Handle", mock.Anything, mock.Anything).Return(nil) + sonarQubeWebhookHandler = sonarQubeHandlerMock + + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/hooks/sonarqube", bytes.NewBuffer([]byte(`{}`))) + req.Header.Add("X-SonarQube-Project", "gitea-sonarqube-bot") + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + sonarQubeHandlerMock.AssertNumberOfCalls(t, "Handle", 1) +} + +func TestGiteaAPIRouteMissingEventHeader(t *testing.T) { + router := setupRouter() + + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/hooks/gitea", bytes.NewBuffer([]byte(`{}`))) + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusNotFound, w.Code) +} + +func TestGiteaAPIRouteSynchronizeProcessing(t *testing.T) { + router := setupRouter() + + giteaHandlerMock := new(GiteaHandlerMock) + giteaHandlerMock.On("HandleSynchronize", mock.Anything, mock.Anything).Return(nil) + giteaHandlerMock.On("HandleComment", mock.Anything, mock.Anything).Return(nil) + giteaWebhookHandler = giteaHandlerMock + + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/hooks/gitea", bytes.NewBuffer([]byte(`{}`))) + req.Header.Add("X-Gitea-Event", "pull_request") + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + giteaHandlerMock.AssertNumberOfCalls(t, "HandleSynchronize", 1) + giteaHandlerMock.AssertNumberOfCalls(t, "HandleComment", 0) +} + +func TestGiteaAPIRouteCommentProcessing(t *testing.T) { + router := setupRouter() + + giteaHandlerMock := new(GiteaHandlerMock) + giteaHandlerMock.On("HandleSynchronize", mock.Anything, mock.Anything).Return(nil) + giteaHandlerMock.On("HandleComment", mock.Anything, mock.Anything).Return(nil) + giteaWebhookHandler = giteaHandlerMock + + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/hooks/gitea", bytes.NewBuffer([]byte(`{}`))) + req.Header.Add("X-Gitea-Event", "issue_comment") + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + giteaHandlerMock.AssertNumberOfCalls(t, "HandleSynchronize", 0) + giteaHandlerMock.AssertNumberOfCalls(t, "HandleComment", 1) +} + +func TestGiteaAPIRouteUnknownEvent(t *testing.T) { + router := setupRouter() + + giteaHandlerMock := new(GiteaHandlerMock) + giteaHandlerMock.On("HandleSynchronize", mock.Anything, mock.Anything).Return(nil) + giteaHandlerMock.On("HandleComment", mock.Anything, mock.Anything).Return(nil) + giteaWebhookHandler = giteaHandlerMock + + w := httptest.NewRecorder() + req, _ := http.NewRequest("POST", "/hooks/gitea", bytes.NewBuffer([]byte(`{}`))) + req.Header.Add("X-Gitea-Event", "unknown") + router.ServeHTTP(w, req) + + assert.Equal(t, http.StatusOK, w.Code) + giteaHandlerMock.AssertNumberOfCalls(t, "HandleSynchronize", 0) + giteaHandlerMock.AssertNumberOfCalls(t, "HandleComment", 0) +} diff --git a/internal/api/sonarqube.go b/internal/api/sonarqube.go index 77fbf30..6a73d49 100644 --- a/internal/api/sonarqube.go +++ b/internal/api/sonarqube.go @@ -14,10 +14,13 @@ import ( webhook "gitea-sonarqube-pr-bot/internal/webhooks/sonarqube" ) +type SonarQubeWebhookHandlerInferface interface { + Handle(rw http.ResponseWriter, r *http.Request) +} + type SonarQubeWebhookHandler struct { - fetchDetails func(w *webhook.Webhook) - giteaSdk giteaSdk.GiteaSdkInterface - sqSdk sqSdk.SonarQubeSdkInterface + giteaSdk giteaSdk.GiteaSdkInterface + sqSdk sqSdk.SonarQubeSdkInterface } func (*SonarQubeWebhookHandler) inProjectsMapping(p []settings.Project, n string) (bool, int) { @@ -31,13 +34,6 @@ func (*SonarQubeWebhookHandler) inProjectsMapping(p []settings.Project, n string } func (h *SonarQubeWebhookHandler) processData(w *webhook.Webhook, repo settings.GiteaRepository) { - if strings.ToLower(w.Branch.Type) != "pull_request" { - log.Println("Ignore Hook for non-PR") - return - } - - h.fetchDetails(w) - status := giteaSdk.StatusOK if w.QualityGate.Status != "OK" { status = giteaSdk.StatusFailure @@ -96,19 +92,21 @@ func (h *SonarQubeWebhookHandler) Handle(rw http.ResponseWriter, r *http.Request // Send response to SonarQube at this point to ensure being within 10 seconds limit of webhook response timeout rw.WriteHeader(http.StatusOK) + + if strings.ToLower(w.Branch.Type) != "pull_request" { + io.WriteString(rw, `{"message": "Ignore Hook for non-PR analysis."}`) + log.Println("Ignore Hook for non-PR analysis") + return + } + io.WriteString(rw, `{"message": "Processing data. See bot logs for details."}`) h.processData(w, settings.Projects[pIdx].Gitea) } -func fetchDetails(w *webhook.Webhook) { - log.Printf("This method will load additional data from SonarQube based on PR %d", w.PRIndex) -} - -func NewSonarQubeWebhookHandler(g giteaSdk.GiteaSdkInterface, sq sqSdk.SonarQubeSdkInterface) *SonarQubeWebhookHandler { +func NewSonarQubeWebhookHandler(g giteaSdk.GiteaSdkInterface, sq sqSdk.SonarQubeSdkInterface) SonarQubeWebhookHandlerInferface { return &SonarQubeWebhookHandler{ - fetchDetails: fetchDetails, - giteaSdk: g, - sqSdk: sq, + giteaSdk: g, + sqSdk: sq, } } diff --git a/internal/api/sonarqube_test.go b/internal/api/sonarqube_test.go index ce5011e..d0643ef 100644 --- a/internal/api/sonarqube_test.go +++ b/internal/api/sonarqube_test.go @@ -11,12 +11,8 @@ import ( "github.com/stretchr/testify/assert" ) -func withValidSonarQubeRequestData(t *testing.T, mockPreparation func(*HandlerPartialMock), jsonBody []byte) (*http.Request, *httptest.ResponseRecorder, http.HandlerFunc, *HandlerPartialMock) { - partialMock := new(HandlerPartialMock) - mockPreparation(partialMock) - +func withValidSonarQubeRequestData(t *testing.T, jsonBody []byte) (*http.Request, *httptest.ResponseRecorder, http.HandlerFunc) { webhookHandler := NewSonarQubeWebhookHandler(new(GiteaSdkMock), new(SQSdkMock)) - webhookHandler.fetchDetails = partialMock.fetchDetails req, err := http.NewRequest("POST", "/hooks/sonarqube", bytes.NewBuffer(jsonBody)) if err != nil { @@ -27,7 +23,7 @@ func withValidSonarQubeRequestData(t *testing.T, mockPreparation func(*HandlerPa rr := httptest.NewRecorder() handler := http.HandlerFunc(webhookHandler.Handle) - return req, rr, handler, partialMock + return req, rr, handler } func TestHandleSonarQubeWebhookProjectMapped(t *testing.T) { @@ -38,7 +34,7 @@ func TestHandleSonarQubeWebhookProjectMapped(t *testing.T) { }, }, } - req, rr, handler, _ := withValidSonarQubeRequestData(t, defaultMockPreparation, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "PULL_REQUEST", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) + req, rr, handler := withValidSonarQubeRequestData(t, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "PULL_REQUEST", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusOK, rr.Code) @@ -53,7 +49,7 @@ func TestHandleSonarQubeWebhookProjectNotMapped(t *testing.T) { }, }, } - req, rr, handler, _ := withValidSonarQubeRequestData(t, defaultMockPreparation, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "PULL_REQUEST", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) + req, rr, handler := withValidSonarQubeRequestData(t, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "PULL_REQUEST", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusOK, rr.Code) @@ -69,7 +65,7 @@ func TestHandleSonarQubeWebhookInvalidJSONBody(t *testing.T) { }, } - req, rr, handler, _ := withValidSonarQubeRequestData(t, defaultMockPreparation, []byte(`{ "serverUrl": ["invalid-server-url-content"] }`)) + req, rr, handler := withValidSonarQubeRequestData(t, []byte(`{ "serverUrl": ["invalid-server-url-content"] }`)) handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusUnprocessableEntity, rr.Code) @@ -85,12 +81,11 @@ func TestHandleSonarQubeWebhookForPullRequest(t *testing.T) { }, } - req, rr, handler, partialMock := withValidSonarQubeRequestData(t, defaultMockPreparation, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "PULL_REQUEST", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) + req, rr, handler := withValidSonarQubeRequestData(t, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "PULL_REQUEST", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusOK, rr.Code) assert.Equal(t, `{"message": "Processing data. See bot logs for details."}`, rr.Body.String()) - partialMock.AssertNumberOfCalls(t, "fetchDetails", 1) } func TestHandleSonarQubeWebhookForBranch(t *testing.T) { @@ -102,10 +97,9 @@ func TestHandleSonarQubeWebhookForBranch(t *testing.T) { }, } - req, rr, handler, partialMock := withValidSonarQubeRequestData(t, defaultMockPreparation, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "BRANCH", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) + req, rr, handler := withValidSonarQubeRequestData(t, []byte(`{ "serverUrl": "https://example.com/sonarqube", "taskId": "AXouyxDpizdp4B1K", "status": "SUCCESS", "analysedAt": "2021-05-21T12:12:07+0000", "revision": "f84442009c09b1adc278b6aa80a3853419f54007", "changedAt": "2021-05-21T12:12:07+0000", "project": { "key": "pr-bot", "name": "PR Bot", "url": "https://example.com/sonarqube/dashboard?id=pr-bot" }, "branch": { "name": "PR-1337", "type": "BRANCH", "isMain": false, "url": "https://example.com/sonarqube/dashboard?id=pr-bot&pullRequest=PR-1337" }, "qualityGate": { "name": "PR Bot", "status": "OK", "conditions": [ { "metric": "new_reliability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_maintainability_rating", "operator": "GREATER_THAN", "value": "1", "status": "OK", "errorThreshold": "1" }, { "metric": "new_security_hotspots_reviewed", "operator": "LESS_THAN", "status": "NO_VALUE", "errorThreshold": "100" } ] }, "properties": {} }`)) handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusOK, rr.Code) - assert.Equal(t, `{"message": "Processing data. See bot logs for details."}`, rr.Body.String()) - partialMock.AssertNumberOfCalls(t, "fetchDetails", 0) + assert.Equal(t, `{"message": "Ignore Hook for non-PR analysis."}`, rr.Body.String()) }