1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/sonar/taskService_test.go
Sven Merk 7fa31ae9cc
feat(http): Resilience via retry on intermittent communication issues (#2877)
* feat(http): Resilience on connectivity issues

* Update whitesourceExecuteScan.go

* Update splunk_test.go

* Fix initialization

* Change http interaction

* Fix fmt and tests

* Final test fix
2021-06-15 11:13:24 +02:00

232 lines
8.4 KiB
Go

package sonar
import (
"errors"
"net/http"
"testing"
"time"
"github.com/jarcoal/httpmock"
sonargo "github.com/magicsong/sonargo/sonar"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
piperhttp "github.com/SAP/jenkins-library/pkg/http"
)
func TestGetTask(t *testing.T) {
testURL := "https://example.org"
t.Run("success", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
sender := &piperhttp.Client{}
sender.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// add response handler
httpmock.RegisterResponder(http.MethodGet, testURL+"/api/"+EndpointCeTask+"", httpmock.NewStringResponder(http.StatusOK, responseCeTaskSuccess))
// create service instance
serviceUnderTest := NewTaskService(testURL, mock.Anything, mock.Anything, sender)
// test
result, response, err := serviceUnderTest.GetTask(&sonargo.CeTaskOption{Id: mock.Anything})
// assert
assert.NoError(t, err)
assert.NotEmpty(t, result)
assert.NotEmpty(t, response)
assert.Equal(t, 1, httpmock.GetTotalCallCount(), "unexpected number of requests")
})
t.Run("request error", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
sender := &piperhttp.Client{}
sender.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// add response handler
httpmock.RegisterResponder(http.MethodGet, testURL+"/api/"+EndpointCeTask+"", httpmock.NewErrorResponder(errors.New("internal server error")))
// create service instance
serviceUnderTest := NewTaskService(testURL, mock.Anything, mock.Anything, sender)
// test
result, response, err := serviceUnderTest.GetTask(&sonargo.CeTaskOption{Id: mock.Anything})
// assert
assert.Error(t, err)
assert.Contains(t, err.Error(), "internal server error")
assert.Empty(t, result)
assert.Empty(t, response)
assert.Equal(t, 1, httpmock.GetTotalCallCount(), "unexpected number of requests")
})
t.Run("server error", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
sender := &piperhttp.Client{}
sender.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// add response handler
httpmock.RegisterResponder(http.MethodGet, testURL+"/api/"+EndpointCeTask+"", httpmock.NewStringResponder(http.StatusNotFound, responseCeTaskError))
// create service instance
serviceUnderTest := NewTaskService(testURL, mock.Anything, mock.Anything, sender)
// test
result, response, err := serviceUnderTest.GetTask(&sonargo.CeTaskOption{Id: mock.Anything})
// assert
assert.Error(t, err)
assert.Contains(t, err.Error(), "No activity found for task ")
assert.Empty(t, result)
assert.NotEmpty(t, response)
assert.Equal(t, 1, httpmock.GetTotalCallCount(), "unexpected number of requests")
})
}
func TestWaitForTask(t *testing.T) {
testURL := "https://example.org"
t.Run("success", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
sender := &piperhttp.Client{}
sender.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// add response handler
httpmock.RegisterResponder(http.MethodGet, testURL+"/api/"+EndpointCeTask+"", httpmock.ResponderFromMultipleResponses(
[]*http.Response{
httpmock.NewStringResponse(http.StatusOK, responseCeTaskPending),
httpmock.NewStringResponse(http.StatusOK, responseCeTaskProcessing),
httpmock.NewStringResponse(http.StatusOK, responseCeTaskSuccess),
},
))
// create service instance
serviceUnderTest := NewTaskService(testURL, mock.Anything, mock.Anything, sender)
serviceUnderTest.PollInterval = time.Millisecond
// test
err := serviceUnderTest.WaitForTask()
// assert
assert.NoError(t, err)
assert.Equal(t, 3, httpmock.GetTotalCallCount(), "unexpected number of requests")
})
t.Run("failure", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
sender := &piperhttp.Client{}
sender.SetOptions(piperhttp.ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// add response handler
httpmock.RegisterResponder(http.MethodGet, testURL+"/api/"+EndpointCeTask+"", httpmock.ResponderFromMultipleResponses(
[]*http.Response{
httpmock.NewStringResponse(http.StatusOK, responseCeTaskPending),
httpmock.NewStringResponse(http.StatusOK, responseCeTaskProcessing),
httpmock.NewStringResponse(http.StatusNotFound, responseCeTaskFailure),
},
))
// create service instance
serviceUnderTest := NewTaskService(testURL, mock.Anything, mock.Anything, sender)
serviceUnderTest.PollInterval = time.Millisecond
// test
err := serviceUnderTest.WaitForTask()
// assert
assert.Error(t, err)
assert.Contains(t, err.Error(), "status: FAILED")
assert.Equal(t, 3, httpmock.GetTotalCallCount(), "unexpected number of requests")
})
}
const responseCeTaskError = `{
"errors": [
{
"msg": "No activity found for task 'AXDj5ZWQ_ZJrW2xGuBWl'"
}
]
}`
const responseCeTaskPending = `{
"task": {
"id": "AXe5y_ZMPMpzvP5DRxw_",
"type": "REPORT",
"componentId": "AW8jANn5v4pDRYwyZIiM",
"componentKey": "Piper-Validation/Golang",
"componentName": "Piper-Validation: Golang",
"componentQualifier": "TRK",
"analysisId": "AXe5y_mgcqEbAZBpFc0V",
"status": "PENDING",
"submittedAt": "2021-02-19T10:18:07+0000",
"submitterLogin": "CCFenner",
"startedAt": "2021-02-19T10:18:08+0000",
"executedAt": "2021-02-19T10:18:09+0000",
"executionTimeMs": 551,
"logs": false,
"hasScannerContext": true,
"organization": "default-organization",
"warningCount": 1,
"warnings": []
}
}`
const responseCeTaskProcessing = `{
"task": {
"id": "AXe5y_ZMPMpzvP5DRxw_",
"type": "REPORT",
"componentId": "AW8jANn5v4pDRYwyZIiM",
"componentKey": "Piper-Validation/Golang",
"componentName": "Piper-Validation: Golang",
"componentQualifier": "TRK",
"analysisId": "AXe5y_mgcqEbAZBpFc0V",
"status": "IN_PROGRESS",
"submittedAt": "2021-02-19T10:18:07+0000",
"submitterLogin": "CCFenner",
"startedAt": "2021-02-19T10:18:08+0000",
"executedAt": "2021-02-19T10:18:09+0000",
"executionTimeMs": 551,
"logs": false,
"hasScannerContext": true,
"organization": "default-organization",
"warningCount": 1,
"warnings": []
}
}`
const responseCeTaskSuccess = `{
"task": {
"id": "AXe5y_ZMPMpzvP5DRxw_",
"type": "REPORT",
"componentId": "AW8jANn5v4pDRYwyZIiM",
"componentKey": "Piper-Validation/Golang",
"componentName": "Piper-Validation: Golang",
"componentQualifier": "TRK",
"analysisId": "AXe5y_mgcqEbAZBpFc0V",
"status": "SUCCESS",
"submittedAt": "2021-02-19T10:18:07+0000",
"submitterLogin": "CCFenner",
"startedAt": "2021-02-19T10:18:08+0000",
"executedAt": "2021-02-19T10:18:09+0000",
"executionTimeMs": 551,
"logs": false,
"hasScannerContext": true,
"organization": "default-organization",
"warningCount": 1,
"warnings": [
"The project key ‘Piper-Validation/Golang’ contains invalid characters. Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit. You should update the project key with the expected format."
]
}
}`
const responseCeTaskFailure = `{
"task": {
"organization": "my-org-1",
"id": "AVAn5RKqYwETbXvgas-I",
"type": "REPORT",
"componentId": "AVAn5RJmYwETbXvgas-H",
"componentKey": "project_1",
"componentName": "Project One",
"componentQualifier": "TRK",
"analysisId": "123456",
"status": "FAILED",
"submittedAt": "2015-10-02T11:32:15+0200",
"startedAt": "2015-10-02T11:32:16+0200",
"executedAt": "2015-10-02T11:32:22+0200",
"executionTimeMs": 5286,
"errorMessage": "Fail to extract report AVaXuGAi_te3Ldc_YItm from database",
"logs": false,
"hasErrorStacktrace": true,
"errorStacktrace": "java.lang.IllegalStateException: Fail to extract report AVaXuGAi_te3Ldc_YItm from database\n\tat org.sonar.server.computation.task.projectanalysis.step.ExtractReportStep.execute(ExtractReportStep.java:50)",
"scannerContext": "SonarQube plugins:\n\t- Git 1.0 (scmgit)\n\t- Java 3.13.1 (java)",
"hasScannerContext": true
}
}`