2021-10-10 16:18:14 +02:00
|
|
|
package api
|
2021-06-24 14:38:04 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"testing"
|
|
|
|
|
2021-10-10 16:28:59 +02:00
|
|
|
giteaSdk "gitea-sonarqube-pr-bot/internal/clients/gitea"
|
2021-10-10 16:43:37 +02:00
|
|
|
sqSdk "gitea-sonarqube-pr-bot/internal/clients/sonarqube"
|
2021-06-29 11:59:49 +02:00
|
|
|
"gitea-sonarqube-pr-bot/internal/settings"
|
|
|
|
webhook "gitea-sonarqube-pr-bot/internal/webhooks/sonarqube"
|
2021-10-03 17:49:23 +02:00
|
|
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/mock"
|
2021-06-24 14:38:04 +02:00
|
|
|
)
|
|
|
|
|
2021-07-11 12:28:00 +02:00
|
|
|
type HandlerPartialMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *HandlerPartialMock) fetchDetails(w *webhook.Webhook) {
|
|
|
|
h.Called(w)
|
|
|
|
}
|
|
|
|
|
2021-07-12 12:36:22 +02:00
|
|
|
type GiteaSdkMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *GiteaSdkMock) PostComment(_ settings.GiteaRepository, _ int, _ string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-10-10 15:58:03 +02:00
|
|
|
func (h *GiteaSdkMock) DetermineHEAD(_ settings.GiteaRepository, _ int64) (string, error) {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
2021-10-10 16:28:59 +02:00
|
|
|
func (h *GiteaSdkMock) UpdateStatus(_ settings.GiteaRepository, _ string, _ giteaSdk.StatusDetails) error {
|
2021-10-09 21:09:23 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-10-03 17:49:23 +02:00
|
|
|
type SQSdkMock struct {
|
|
|
|
mock.Mock
|
|
|
|
}
|
|
|
|
|
2021-10-10 16:43:37 +02:00
|
|
|
func (h *SQSdkMock) GetMeasures(project string, branch string) (*sqSdk.MeasuresResponse, error) {
|
|
|
|
return &sqSdk.MeasuresResponse{}, nil
|
2021-10-03 17:49:23 +02:00
|
|
|
}
|
|
|
|
|
2021-10-10 19:01:48 +02:00
|
|
|
func (h *SQSdkMock) GetPullRequestUrl(project string, index int64) string {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *SQSdkMock) GetPullRequest(project string, index int64) (*sqSdk.PullRequest, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2021-07-11 12:28:00 +02:00
|
|
|
func defaultMockPreparation(h *HandlerPartialMock) {
|
|
|
|
h.On("fetchDetails", mock.Anything).Return(nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func withValidRequestData(t *testing.T, mockPreparation func(*HandlerPartialMock), jsonBody []byte) (*http.Request, *httptest.ResponseRecorder, http.HandlerFunc, *HandlerPartialMock) {
|
|
|
|
partialMock := new(HandlerPartialMock)
|
|
|
|
mockPreparation(partialMock)
|
|
|
|
|
2021-10-03 17:49:23 +02:00
|
|
|
webhookHandler := NewSonarQubeWebhookHandler(new(GiteaSdkMock), new(SQSdkMock))
|
2021-07-11 12:28:00 +02:00
|
|
|
webhookHandler.fetchDetails = partialMock.fetchDetails
|
2021-06-29 11:59:49 +02:00
|
|
|
|
2021-06-24 14:38:04 +02:00
|
|
|
req, err := http.NewRequest("POST", "/hooks/sonarqube", bytes.NewBuffer(jsonBody))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
req.Header.Set("X-SonarQube-Project", "pr-bot")
|
|
|
|
|
|
|
|
rr := httptest.NewRecorder()
|
2021-06-29 11:59:49 +02:00
|
|
|
handler := http.HandlerFunc(webhookHandler.Handle)
|
2021-06-24 14:38:04 +02:00
|
|
|
|
2021-07-11 12:28:00 +02:00
|
|
|
return req, rr, handler, partialMock
|
2021-06-24 14:38:04 +02:00
|
|
|
}
|
|
|
|
|
2021-06-29 11:59:49 +02:00
|
|
|
func TestHandleSonarQubeWebhookProjectMapped(t *testing.T) {
|
2021-06-24 14:38:04 +02:00
|
|
|
settings.Projects = []settings.Project{
|
|
|
|
settings.Project{
|
2021-10-03 17:49:23 +02:00
|
|
|
SonarQube: struct{ Key string }{
|
2021-06-24 14:38:04 +02:00
|
|
|
Key: "pr-bot",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2021-07-11 12:28:00 +02:00
|
|
|
req, rr, handler, _ := withValidRequestData(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": {} }`))
|
2021-06-24 14:38:04 +02:00
|
|
|
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())
|
|
|
|
}
|
|
|
|
|
2021-06-29 11:59:49 +02:00
|
|
|
func TestHandleSonarQubeWebhookProjectNotMapped(t *testing.T) {
|
2021-06-24 14:38:04 +02:00
|
|
|
settings.Projects = []settings.Project{
|
|
|
|
settings.Project{
|
2021-10-03 17:49:23 +02:00
|
|
|
SonarQube: struct{ Key string }{
|
2021-06-24 14:38:04 +02:00
|
|
|
Key: "another-project",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2021-07-11 12:28:00 +02:00
|
|
|
req, rr, handler, _ := withValidRequestData(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": {} }`))
|
2021-06-24 14:38:04 +02:00
|
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusOK, rr.Code)
|
|
|
|
assert.Equal(t, `{"message": "Project 'pr-bot' not in configured list. Request ignored."}`, rr.Body.String())
|
|
|
|
}
|
|
|
|
|
2021-06-29 11:59:49 +02:00
|
|
|
func TestHandleSonarQubeWebhookInvalidJSONBody(t *testing.T) {
|
2021-06-24 14:38:04 +02:00
|
|
|
settings.Projects = []settings.Project{
|
|
|
|
settings.Project{
|
2021-10-03 17:49:23 +02:00
|
|
|
SonarQube: struct{ Key string }{
|
2021-06-24 14:38:04 +02:00
|
|
|
Key: "pr-bot",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2021-07-11 12:28:00 +02:00
|
|
|
req, rr, handler, _ := withValidRequestData(t, defaultMockPreparation, []byte(`{ "serverUrl": ["invalid-server-url-content"] }`))
|
2021-06-24 14:38:04 +02:00
|
|
|
handler.ServeHTTP(rr, req)
|
|
|
|
|
|
|
|
assert.Equal(t, http.StatusUnprocessableEntity, rr.Code)
|
|
|
|
assert.Equal(t, `{"message": "Error parsing POST body."}`, rr.Body.String())
|
|
|
|
}
|
2021-07-11 12:28:00 +02:00
|
|
|
|
|
|
|
func TestHandleSonarQubeWebhookForPullRequest(t *testing.T) {
|
|
|
|
settings.Projects = []settings.Project{
|
|
|
|
settings.Project{
|
2021-10-03 17:49:23 +02:00
|
|
|
SonarQube: struct{ Key string }{
|
2021-07-11 12:28:00 +02:00
|
|
|
Key: "pr-bot",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
req, rr, handler, partialMock := withValidRequestData(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": {} }`))
|
|
|
|
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) {
|
|
|
|
settings.Projects = []settings.Project{
|
|
|
|
settings.Project{
|
2021-10-03 17:49:23 +02:00
|
|
|
SonarQube: struct{ Key string }{
|
2021-07-11 12:28:00 +02:00
|
|
|
Key: "pr-bot",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
req, rr, handler, partialMock := withValidRequestData(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": {} }`))
|
|
|
|
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)
|
|
|
|
}
|