github.com/ouraigua/jenkins-library@v0.0.0-20231028010029-fbeaf2f3aa9b/pkg/config/config_test.go (about) 1 //go:build unit 2 // +build unit 3 4 package config 5 6 import ( 7 "errors" 8 "fmt" 9 "io" 10 "os" 11 "path/filepath" 12 "reflect" 13 "strings" 14 "testing" 15 16 "github.com/SAP/jenkins-library/pkg/piperenv" 17 "github.com/stretchr/testify/assert" 18 ) 19 20 type errReadCloser int 21 22 func (errReadCloser) Read(p []byte) (n int, err error) { 23 return 0, errors.New("read error") 24 } 25 26 func (errReadCloser) Close() error { 27 return nil 28 } 29 30 func customDefaultsOpenFileMock(name string, tokens map[string]string) (io.ReadCloser, error) { 31 return io.NopCloser(strings.NewReader("general:\n p0: p0_custom_default\nstages:\n stage1:\n p1: p1_custom_default")), nil 32 } 33 34 func TestReadConfig(t *testing.T) { 35 36 var c Config 37 38 t.Run("Success case", func(t *testing.T) { 39 40 myConfig := strings.NewReader("general:\n generalTestKey: generalTestValue\nsteps:\n testStep:\n testStepKey: testStepValue") 41 42 err := c.ReadConfig(io.NopCloser(myConfig)) // NopCloser "no-ops" the closing interface since strings do not need to be closed 43 if err != nil { 44 t.Errorf("Got error although no error expected: %v", err) 45 } 46 47 if c.General["generalTestKey"] != "generalTestValue" { 48 t.Errorf("General config- got: %v, expected: %v", c.General["generalTestKey"], "generalTestValue") 49 } 50 51 if c.Steps["testStep"]["testStepKey"] != "testStepValue" { 52 t.Errorf("Step config - got: %v, expected: %v", c.Steps["testStep"]["testStepKey"], "testStepValue") 53 } 54 }) 55 56 t.Run("Read failure", func(t *testing.T) { 57 var rc errReadCloser 58 err := c.ReadConfig(rc) 59 if err == nil { 60 t.Errorf("Got no error although error expected.") 61 } 62 }) 63 64 t.Run("Unmarshalling failure", func(t *testing.T) { 65 myConfig := strings.NewReader("general:\n generalTestKey: generalTestValue\nsteps:\n testStep:\n\ttestStepKey: testStepValue") 66 err := c.ReadConfig(io.NopCloser(myConfig)) 67 if err == nil { 68 t.Errorf("Got no error although error expected.") 69 } 70 }) 71 72 } 73 74 func TestGetStepConfig(t *testing.T) { 75 76 t.Run("Success case", func(t *testing.T) { 77 78 testConfig := `general: 79 p3: p3_general 80 px3: px3_general 81 p4: p4_general 82 steps: 83 step1: 84 p4: p4_step 85 px4: px4_step 86 p5: p5_step 87 dependentParameter: dependentValue 88 stepAlias: 89 p8: p8_stepAlias 90 stages: 91 stage1: 92 p5: p5_stage 93 px5: px5_stage 94 p6: p6_stage 95 ` 96 filters := StepFilters{ 97 General: []string{"p0", "p1", "p2", "p3", "p4"}, 98 Steps: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p8", "dependentParameter", "pd1", "dependentValue", "pd2"}, 99 Stages: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p6"}, 100 Parameters: []string{"p0", "p1", "p2", "p3", "p4", "p5", "p6", "p7"}, 101 Env: []string{"p0", "p1", "p2", "p3", "p4", "p5"}, 102 } 103 104 defaults1 := `general: 105 p0: p0_general_default 106 px0: px0_general_default 107 p1: p1_general_default 108 steps: 109 step1: 110 p1: p1_step_default 111 px1: px1_step_default 112 p2: p2_step_default 113 dependentValue: 114 pd1: pd1_dependent_default 115 ` 116 117 defaults2 := `general: 118 p2: p2_general_default 119 px2: px2_general_default 120 p3: p3_general_default 121 ` 122 123 paramJSON := `{"p6":"p6_param","p7":"p7_param"}` 124 125 flags := map[string]interface{}{"p7": "p7_flag"} 126 127 var c Config 128 defaults := []io.ReadCloser{io.NopCloser(strings.NewReader(defaults1)), io.NopCloser(strings.NewReader(defaults2))} 129 130 myConfig := io.NopCloser(strings.NewReader(testConfig)) 131 132 parameterMetadata := []StepParameters{ 133 { 134 Name: "pd1", 135 Scope: []string{"STEPS"}, 136 Conditions: []Condition{ 137 { 138 Params: []Param{ 139 {Name: "dependentParameter", Value: "dependentValue"}, 140 }, 141 }, 142 }, 143 }, 144 { 145 Name: "pd2", 146 Default: "pd2_metadata_default", 147 Scope: []string{"STEPS"}, 148 Conditions: []Condition{ 149 { 150 Params: []Param{ 151 {Name: "dependentParameter", Value: "dependentValue"}, 152 }, 153 }, 154 }, 155 }, 156 { 157 Name: "pe1", 158 Scope: []string{"STEPS"}, 159 ResourceRef: []ResourceReference{{Name: "commonPipelineEnvironment", Param: "test_pe1"}}, 160 Type: "string", 161 }, 162 } 163 secretMetadata := []StepSecrets{ 164 { 165 Name: "sd1", 166 Type: "jenkins", 167 }, 168 } 169 170 stepAliases := []Alias{{Name: "stepAlias"}} 171 172 stepMeta := StepData{ 173 Spec: StepSpec{ 174 Inputs: StepInputs{ 175 Parameters: parameterMetadata, 176 Secrets: secretMetadata, 177 }, 178 }, 179 Metadata: StepMetadata{ 180 Aliases: stepAliases, 181 }, 182 } 183 184 dir := t.TempDir() 185 186 piperenv.SetParameter(filepath.Join(dir, "commonPipelineEnvironment"), "test_pe1", "pe1_val") 187 188 stepConfig, err := c.GetStepConfig(flags, paramJSON, myConfig, defaults, false, filters, stepMeta, stepMeta.GetResourceParameters(dir, "commonPipelineEnvironment"), "stage1", "step1") 189 190 assert.Equal(t, nil, err, "error occurred but none expected") 191 192 t.Run("Config", func(t *testing.T) { 193 expected := map[string]string{ 194 "p0": "p0_general_default", 195 "p1": "p1_step_default", 196 "p2": "p2_general_default", 197 "p3": "p3_general", 198 "p4": "p4_step", 199 "p5": "p5_stage", 200 "p6": "p6_param", 201 "p7": "p7_flag", 202 "p8": "p8_stepAlias", 203 "pd1": "pd1_dependent_default", 204 "pd2": "pd2_metadata_default", 205 "pe1": "pe1_val", 206 } 207 208 for k, v := range expected { 209 t.Run(k, func(t *testing.T) { 210 if stepConfig.Config[k] != v { 211 t.Errorf("got: %v, expected: %v", stepConfig.Config[k], v) 212 } 213 }) 214 } 215 }) 216 217 t.Run("Config not expected", func(t *testing.T) { 218 notExpectedKeys := []string{"px0", "px1", "px2", "px3", "px4", "px5"} 219 for _, p := range notExpectedKeys { 220 t.Run(p, func(t *testing.T) { 221 if stepConfig.Config[p] != nil { 222 t.Errorf("unexpected: %v", p) 223 } 224 }) 225 } 226 }) 227 }) 228 229 t.Run("Success case - environment nil", func(t *testing.T) { 230 231 testConfig := "" 232 filters := StepFilters{ 233 General: []string{"p0"}, 234 } 235 236 defaults1 := `general: 237 p0: p0_general_default 238 ` 239 var c Config 240 defaults := []io.ReadCloser{io.NopCloser(strings.NewReader(defaults1))} 241 242 myConfig := io.NopCloser(strings.NewReader(testConfig)) 243 244 stepMeta := StepData{Spec: StepSpec{Inputs: StepInputs{Parameters: []StepParameters{ 245 {Name: "p0", ResourceRef: []ResourceReference{{Name: "commonPipelineEnvironment", Param: "p0"}}}, 246 }}}} 247 248 dir := t.TempDir() 249 250 stepConfig, err := c.GetStepConfig(map[string]interface{}{}, "", myConfig, defaults, false, filters, stepMeta, stepMeta.GetResourceParameters(dir, "commonPipelineEnvironment"), "stage1", "step1") 251 252 assert.Equal(t, nil, err, "error occurred but none expected") 253 254 assert.Equal(t, "p0_general_default", stepConfig.Config["p0"]) 255 }) 256 257 t.Run("Consider custom defaults from config", func(t *testing.T) { 258 var c Config 259 testConfDefaults := "customDefaults:\n- testDefaults.yaml" 260 261 c.openFile = customDefaultsOpenFileMock 262 263 stepConfig, err := c.GetStepConfig(nil, "", io.NopCloser(strings.NewReader(testConfDefaults)), nil, false, StepFilters{General: []string{"p0"}}, StepData{}, nil, "stage1", "step1") 264 265 assert.NoError(t, err, "Error occurred but no error expected") 266 assert.Equal(t, "p0_custom_default", stepConfig.Config["p0"]) 267 assert.Equal(t, "p1_custom_default", stepConfig.Config["p1"]) 268 269 }) 270 271 t.Run("Don't consider custom defaults from config", func(t *testing.T) { 272 var c Config 273 testConfDefaults := "customDefaults:\n- testDefaults.yaml" 274 275 c.openFile = customDefaultsOpenFileMock 276 277 stepConfig, err := c.GetStepConfig(nil, "", io.NopCloser(strings.NewReader(testConfDefaults)), nil, true, StepFilters{General: []string{"p0"}}, StepData{}, nil, "stage1", "step1") 278 279 assert.NoError(t, err, "Error occurred but no error expected") 280 assert.Equal(t, nil, stepConfig.Config["p0"]) 281 assert.Equal(t, nil, stepConfig.Config["p1"]) 282 283 }) 284 285 t.Run("Consider defaults from step config", func(t *testing.T) { 286 var c Config 287 288 stepParams := []StepParameters{{Name: "p0", Scope: []string{"GENERAL"}, Type: "string", Default: "p0_step_default", Aliases: []Alias{{Name: "p0_alias"}}}} 289 metadata := StepData{ 290 Spec: StepSpec{ 291 Inputs: StepInputs{ 292 Parameters: stepParams, 293 }, 294 }, 295 } 296 testConf := "general:\n p1: p1_conf" 297 298 stepConfig, err := c.GetStepConfig(nil, "", io.NopCloser(strings.NewReader(testConf)), nil, false, StepFilters{General: []string{"p0", "p1"}}, metadata, nil, "stage1", "step1") 299 300 assert.NoError(t, err, "Error occurred but no error expected") 301 assert.Equal(t, "p0_step_default", stepConfig.Config["p0"]) 302 assert.Equal(t, "p1_conf", stepConfig.Config["p1"]) 303 }) 304 305 t.Run("Ignore alias if wrong type", func(t *testing.T) { 306 var c Config 307 308 stepParams := []StepParameters{ 309 {Name: "p0", Scope: []string{"GENERAL"}, Type: "bool", Aliases: []Alias{}}, 310 {Name: "p1", Scope: []string{"GENERAL"}, Type: "string", Aliases: []Alias{{Name: "p0/subParam"}}}} 311 metadata := StepData{ 312 Spec: StepSpec{ 313 Inputs: StepInputs{ 314 Parameters: stepParams, 315 }, 316 }, 317 } 318 testConf := "general:\n p0: true" 319 320 stepConfig, err := c.GetStepConfig(nil, "", io.NopCloser(strings.NewReader(testConf)), nil, false, StepFilters{General: []string{"p0", "p1"}}, metadata, nil, "stage1", "step1") 321 322 assert.NoError(t, err, "Error occurred but no error expected") 323 assert.Equal(t, true, stepConfig.Config["p0"]) 324 assert.Equal(t, nil, stepConfig.Config["p1"]) 325 }) 326 327 t.Run("Apply alias to paramJSON", func(t *testing.T) { 328 var c Config 329 330 secrets := []StepSecrets{ 331 {Name: "p0", Type: "string", Aliases: []Alias{{Name: "p1/subParam"}}}} 332 metadata := StepData{ 333 Spec: StepSpec{ 334 Inputs: StepInputs{ 335 Secrets: secrets, 336 }, 337 }, 338 } 339 testConf := "" 340 341 paramJSON := "{\"p1\":{\"subParam\":\"p1_value\"}}" 342 stepConfig, err := c.GetStepConfig(nil, paramJSON, io.NopCloser(strings.NewReader(testConf)), nil, true, StepFilters{Parameters: []string{"p0"}}, metadata, nil, "stage1", "step1") 343 344 assert.NoError(t, err, "Error occurred but no error expected") 345 assert.Equal(t, "p1_value", stepConfig.Config["p0"]) 346 }) 347 348 t.Run("Failure case config", func(t *testing.T) { 349 var c Config 350 myConfig := io.NopCloser(strings.NewReader("invalid config")) 351 _, err := c.GetStepConfig(nil, "", myConfig, nil, false, StepFilters{}, StepData{}, nil, "stage1", "step1") 352 assert.EqualError(t, err, "failed to parse custom pipeline configuration: format of configuration is invalid \"invalid config\": error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type config.Config", "default error expected") 353 }) 354 355 t.Run("Failure case defaults", func(t *testing.T) { 356 var c Config 357 myConfig := io.NopCloser(strings.NewReader("")) 358 myDefaults := []io.ReadCloser{io.NopCloser(strings.NewReader("invalid defaults"))} 359 _, err := c.GetStepConfig(nil, "", myConfig, myDefaults, false, StepFilters{}, StepData{}, nil, "stage1", "step1") 360 assert.EqualError(t, err, "failed to read default configuration: error unmarshalling \"invalid defaults\": error unmarshaling JSON: while decoding JSON: json: cannot unmarshal string into Go value of type config.Config", "default error expected") 361 }) 362 363 t.Run("Test reporting parameters with aliases and cpe resources", func(t *testing.T) { 364 var c Config 365 testConfig := io.NopCloser(strings.NewReader(`general: 366 gcpJsonKeyFilePath: gcpJsonKeyFilePath_value 367 steps: 368 step1: 369 jsonKeyFilePath: gcpJsonKeyFilePath_from_alias`)) 370 testDefaults := []io.ReadCloser{io.NopCloser(strings.NewReader(`general: 371 pipelineId: gcsBucketId_from_alias 372 steps: 373 step1: 374 gcsBucketId: gcsBucketId_value`))} 375 dir := t.TempDir() 376 cpeDir := filepath.Join(dir, "commonPipelineEnvironment/custom") 377 err := os.MkdirAll(cpeDir, 0700) 378 if err != nil { 379 t.Fatal("Failed to create sub directory") 380 } 381 382 err = os.WriteFile(filepath.Join(cpeDir, "gcsFolderPath.json"), []byte("\"value_from_cpe\""), 0700) 383 assert.NoError(t, err) 384 385 stepMeta := StepData{Spec: StepSpec{Inputs: StepInputs{Parameters: []StepParameters{}}}} 386 stepConfig, err := c.GetStepConfig(nil, "", testConfig, testDefaults, false, StepFilters{General: []string{"p0", "p1"}}, stepMeta, ReportingParameters.GetResourceParameters(dir, "commonPipelineEnvironment"), "stage1", "step1") 387 388 assert.NoError(t, err, "Error occurred but no error expected") 389 assert.Equal(t, "gcpJsonKeyFilePath_from_alias", stepConfig.Config["gcpJsonKeyFilePath"]) 390 assert.Equal(t, "gcsBucketId_value", stepConfig.Config["gcsBucketId"]) 391 assert.Equal(t, "value_from_cpe", stepConfig.Config["gcsFolderPath"]) 392 }) 393 394 //ToDo: test merging of env and parameters/flags 395 } 396 397 func TestGetStepConfigWithJSON(t *testing.T) { 398 399 filters := StepFilters{All: []string{"key1"}} 400 401 t.Run("Without flags", func(t *testing.T) { 402 sc := GetStepConfigWithJSON(nil, `"key1":"value1","key2":"value2"`, filters) 403 404 if sc.Config["key1"] != "value1" && sc.Config["key2"] == "value2" { 405 t.Errorf("got: %v, expected: %v", sc.Config, StepConfig{Config: map[string]interface{}{"key1": "value1"}}) 406 } 407 }) 408 409 t.Run("With flags", func(t *testing.T) { 410 flags := map[string]interface{}{"key1": "flagVal1"} 411 sc := GetStepConfigWithJSON(flags, `"key1":"value1","key2":"value2"`, filters) 412 if sc.Config["key1"] != "flagVal1" { 413 t.Errorf("got: %v, expected: %v", sc.Config["key1"], "flagVal1") 414 } 415 }) 416 } 417 418 func TestGetStageConfig(t *testing.T) { 419 420 testConfig := `general: 421 p1: p1_general 422 px1: px1_general 423 stages: 424 stage1: 425 p2: p2_stage 426 px2: px2_stage 427 ` 428 defaults1 := `general: 429 p0: p0_general_default 430 px0: px0_general_default 431 ` 432 paramJSON := `{"p3":"p3_param"}` 433 434 t.Run("Success case - with filters", func(t *testing.T) { 435 436 acceptedParams := []string{"p0", "p1", "p2", "p3"} 437 438 var c Config 439 defaults := []io.ReadCloser{io.NopCloser(strings.NewReader(defaults1))} 440 441 myConfig := io.NopCloser(strings.NewReader(testConfig)) 442 443 stepConfig, err := c.GetStageConfig(paramJSON, myConfig, defaults, false, acceptedParams, "stage1") 444 445 assert.Equal(t, nil, err, "error occurred but none expected") 446 447 t.Run("Config", func(t *testing.T) { 448 expected := map[string]string{ 449 "p0": "p0_general_default", 450 "p1": "p1_general", 451 "p2": "p2_stage", 452 "p3": "p3_param", 453 } 454 455 for k, v := range expected { 456 t.Run(k, func(t *testing.T) { 457 if stepConfig.Config[k] != v { 458 t.Errorf("got: %v, expected: %v", stepConfig.Config[k], v) 459 } 460 }) 461 } 462 }) 463 464 t.Run("Config not expected", func(t *testing.T) { 465 notExpectedKeys := []string{"px0", "px1", "px2"} 466 for _, p := range notExpectedKeys { 467 t.Run(p, func(t *testing.T) { 468 if stepConfig.Config[p] != nil { 469 t.Errorf("unexpected: %v", p) 470 } 471 }) 472 } 473 }) 474 }) 475 476 t.Run("Success case - no filters", func(t *testing.T) { 477 478 acceptedParams := []string{} 479 480 var c Config 481 defaults := []io.ReadCloser{io.NopCloser(strings.NewReader(defaults1))} 482 483 myConfig := io.NopCloser(strings.NewReader(testConfig)) 484 485 stepConfig, err := c.GetStageConfig(paramJSON, myConfig, defaults, false, acceptedParams, "stage1") 486 487 assert.Equal(t, nil, err, "error occurred but none expected") 488 489 t.Run("Config", func(t *testing.T) { 490 expected := map[string]string{ 491 "p0": "p0_general_default", 492 "px0": "px0_general_default", 493 "p1": "p1_general", 494 "px1": "px1_general", 495 "p2": "p2_stage", 496 "px2": "px2_stage", 497 "p3": "p3_param", 498 } 499 500 for k, v := range expected { 501 t.Run(k, func(t *testing.T) { 502 if stepConfig.Config[k] != v { 503 t.Errorf("got: %v, expected: %v", stepConfig.Config[k], v) 504 } 505 }) 506 } 507 }) 508 }) 509 } 510 511 func TestApplyAliasConfig(t *testing.T) { 512 p := []StepParameters{ 513 { 514 Name: "p0", 515 Aliases: []Alias{ 516 {Name: "p0_notused"}, 517 }, 518 }, 519 { 520 Name: "p1", 521 Aliases: []Alias{ 522 {Name: "p1_alias"}, 523 }, 524 }, 525 { 526 Name: "p2", 527 Aliases: []Alias{ 528 {Name: "p2_alias/deep/test"}, 529 }, 530 }, 531 { 532 Name: "p3", 533 Aliases: []Alias{ 534 {Name: "p3_notused"}, 535 }, 536 }, 537 { 538 Name: "p4", 539 Aliases: []Alias{ 540 {Name: "p4_alias"}, 541 {Name: "p4_2nd_alias"}, 542 }, 543 }, 544 { 545 Name: "p5", 546 Aliases: []Alias{ 547 {Name: "p5_notused"}, 548 }, 549 }, 550 { 551 Name: "p6", 552 Aliases: []Alias{ 553 {Name: "p6_1st_alias"}, 554 {Name: "p6_alias"}, 555 }, 556 }, 557 { 558 Name: "p7", 559 Aliases: []Alias{ 560 {Name: "p7_alias"}, 561 }, 562 }, 563 { 564 Name: "p8", 565 Aliases: []Alias{ 566 {Name: "p8_alias"}, 567 }, 568 }, 569 { 570 Name: "p9", 571 }, 572 } 573 s := []StepSecrets{ 574 { 575 Name: "s1", 576 Aliases: []Alias{ 577 {Name: "s1_alias"}, 578 }, 579 }, 580 } 581 582 filters := StepFilters{ 583 General: []string{"p1", "p2"}, 584 Stages: []string{"p4"}, 585 Steps: []string{"p6", "p8", "s1"}, 586 } 587 588 c := Config{ 589 General: map[string]interface{}{ 590 "p0_notused": "p0_general", 591 "p1_alias": "p1_general", 592 "p2_alias": map[string]interface{}{ 593 "deep": map[string]interface{}{ 594 "test": "p2_general", 595 }, 596 }, 597 }, 598 Stages: map[string]map[string]interface{}{ 599 "stage1": { 600 "p3_notused": "p3_stage", 601 "p4_alias": "p4_stage", 602 }, 603 }, 604 Steps: map[string]map[string]interface{}{ 605 "step1": { 606 "p5_notused": "p5_step", 607 "p6_alias": "p6_step", 608 "p7": "p7_step", 609 }, 610 "stepAlias1": { 611 "p7": "p7_stepAlias", 612 "p8_alias": "p8_stepAlias", 613 "p9": "p9_stepAlias", 614 "s1_alias": "s1_stepAlias", 615 }, 616 }, 617 } 618 619 stepAliases := []Alias{{Name: "stepAlias1"}} 620 621 c.ApplyAliasConfig(p, s, filters, "stage1", "step1", stepAliases) 622 623 t.Run("Global", func(t *testing.T) { 624 assert.Nil(t, c.General["p0"]) 625 assert.Equal(t, "p1_general", c.General["p1"]) 626 assert.Equal(t, "p2_general", c.General["p2"]) 627 }) 628 629 t.Run("Stage", func(t *testing.T) { 630 assert.Nil(t, c.General["p3"]) 631 assert.Equal(t, "p4_stage", c.Stages["stage1"]["p4"]) 632 }) 633 634 t.Run("Steps", func(t *testing.T) { 635 assert.Nil(t, c.General["p5"]) 636 assert.Equal(t, "p6_step", c.Steps["step1"]["p6"]) 637 assert.Equal(t, "p7_step", c.Steps["step1"]["p7"]) 638 assert.Equal(t, "p8_stepAlias", c.Steps["step1"]["p8"]) 639 assert.Equal(t, "p9_stepAlias", c.Steps["step1"]["p9"]) 640 assert.Equal(t, "s1_stepAlias", c.Steps["step1"]["s1"]) 641 }) 642 643 } 644 645 func TestGetDeepAliasValue(t *testing.T) { 646 c := map[string]interface{}{ 647 "p0": "p0_val", 648 "p1": 11, 649 "p2": map[string]interface{}{ 650 "p2_0": "p2_0_val", 651 "p2_1": map[string]interface{}{ 652 "p2_1_0": "p2_1_0_val", 653 }, 654 }, 655 } 656 tt := []struct { 657 key string 658 expected interface{} 659 }{ 660 {key: "p0", expected: "p0_val"}, 661 {key: "p1", expected: 11}, 662 {key: "p2/p2_0", expected: "p2_0_val"}, 663 {key: "p2/p2_1/p2_1_0", expected: "p2_1_0_val"}, 664 } 665 666 for k, v := range tt { 667 assert.Equal(t, v.expected, getDeepAliasValue(c, v.key), fmt.Sprintf("wrong return value for run %v", k+1)) 668 } 669 } 670 671 func TestCopyStepAliasConfig(t *testing.T) { 672 t.Run("Step config available", func(t *testing.T) { 673 c := Config{ 674 Steps: map[string]map[string]interface{}{ 675 "step1": { 676 "p1": "p1_step", 677 "p2": "p2_step", 678 }, 679 "stepAlias1": { 680 "p2": "p2_stepAlias", 681 "p3": "p3_stepAlias", 682 }, 683 "stepAlias2": { 684 "p3": "p3_stepAlias2", 685 "p4": "p4_stepAlias2", 686 }, 687 }, 688 } 689 690 expected := Config{ 691 Steps: map[string]map[string]interface{}{ 692 "step1": { 693 "p1": "p1_step", 694 "p2": "p2_step", 695 "p3": "p3_stepAlias", 696 "p4": "p4_stepAlias2", 697 }, 698 "stepAlias1": { 699 "p2": "p2_stepAlias", 700 "p3": "p3_stepAlias", 701 }, 702 "stepAlias2": { 703 "p3": "p3_stepAlias2", 704 "p4": "p4_stepAlias2", 705 }, 706 }, 707 } 708 709 c.copyStepAliasConfig("step1", []Alias{{Name: "stepAlias1"}, {Name: "stepAlias2"}}) 710 assert.Equal(t, expected, c) 711 }) 712 713 t.Run("Step config not available", func(t *testing.T) { 714 c := Config{ 715 Steps: map[string]map[string]interface{}{ 716 "stepAlias1": { 717 "p2": "p2_stepAlias", 718 }, 719 }, 720 } 721 722 expected := Config{ 723 Steps: map[string]map[string]interface{}{ 724 "step1": { 725 "p2": "p2_stepAlias", 726 }, 727 "stepAlias1": { 728 "p2": "p2_stepAlias", 729 }, 730 }, 731 } 732 733 c.copyStepAliasConfig("step1", []Alias{{Name: "stepAlias1"}}) 734 assert.Equal(t, expected, c) 735 }) 736 } 737 738 func TestGetJSON(t *testing.T) { 739 740 t.Run("Success case", func(t *testing.T) { 741 custom := map[string]interface{}{"key1": "value1"} 742 json, err := GetJSON(custom) 743 if err != nil { 744 t.Errorf("Got error although no error expected: %v", err) 745 } 746 747 if json != `{"key1":"value1"}` { 748 t.Errorf("got: %v, expected: %v", json, `{"key1":"value1"}`) 749 } 750 751 }) 752 t.Run("Marshalling failure", func(t *testing.T) { 753 _, err := GetJSON(make(chan int)) 754 if err == nil { 755 t.Errorf("Got no error although error expected") 756 } 757 }) 758 } 759 760 func TestMerge(t *testing.T) { 761 762 testTable := []struct { 763 Source map[string]interface{} 764 Filter []string 765 MergeData map[string]interface{} 766 ExpectedOutput map[string]interface{} 767 }{ 768 { 769 Source: map[string]interface{}{"key1": "baseValue"}, 770 Filter: []string{}, 771 MergeData: map[string]interface{}{"key1": "overwrittenValue"}, 772 ExpectedOutput: map[string]interface{}{"key1": "overwrittenValue"}, 773 }, 774 { 775 Source: map[string]interface{}{"key1": "value1"}, 776 Filter: []string{}, 777 MergeData: map[string]interface{}{"key2": "value2"}, 778 ExpectedOutput: map[string]interface{}{"key1": "value1", "key2": "value2"}, 779 }, 780 { 781 Source: map[string]interface{}{"key1": "value1"}, 782 Filter: []string{"key1"}, 783 MergeData: map[string]interface{}{"key2": "value2"}, 784 ExpectedOutput: map[string]interface{}{"key1": "value1"}, 785 }, 786 { 787 Source: map[string]interface{}{"key1": map[string]interface{}{"key1_1": "value1"}}, 788 Filter: []string{}, 789 MergeData: map[string]interface{}{"key1": map[string]interface{}{"key1_2": "value2"}}, 790 ExpectedOutput: map[string]interface{}{"key1": map[string]interface{}{"key1_1": "value1", "key1_2": "value2"}}, 791 }, 792 { 793 Source: map[string]interface{}{"key1": "value1"}, 794 Filter: []string{"key1", ".+Key$"}, 795 MergeData: map[string]interface{}{"regexKey": "value2", "regexKeyIgnored": "value3", "Key": "value3"}, 796 ExpectedOutput: map[string]interface{}{"key1": "value1", "regexKey": "value2"}, 797 }, 798 } 799 800 for _, row := range testTable { 801 t.Run(fmt.Sprintf("Merging %v into %v", row.MergeData, row.Source), func(t *testing.T) { 802 stepConfig := StepConfig{Config: row.Source} 803 stepConfig.mixIn(row.MergeData, row.Filter) 804 assert.Equal(t, row.ExpectedOutput, stepConfig.Config, "Mixin was incorrect") 805 }) 806 } 807 } 808 809 func TestStepConfig_mixInHookConfig(t *testing.T) { 810 type fields struct { 811 Config map[string]interface{} 812 HookConfig map[string]interface{} 813 } 814 type args struct { 815 mergeData map[string]interface{} 816 } 817 tests := []struct { 818 name string 819 fields fields 820 args args 821 want map[string]interface{} 822 }{ 823 {name: "Splunk only", 824 fields: fields{ 825 Config: nil, 826 HookConfig: nil, 827 }, 828 args: args{mergeData: map[string]interface{}{ 829 "splunk": map[string]interface{}{ 830 "dsn": "dsn", 831 "token": "token", 832 "sendLogs": "false", 833 }, 834 }}, 835 want: map[string]interface{}{ 836 "splunk": map[string]interface{}{ 837 "dsn": "dsn", 838 "token": "token", 839 "sendLogs": "false", 840 }, 841 }, 842 }, 843 {name: "Sentry only", 844 fields: fields{ 845 Config: nil, 846 HookConfig: nil, 847 }, 848 args: args{mergeData: map[string]interface{}{ 849 "sentry": map[string]interface{}{ 850 "dsn": "sentrydsn", 851 }, 852 }}, 853 want: map[string]interface{}{ 854 "sentry": map[string]interface{}{ 855 "dsn": "sentrydsn", 856 }, 857 }, 858 }, 859 {name: "Splunk and Sentry", 860 fields: fields{ 861 Config: nil, 862 HookConfig: nil, 863 }, 864 args: args{mergeData: map[string]interface{}{ 865 "splunk": map[string]interface{}{ 866 "dsn": "dsn", 867 "token": "token", 868 "sendLogs": "false", 869 }, 870 "sentry": map[string]interface{}{ 871 "dsn": "sentrydsn", 872 }, 873 }}, 874 want: map[string]interface{}{ 875 "splunk": map[string]interface{}{ 876 "dsn": "dsn", 877 "token": "token", 878 "sendLogs": "false", 879 }, 880 "sentry": map[string]interface{}{ 881 "dsn": "sentrydsn", 882 }, 883 }, 884 }, 885 {name: "No Hook", 886 fields: fields{ 887 Config: nil, 888 HookConfig: nil, 889 }, 890 args: args{mergeData: nil}, 891 want: map[string]interface{}{}, 892 }, 893 } 894 for _, tt := range tests { 895 t.Run(tt.name, func(t *testing.T) { 896 s := &StepConfig{ 897 Config: tt.fields.Config, 898 HookConfig: tt.fields.HookConfig, 899 } 900 s.mixInHookConfig(tt.args.mergeData) 901 if !reflect.DeepEqual(s.HookConfig, tt.want) { 902 t.Errorf("mixInHookConfig() = %v, want %v", s.HookConfig, tt.want) 903 } 904 }) 905 } 906 } 907 908 func TestMixInStepDefaults(t *testing.T) { 909 tt := []struct { 910 name string 911 stepConfig *StepConfig 912 stepParams []StepParameters 913 expected map[string]interface{} 914 }{ 915 {name: "empty", stepConfig: &StepConfig{}, stepParams: []StepParameters{}, expected: map[string]interface{}{}}, 916 {name: "no condition", stepConfig: &StepConfig{}, stepParams: []StepParameters{{Name: "noCondition", Default: "noCondition_default"}}, expected: map[string]interface{}{"noCondition": "noCondition_default"}}, 917 { 918 name: "with multiple conditions", 919 stepConfig: &StepConfig{}, 920 stepParams: []StepParameters{ 921 {Name: "dependentParam1", Default: "dependentParam1_value"}, 922 {Name: "dependentParam2", Default: "dependentParam2_value"}, 923 { 924 Name: "withConditionParameter", 925 Default: "withCondition_default_a", 926 Conditions: []Condition{ 927 {ConditionRef: "strings-equal", Params: []Param{{Name: "dependentParam1", Value: "dependentParam1_value1"}}}, 928 {ConditionRef: "strings-equal", Params: []Param{{Name: "dependentParam2", Value: "dependentParam2_value1"}}}, 929 }, 930 }, 931 { 932 Name: "withConditionParameter", 933 Default: "withCondition_default_b", 934 Conditions: []Condition{ 935 {ConditionRef: "strings-equal", Params: []Param{{Name: "dependentParam1", Value: "dependentParam1_value2"}}}, 936 {ConditionRef: "strings-equal", Params: []Param{{Name: "dependentParam2", Value: "dependentParam2_value2"}}}, 937 }, 938 }, 939 }, 940 expected: map[string]interface{}{ 941 "dependentParam1": "dependentParam1_value", 942 "dependentParam2": "dependentParam2_value", 943 "dependentParam1_value1": map[string]interface{}{"withConditionParameter": "withCondition_default_a"}, 944 "dependentParam2_value1": map[string]interface{}{"withConditionParameter": "withCondition_default_a"}, 945 "dependentParam1_value2": map[string]interface{}{"withConditionParameter": "withCondition_default_b"}, 946 "dependentParam2_value2": map[string]interface{}{"withConditionParameter": "withCondition_default_b"}, 947 }, 948 }, 949 } 950 951 for _, test := range tt { 952 test.stepConfig.mixInStepDefaults(test.stepParams) 953 assert.Equal(t, test.expected, test.stepConfig.Config, test.name) 954 } 955 } 956 957 func TestCloneConfig(t *testing.T) { 958 testConfig := &Config{ 959 General: map[string]interface{}{ 960 "p0": "p0_general", 961 }, 962 Stages: map[string]map[string]interface{}{ 963 "stage1": { 964 "p1": "p1_stage", 965 }, 966 }, 967 Steps: map[string]map[string]interface{}{ 968 "step1": { 969 "p2": "p2_step", 970 }, 971 }, 972 } 973 clone, err := cloneConfig(testConfig) 974 assert.NoError(t, err) 975 assert.Equal(t, testConfig, clone) 976 testConfig.General["p0"] = "new_value" 977 assert.NotEqual(t, testConfig.General, clone.General) 978 }