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  }