mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
5f4cd838cf
* Add StepStartTime, Renames StepDuration, adds PiperCommithash, removes Branch, GitOwner, GitRepository from logged telemetry information * Fixes test case for telemetry logging * Activates step monitoring data in debug mode * Pretty debug json printing * Reduces log noise, setting warning to debug
351 lines
9.1 KiB
Go
351 lines
9.1 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"github.com/SAP/jenkins-library/pkg/log"
|
|
"github.com/SAP/jenkins-library/pkg/orchestrator"
|
|
"github.com/jarcoal/httpmock"
|
|
"github.com/sirupsen/logrus"
|
|
"github.com/sirupsen/logrus/hooks/test"
|
|
"net/http"
|
|
"reflect"
|
|
"regexp"
|
|
"testing"
|
|
"time"
|
|
|
|
piperhttp "github.com/SAP/jenkins-library/pkg/http"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestTelemetry_Initialize(t *testing.T) {
|
|
type fields struct {
|
|
baseData BaseData
|
|
baseMetaData BaseMetaData
|
|
data Data
|
|
provider orchestrator.OrchestratorSpecificConfigProviding
|
|
disabled bool
|
|
client *piperhttp.Client
|
|
CustomReportingDsn string
|
|
CustomReportingToken string
|
|
customClient *piperhttp.Client
|
|
BaseURL string
|
|
Endpoint string
|
|
SiteID string
|
|
}
|
|
type args struct {
|
|
telemetryDisabled bool
|
|
stepName string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
args args
|
|
want *piperhttp.Client
|
|
}{
|
|
{
|
|
name: "telemetry disabled",
|
|
fields: fields{},
|
|
args: args{
|
|
telemetryDisabled: true,
|
|
stepName: "test",
|
|
},
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "telemetry enabled",
|
|
fields: fields{},
|
|
args: args{
|
|
telemetryDisabled: false,
|
|
stepName: "test",
|
|
},
|
|
want: &piperhttp.Client{},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
telemetryClient := &Telemetry{}
|
|
telemetryClient.Initialize(tt.args.telemetryDisabled, tt.args.stepName)
|
|
// assert
|
|
assert.NotEqual(t, tt.want, telemetryClient.client)
|
|
assert.Equal(t, tt.args.stepName, telemetryClient.baseData.StepName)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTelemetry_Send(t *testing.T) {
|
|
type fields struct {
|
|
baseData BaseData
|
|
baseMetaData BaseMetaData
|
|
data Data
|
|
provider orchestrator.OrchestratorSpecificConfigProviding
|
|
disabled bool
|
|
client *piperhttp.Client
|
|
CustomReportingDsn string
|
|
CustomReportingToken string
|
|
BaseURL string
|
|
Endpoint string
|
|
SiteID string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
swaCalls int
|
|
}{
|
|
{
|
|
name: "Telemetry disabled, reporting disabled",
|
|
fields: fields{
|
|
disabled: true,
|
|
},
|
|
swaCalls: 0,
|
|
},
|
|
{
|
|
name: "Telemetry enabled",
|
|
fields: fields{
|
|
disabled: false,
|
|
},
|
|
swaCalls: 1,
|
|
},
|
|
{
|
|
name: "Telemetry disabled",
|
|
fields: fields{
|
|
disabled: true,
|
|
},
|
|
swaCalls: 0,
|
|
},
|
|
}
|
|
|
|
httpmock.Activate()
|
|
defer httpmock.DeactivateAndReset()
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
httpmock.Reset()
|
|
telemetryClient := &Telemetry{disabled: tt.fields.disabled}
|
|
telemetryClient.Initialize(tt.fields.disabled, tt.name)
|
|
telemetryClient.CustomReportingDsn = tt.fields.CustomReportingDsn
|
|
if telemetryClient.client == nil {
|
|
telemetryClient.client = &piperhttp.Client{}
|
|
}
|
|
|
|
url := telemetryClient.BaseURL + telemetryClient.Endpoint
|
|
|
|
telemetryClient.client.SetOptions(piperhttp.ClientOptions{
|
|
MaxRequestDuration: 5 * time.Second,
|
|
Token: "TOKEN",
|
|
TransportSkipVerification: true,
|
|
UseDefaultTransport: true,
|
|
MaxRetries: -1,
|
|
})
|
|
|
|
if tt.fields.CustomReportingDsn != "" {
|
|
telemetryClient.customClient = &piperhttp.Client{}
|
|
telemetryClient.customClient.SetOptions(piperhttp.ClientOptions{
|
|
MaxRequestDuration: 5 * time.Second,
|
|
Token: "TOKEN",
|
|
TransportSkipVerification: true,
|
|
UseDefaultTransport: true, // Needed for mocking
|
|
MaxRetries: -1,
|
|
})
|
|
}
|
|
|
|
httpmock.RegisterResponder(http.MethodGet, url,
|
|
func(req *http.Request) (*http.Response, error) {
|
|
return httpmock.NewStringResponse(200, "Ok"), nil
|
|
},
|
|
)
|
|
httpmock.RegisterResponder(http.MethodPost, telemetryClient.CustomReportingDsn,
|
|
func(req *http.Request) (*http.Response, error) {
|
|
return httpmock.NewStringResponse(200, "Ok"), nil
|
|
},
|
|
)
|
|
|
|
// test
|
|
telemetryClient.SetData(&CustomData{})
|
|
telemetryClient.Send()
|
|
|
|
// assert
|
|
info := httpmock.GetCallCountInfo()
|
|
|
|
if got := info["GET "+url]; !assert.Equal(t, got, tt.swaCalls) {
|
|
t.Errorf("Send() = swa calls %v, wanted %v", got, tt.swaCalls)
|
|
}
|
|
|
|
})
|
|
}
|
|
defer httpmock.DeactivateAndReset()
|
|
}
|
|
|
|
func TestSetData(t *testing.T) {
|
|
type args struct {
|
|
customData *CustomData
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want Data
|
|
}{
|
|
{
|
|
name: "Test",
|
|
args: args{customData: &CustomData{
|
|
Duration: "100",
|
|
ErrorCode: "0",
|
|
ErrorCategory: "Undefined",
|
|
PiperCommitHash: "abcd12345",
|
|
},
|
|
},
|
|
want: Data{
|
|
BaseData: BaseData{
|
|
URL: "",
|
|
ActionName: "",
|
|
EventType: "",
|
|
StepName: "TestCreateDataObject",
|
|
SiteID: "",
|
|
PipelineURLHash: "",
|
|
BuildURLHash: "",
|
|
Orchestrator: "Unknown",
|
|
},
|
|
BaseMetaData: BaseMetaData{
|
|
StepNameLabel: "stepName",
|
|
StageNameLabel: "stageName",
|
|
PipelineURLHashLabel: "pipelineUrlHash",
|
|
BuildURLHashLabel: "buildUrlHash",
|
|
DurationLabel: "duration",
|
|
ExitCodeLabel: "exitCode",
|
|
ErrorCategoryLabel: "errorCategory",
|
|
OrchestratorLabel: "orchestrator",
|
|
PiperCommitHashLabel: "piperCommitHash",
|
|
},
|
|
CustomData: CustomData{
|
|
Duration: "100",
|
|
ErrorCode: "0",
|
|
ErrorCategory: "Undefined",
|
|
PiperCommitHash: "abcd12345",
|
|
Custom1Label: "",
|
|
Custom2Label: "",
|
|
Custom3Label: "",
|
|
Custom4Label: "",
|
|
Custom5Label: "",
|
|
Custom1: "",
|
|
Custom2: "",
|
|
Custom3: "",
|
|
Custom4: "",
|
|
Custom5: "",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
telemetryClient := Telemetry{}
|
|
telemetryClient.Initialize(false, "TestCreateDataObject")
|
|
telemetryClient.baseData = BaseData{
|
|
URL: "",
|
|
ActionName: "",
|
|
EventType: "",
|
|
StepName: "TestCreateDataObject",
|
|
SiteID: "",
|
|
PipelineURLHash: "",
|
|
BuildURLHash: "",
|
|
Orchestrator: "Unknown",
|
|
}
|
|
telemetryClient.baseMetaData = baseMetaData
|
|
telemetryClient.SetData(tt.args.customData)
|
|
fmt.Println(telemetryClient.data)
|
|
fmt.Println(tt.want)
|
|
if !reflect.DeepEqual(telemetryClient.data, tt.want) {
|
|
t.Errorf("CreateDataObject() t.data= %v, want %v", telemetryClient.data, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestTelemetry_logStepTelemetryData(t *testing.T) {
|
|
|
|
provider := &orchestrator.UnknownOrchestratorConfigProvider{}
|
|
|
|
type fields struct {
|
|
data Data
|
|
provider orchestrator.OrchestratorSpecificConfigProviding
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
fields fields
|
|
fatalError logrus.Fields
|
|
logOutput string
|
|
}{
|
|
{
|
|
name: "logging with error, no fatalError set",
|
|
fields: fields{
|
|
data: Data{
|
|
BaseData: BaseData{},
|
|
BaseMetaData: BaseMetaData{},
|
|
CustomData: CustomData{
|
|
ErrorCode: "1",
|
|
Duration: "200",
|
|
PiperCommitHash: "n/a",
|
|
},
|
|
},
|
|
provider: provider,
|
|
},
|
|
},
|
|
{
|
|
name: "logging with error, fatal error set",
|
|
fields: fields{
|
|
data: Data{
|
|
BaseData: BaseData{},
|
|
BaseMetaData: BaseMetaData{},
|
|
CustomData: CustomData{
|
|
ErrorCode: "1",
|
|
Duration: "200",
|
|
PiperCommitHash: "n/a",
|
|
},
|
|
},
|
|
provider: provider,
|
|
},
|
|
fatalError: logrus.Fields{
|
|
"message": "Some error happened",
|
|
"error": "Oh snap!",
|
|
"category": "undefined",
|
|
"result": "failure",
|
|
"correlationId": "test",
|
|
"time": "0000-00-00 00:00:00.000",
|
|
},
|
|
},
|
|
{
|
|
name: "logging without error",
|
|
fields: fields{
|
|
data: Data{
|
|
CustomData: CustomData{
|
|
ErrorCode: "0",
|
|
Duration: "200",
|
|
PiperCommitHash: "n/a",
|
|
},
|
|
},
|
|
provider: provider,
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
_, hook := test.NewNullLogger()
|
|
log.RegisterHook(hook)
|
|
telemetry := &Telemetry{
|
|
data: tt.fields.data,
|
|
provider: tt.fields.provider,
|
|
}
|
|
var re *regexp.Regexp
|
|
if tt.fatalError != nil {
|
|
errDetails, _ := json.Marshal(&tt.fatalError)
|
|
log.SetFatalErrorDetail(errDetails)
|
|
re = regexp.MustCompile(`Step telemetry data:{"StepStartTime":".*?","PipelineURLHash":"","BuildURLHash":"","StageName":"","StepName":"","ErrorCode":"\d","StepDuration":"\d+","ErrorCategory":"","CorrelationID":"n/a","PiperCommitHash":"n/a","ErrorDetail":{"category":"undefined","correlationId":"test","error":"Oh snap!","message":"Some error happened","result":"failure","time":"0000-00-00 00:00:00.000"}}`)
|
|
|
|
} else {
|
|
re = regexp.MustCompile(`Step telemetry data:{"StepStartTime":".*?","PipelineURLHash":"","BuildURLHash":"","StageName":"","StepName":"","ErrorCode":"\d","StepDuration":"\d+","ErrorCategory":"","CorrelationID":"n/a","PiperCommitHash":"n/a","ErrorDetail":null}`)
|
|
}
|
|
telemetry.logStepTelemetryData()
|
|
assert.Regexp(t, re, hook.LastEntry().Message)
|
|
hook.Reset()
|
|
})
|
|
}
|
|
}
|