github.com/xgoffin/jenkins-library@v1.154.0/pkg/splunk/splunk_test.go (about)

     1  package splunk
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"reflect"
     9  	"testing"
    10  	"time"
    11  
    12  	piperhttp "github.com/SAP/jenkins-library/pkg/http"
    13  	"github.com/SAP/jenkins-library/pkg/log"
    14  	"github.com/SAP/jenkins-library/pkg/telemetry"
    15  	"github.com/jarcoal/httpmock"
    16  )
    17  
    18  func TestInitialize(t *testing.T) {
    19  	type args struct {
    20  		correlationID string
    21  		dsn           string
    22  		token         string
    23  		index         string
    24  		sendLogs      bool
    25  	}
    26  	tests := []struct {
    27  		name    string
    28  		args    args
    29  		wantErr bool
    30  	}{
    31  		{"Testing initialize splunk",
    32  			args{
    33  				correlationID: "correlationID",
    34  				dsn:           "https://splunkURL.sap/services/collector",
    35  				token:         "SECRET-TOKEN",
    36  				index:         "test-index",
    37  				sendLogs:      false,
    38  			},
    39  			false,
    40  		},
    41  	}
    42  	for _, tt := range tests {
    43  		t.Run(tt.name, func(t *testing.T) {
    44  			splunkClient := &Splunk{}
    45  			if err := splunkClient.Initialize(tt.args.correlationID, tt.args.dsn, tt.args.token, tt.args.index, tt.args.sendLogs); (err != nil) != tt.wantErr {
    46  				t.Errorf("Initialize() error = %v, wantErr %v", err, tt.wantErr)
    47  			}
    48  		})
    49  	}
    50  }
    51  
    52  func TestSend(t *testing.T) {
    53  
    54  	type args struct {
    55  		telemetryData *telemetry.Data
    56  		logCollector  *log.CollectorHook
    57  		sendLogs      bool
    58  		maxBatchSize  int
    59  	}
    60  	tests := []struct {
    61  		name          string
    62  		args          args
    63  		wantErr       bool
    64  		payloadLength int
    65  		logLength     int // length of log per payload
    66  	}{
    67  		{name: "Testing Success Step - Send Telemetry Only",
    68  			args: args{
    69  				telemetryData: &telemetry.Data{
    70  					BaseData:     telemetry.BaseData{},
    71  					BaseMetaData: telemetry.BaseMetaData{},
    72  					CustomData: telemetry.CustomData{
    73  						Duration:      "100",
    74  						ErrorCode:     "0",
    75  						ErrorCategory: "DEBUG",
    76  					},
    77  				},
    78  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
    79  					Messages: []log.Message{
    80  						{
    81  							Time:    time.Time{},
    82  							Level:   0,
    83  							Message: "DEBUG",
    84  							Data:    "DEBUG 0",
    85  						},
    86  						{
    87  							Time:    time.Time{},
    88  							Level:   0,
    89  							Message: "DEBUG",
    90  							Data:    "DEBUG 1",
    91  						},
    92  					}},
    93  				sendLogs: false,
    94  			},
    95  			wantErr:       false,
    96  			payloadLength: 1,
    97  			logLength:     0,
    98  		},
    99  		{name: "Testing Success Step - Send Telemetry Only Although sendLogs Active",
   100  			args: args{
   101  				telemetryData: &telemetry.Data{
   102  					BaseData:     telemetry.BaseData{},
   103  					BaseMetaData: telemetry.BaseMetaData{},
   104  					CustomData: telemetry.CustomData{
   105  						Duration:      "100",
   106  						ErrorCode:     "0",
   107  						ErrorCategory: "DEBUG",
   108  					},
   109  				},
   110  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
   111  					Messages: []log.Message{
   112  						{
   113  							Time:    time.Time{},
   114  							Level:   0,
   115  							Message: "DEBUG",
   116  							Data:    "DEBUG 0",
   117  						},
   118  						{
   119  							Time:    time.Time{},
   120  							Level:   0,
   121  							Message: "DEBUG",
   122  							Data:    "DEBUG 1",
   123  						},
   124  					}},
   125  				sendLogs: true,
   126  			},
   127  			wantErr:       false,
   128  			payloadLength: 1,
   129  			logLength:     0,
   130  		},
   131  		{name: "Testing Failure Step - Send Telemetry Only",
   132  			args: args{
   133  				telemetryData: &telemetry.Data{
   134  					BaseData:     telemetry.BaseData{},
   135  					BaseMetaData: telemetry.BaseMetaData{},
   136  					CustomData: telemetry.CustomData{
   137  						Duration:      "100",
   138  						ErrorCode:     "0",
   139  						ErrorCategory: "DEBUG",
   140  					},
   141  				},
   142  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
   143  					Messages: []log.Message{
   144  						{
   145  							Time:    time.Time{},
   146  							Level:   0,
   147  							Message: "DEBUG",
   148  							Data:    "DEBUG 0",
   149  						},
   150  						{
   151  							Time:    time.Time{},
   152  							Level:   0,
   153  							Message: "DEBUG",
   154  							Data:    "DEBUG 1",
   155  						},
   156  					}},
   157  				sendLogs:     false,
   158  				maxBatchSize: 1000,
   159  			},
   160  			wantErr:       false,
   161  			payloadLength: 1,
   162  			logLength:     0,
   163  		},
   164  		{name: "Testing Failure Step - Send Telemetry and Logs",
   165  			args: args{
   166  				telemetryData: &telemetry.Data{
   167  					BaseData:     telemetry.BaseData{},
   168  					BaseMetaData: telemetry.BaseMetaData{},
   169  					CustomData: telemetry.CustomData{
   170  						Duration:      "100",
   171  						ErrorCode:     "1",
   172  						ErrorCategory: "DEBUG",
   173  					},
   174  				},
   175  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
   176  					Messages: []log.Message{
   177  						{
   178  							Time:    time.Time{},
   179  							Level:   0,
   180  							Message: "DEBUG",
   181  							Data:    "DEBUG 0",
   182  						},
   183  						{
   184  							Time:    time.Time{},
   185  							Level:   0,
   186  							Message: "DEBUG",
   187  							Data:    "DEBUG 1",
   188  						},
   189  					}},
   190  				sendLogs:     true,
   191  				maxBatchSize: 1000,
   192  			},
   193  			wantErr:       false,
   194  			payloadLength: 1,
   195  			logLength:     2,
   196  		},
   197  		{name: "Testing len(maxBatchSize)==len(logMessages)",
   198  			args: args{
   199  				telemetryData: &telemetry.Data{
   200  					BaseData:     telemetry.BaseData{},
   201  					BaseMetaData: telemetry.BaseMetaData{},
   202  					CustomData: telemetry.CustomData{
   203  						Duration:  "100",
   204  						ErrorCode: "1",
   205  					},
   206  				},
   207  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
   208  					Messages: []log.Message{
   209  						{
   210  							Time:    time.Time{},
   211  							Level:   0,
   212  							Message: "DEBUG",
   213  							Data:    "DEBUG 0",
   214  						},
   215  						{
   216  							Time:    time.Time{},
   217  							Level:   0,
   218  							Message: "DEBUG",
   219  							Data:    "DEBUG 1",
   220  						},
   221  					}},
   222  				sendLogs:     true,
   223  				maxBatchSize: 2,
   224  			},
   225  			wantErr:       false,
   226  			payloadLength: 1,
   227  			logLength:     2,
   228  		},
   229  		{name: "Testing len(maxBatchSize)<len(logMessages)",
   230  			args: args{
   231  				telemetryData: &telemetry.Data{
   232  					BaseData:     telemetry.BaseData{},
   233  					BaseMetaData: telemetry.BaseMetaData{},
   234  					CustomData: telemetry.CustomData{
   235  						Duration:  "100",
   236  						ErrorCode: "1",
   237  					},
   238  				},
   239  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
   240  					Messages: []log.Message{
   241  						{
   242  							Time:    time.Time{},
   243  							Level:   0,
   244  							Message: "DEBUG",
   245  							Data:    "DEBUG 0",
   246  						},
   247  						{
   248  							Time:    time.Time{},
   249  							Level:   0,
   250  							Message: "DEBUG",
   251  							Data:    "DEBUG 1",
   252  						},
   253  					}},
   254  				sendLogs:     true,
   255  				maxBatchSize: 1,
   256  			},
   257  			wantErr:       false,
   258  			payloadLength: 2,
   259  			logLength:     1, // equal to maxBatchSize
   260  		},
   261  		{name: "Testing len(maxBatchSize)>len(logMessages)",
   262  			args: args{
   263  				telemetryData: &telemetry.Data{
   264  					BaseData:     telemetry.BaseData{},
   265  					BaseMetaData: telemetry.BaseMetaData{},
   266  					CustomData:   telemetry.CustomData{},
   267  				},
   268  				logCollector: &log.CollectorHook{CorrelationID: "DEBUG",
   269  					Messages: []log.Message{
   270  						{
   271  							Time:    time.Time{},
   272  							Level:   0,
   273  							Message: "DEBUG",
   274  							Data:    "DEBUG 0",
   275  						},
   276  						{
   277  							Time:    time.Time{},
   278  							Level:   0,
   279  							Message: "DEBUG",
   280  							Data:    "DEBUG 1",
   281  						},
   282  					}},
   283  				sendLogs:     true,
   284  				maxBatchSize: 1000,
   285  			},
   286  			wantErr:       false,
   287  			payloadLength: 1,
   288  			logLength:     2,
   289  		},
   290  	}
   291  	for _, tt := range tests {
   292  		t.Run(tt.name, func(t *testing.T) {
   293  			httpmock.Activate()
   294  			defer httpmock.DeactivateAndReset()
   295  
   296  			fakeUrl := "https://splunk.example.com/services/collector"
   297  			// Our database of received payloads
   298  			var payloads []Details
   299  			httpmock.RegisterResponder("POST", fakeUrl,
   300  				func(req *http.Request) (*http.Response, error) {
   301  					splunkMessage := Details{}
   302  					if err := json.NewDecoder(req.Body).Decode(&splunkMessage); err != nil {
   303  						return httpmock.NewStringResponse(400, ""), nil
   304  					}
   305  
   306  					defer req.Body.Close()
   307  					payloads = append(payloads, splunkMessage)
   308  
   309  					resp, err := httpmock.NewJsonResponse(200, splunkMessage)
   310  					if err != nil {
   311  						return httpmock.NewStringResponse(500, ""), nil
   312  					}
   313  					return resp, nil
   314  				},
   315  			)
   316  
   317  			client := piperhttp.Client{}
   318  			client.SetOptions(piperhttp.ClientOptions{
   319  				MaxRequestDuration:        5 * time.Second,
   320  				Token:                     "TOKEN",
   321  				TransportSkipVerification: true,
   322  				UseDefaultTransport:       true,
   323  				MaxRetries:                -1,
   324  			})
   325  
   326  			splunkClient := &Splunk{
   327  				splunkClient:          client,
   328  				splunkDsn:             fakeUrl,
   329  				splunkIndex:           "index",
   330  				correlationID:         "DEBUG",
   331  				postMessagesBatchSize: tt.args.maxBatchSize,
   332  				sendLogs:              tt.args.sendLogs,
   333  			}
   334  			if err := splunkClient.Send(*tt.args.telemetryData, tt.args.logCollector); (err != nil) != tt.wantErr {
   335  				t.Errorf("Send() error = %v, wantErr %v", err, tt.wantErr)
   336  			}
   337  			if len(payloads) != tt.payloadLength {
   338  				t.Errorf("Send() error, wanted %v payloads, got %v.", tt.payloadLength, len(payloads))
   339  			}
   340  
   341  			// The case if more than one payload is present is covered in the if statement above.
   342  			if len(payloads[0].Event.Messages) != tt.logLength {
   343  				t.Errorf("Send() error, wanted %v event messages, got %v.", tt.logLength, len(payloads[0].Event.Messages))
   344  			}
   345  			splunkClient = nil
   346  		})
   347  	}
   348  }
   349  
   350  func Test_prepareTelemetry(t *testing.T) {
   351  	type args struct {
   352  		telemetryData telemetry.Data
   353  	}
   354  	tests := []struct {
   355  		name string
   356  		args args
   357  		want MonitoringData
   358  	}{
   359  		{name: "Testing prepare telemetry information",
   360  			args: args{
   361  				telemetryData: telemetry.Data{
   362  					BaseData:     telemetry.BaseData{},
   363  					BaseMetaData: telemetry.BaseMetaData{},
   364  					CustomData: telemetry.CustomData{
   365  						Duration:      "1234",
   366  						ErrorCode:     "0",
   367  						ErrorCategory: "Undefined",
   368  					},
   369  				},
   370  			},
   371  			want: MonitoringData{
   372  				PipelineUrlHash: "",
   373  				BuildUrlHash:    "",
   374  				StageName:       "",
   375  				StepName:        "",
   376  				ExitCode:        "0",
   377  				Duration:        "1234",
   378  				ErrorCode:       "0",
   379  				ErrorCategory:   "Undefined",
   380  				CorrelationID:   "Correlation-Test",
   381  				CommitHash:      "N/A",
   382  				Branch:          "N/A",
   383  				GitOwner:        "N/A",
   384  				GitRepository:   "N/A",
   385  			},
   386  		},
   387  	}
   388  
   389  	for _, tt := range tests {
   390  		t.Run(tt.name, func(t *testing.T) {
   391  			splunkClient := &Splunk{}
   392  			err := splunkClient.Initialize("Correlation-Test", "splunkUrl", "TOKEN", "index", false)
   393  			if err != nil {
   394  				t.Errorf("Error Initalizing Splunk. %v", err)
   395  			}
   396  			if got := splunkClient.prepareTelemetry(tt.args.telemetryData); !reflect.DeepEqual(got, tt.want) {
   397  				t.Errorf("prepareTelemetry() = %v, want %v", got, tt.want)
   398  			}
   399  		})
   400  	}
   401  }
   402  
   403  func Test_tryPostMessages(t *testing.T) {
   404  	type args struct {
   405  		telemetryData MonitoringData
   406  		messages      []log.Message
   407  	}
   408  	tests := []struct {
   409  		name    string
   410  		args    args
   411  		wantErr bool
   412  	}{
   413  		{
   414  			name: "Test HTTP Success",
   415  			args: args{
   416  				telemetryData: MonitoringData{
   417  					PipelineUrlHash: "1234",
   418  					BuildUrlHash:    "5678",
   419  					StageName:       "deploy",
   420  					StepName:        "cloudFoundryDeploy",
   421  					ExitCode:        "0",
   422  					Duration:        "12345678",
   423  					ErrorCode:       "0",
   424  					ErrorCategory:   "undefined",
   425  					CorrelationID:   "123",
   426  					CommitHash:      "a6bc",
   427  					Branch:          "prod",
   428  					GitOwner:        "N/A",
   429  					GitRepository:   "N/A",
   430  				},
   431  				messages: []log.Message{},
   432  			},
   433  			wantErr: false,
   434  		},
   435  		{
   436  			name: "Test HTTP Failure",
   437  			args: args{
   438  				telemetryData: MonitoringData{
   439  					PipelineUrlHash: "1234",
   440  					BuildUrlHash:    "5678",
   441  					StageName:       "deploy",
   442  					StepName:        "cloudFoundryDeploy",
   443  					ExitCode:        "0",
   444  					Duration:        "12345678",
   445  					ErrorCode:       "0",
   446  					ErrorCategory:   "undefined",
   447  					CorrelationID:   "123",
   448  					CommitHash:      "a6bc",
   449  					Branch:          "prod",
   450  					GitOwner:        "N/A",
   451  					GitRepository:   "N/A",
   452  				},
   453  				messages: []log.Message{},
   454  			},
   455  			wantErr: true,
   456  		},
   457  	}
   458  	for _, tt := range tests {
   459  		t.Run(tt.name, func(t *testing.T) {
   460  			httpmock.Activate()
   461  			fakeUrl := "https://splunk.example.com/services/collector"
   462  			defer httpmock.DeactivateAndReset()
   463  			httpmock.RegisterResponder("POST", fakeUrl,
   464  				func(req *http.Request) (*http.Response, error) {
   465  					if tt.wantErr == true {
   466  						return &http.Response{
   467  							Status:           "400",
   468  							StatusCode:       400,
   469  							Proto:            "",
   470  							ProtoMajor:       0,
   471  							ProtoMinor:       0,
   472  							Header:           nil,
   473  							Body:             nil,
   474  							ContentLength:    0,
   475  							TransferEncoding: nil,
   476  							Close:            false,
   477  							Uncompressed:     false,
   478  							Trailer:          nil,
   479  							Request:          req,
   480  							TLS:              nil,
   481  						}, nil
   482  					}
   483  					return httpmock.NewStringResponse(200, ""), nil
   484  				},
   485  			)
   486  			client := piperhttp.Client{}
   487  			client.SetOptions(piperhttp.ClientOptions{
   488  				MaxRequestDuration:        5 * time.Second,
   489  				Token:                     "TOKEN",
   490  				TransportSkipVerification: true,
   491  				UseDefaultTransport:       true,
   492  				MaxRetries:                -1,
   493  			})
   494  			splunkClient := &Splunk{
   495  				splunkClient:          client,
   496  				splunkDsn:             fakeUrl,
   497  				splunkIndex:           "index",
   498  				correlationID:         "DEBUG",
   499  				postMessagesBatchSize: 1000,
   500  			}
   501  			if err := splunkClient.tryPostMessages(tt.args.telemetryData, tt.args.messages); (err != nil) != tt.wantErr {
   502  				t.Errorf("tryPostMessages() error = %v, wantErr %v", err, tt.wantErr)
   503  			}
   504  		})
   505  	}
   506  }
   507  
   508  func Test_readPipelineEnvironment(t *testing.T) {
   509  	tests := []struct {
   510  		name       string
   511  		result     string
   512  		createFile bool
   513  	}{
   514  		{
   515  			name:       "Test read pipelineEnvironment files not available",
   516  			result:     "N/A",
   517  			createFile: false,
   518  		},
   519  		{
   520  			name:       "Test read pipelineEnvironment files available",
   521  			result:     "master",
   522  			createFile: true,
   523  		},
   524  	}
   525  	for _, tt := range tests {
   526  		t.Run(tt.name, func(t *testing.T) {
   527  
   528  			if tt.createFile {
   529  
   530  				// creating temporarily folders
   531  				path := ".pipeline/commonPipelineEnvironment/"
   532  				err := os.MkdirAll(path, os.ModePerm)
   533  				if err != nil {
   534  					t.Errorf("Could not create .pipeline/ folders: %v", err)
   535  				}
   536  
   537  				err = os.Mkdir(path+"git/", os.ModePerm)
   538  				if err != nil {
   539  					t.Errorf("Could not create git folder: %v", err)
   540  				}
   541  
   542  				// creating temporarily files with dummy content
   543  				branch := []byte("master")
   544  				err = ioutil.WriteFile(path+"git/branch", branch, 0644)
   545  				if err != nil {
   546  					t.Errorf("Could not create branch file: %v", err)
   547  				}
   548  
   549  			}
   550  			result := readCommonPipelineEnvironment("git/branch")
   551  			if result != tt.result {
   552  				t.Errorf("readCommonPipelineEnvironment() got = %v, want %v", result, tt.result)
   553  			}
   554  
   555  			if tt.createFile {
   556  				// deletes temp files
   557  				err := os.RemoveAll(".pipeline")
   558  				if err != nil {
   559  					t.Errorf("Could not delete .pipeline folder: %v", err)
   560  				}
   561  
   562  			}
   563  		})
   564  	}
   565  }