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 }